summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS6
-rw-r--r--ChangeLog0
-rw-r--r--INSTALL182
-rw-r--r--Makefile358
-rw-r--r--Makefile.am2
-rw-r--r--NEWS3
-rw-r--r--configure.in35
-rw-r--r--doc/.cvsignore4
-rw-r--r--doc/Makefile.am1
-rw-r--r--doc/ratpoison.info134
-rw-r--r--doc/ratpoison.texi171
-rw-r--r--src/.cvsignore8
-rw-r--r--src/Makefile.am5
-rw-r--r--src/bar.c141
-rw-r--r--src/bar.h29
-rw-r--r--src/conf.h44
-rw-r--r--src/data.h78
-rw-r--r--src/events.c473
-rw-r--r--src/events.h29
-rw-r--r--src/input.c75
-rw-r--r--src/input.h1
-rw-r--r--src/list.c271
-rw-r--r--src/list.h35
-rw-r--r--src/main.c261
-rw-r--r--src/manage.c175
-rw-r--r--src/manage.h30
-rw-r--r--src/number.c130
-rw-r--r--src/number.h3
-rw-r--r--src/ratpoison.h40
29 files changed, 2704 insertions, 20 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..b2ae343
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,6 @@
+Shawn Betts (sabetts@sfu.ca)
+
+Shawn is the original author and current maintainer for
+ratpoison. Sickened by the rat and the trend in window managers, he
+sat down one evening and pulled an all-nighter writing the first
+version of ratpoison.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..b42a17a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile b/Makefile
index 0ff3854..8512102 100644
--- a/Makefile
+++ b/Makefile
@@ -1,31 +1,349 @@
-# Where to install the ratpoison executable
-INSTALL_DIR=/usr/local/bin
+# Generated automatically from Makefile.in by configure.
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
-# Spew lots of debug messages
-DEBUG = -DDEBUG
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+SHELL = /bin/sh
+
+srcdir = .
+top_srcdir = .
+prefix = /usr/local
+exec_prefix = ${prefix}
+
+bindir = ${exec_prefix}/bin
+sbindir = ${exec_prefix}/sbin
+libexecdir = ${exec_prefix}/libexec
+datadir = ${prefix}/share
+sysconfdir = ${prefix}/etc
+sharedstatedir = ${prefix}/com
+localstatedir = ${prefix}/var
+libdir = ${exec_prefix}/lib
+infodir = ${prefix}/info
+mandir = ${prefix}/man
+includedir = ${prefix}/include
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/ratpoison
+pkglibdir = $(libdir)/ratpoison
+pkgincludedir = $(includedir)/ratpoison
+
+top_builddir = .
+
+ACLOCAL = aclocal
+AUTOCONF = autoconf
+AUTOMAKE = automake
+AUTOHEADER = autoheader
+
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL} $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL_PROGRAM}
+transform = s,x,x,
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
CC = gcc
-LIBS = -lX11
-LDFLAGS = -L/usr/X11R6/lib
-CFLAGS = -g -Wall -I/usr/X11R6/include
+MAKEINFO = makeinfo
+PACKAGE = ratpoison
+VERSION = 0.0.3
+
+SUBDIRS = doc src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ./src/config.h
+CONFIG_CLEAN_FILES =
+DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \
+Makefile.in NEWS aclocal.m4 configure configure.in install-sh missing \
+mkinstalldirs src/config.h.in src/stamp-h.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4): configure.in
+ cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+ cd $(srcdir) && $(AUTOCONF)
+
+src/config.h: src/stamp-h
+ @if test ! -f $@; then \
+ rm -f src/stamp-h; \
+ $(MAKE) src/stamp-h; \
+ else :; fi
+src/stamp-h: $(srcdir)/src/config.h.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES= CONFIG_HEADERS=src/config.h \
+ $(SHELL) ./config.status
+ @echo timestamp > src/stamp-h 2> /dev/null
+$(srcdir)/src/config.h.in: $(srcdir)/src/stamp-h.in
+ @if test ! -f $@; then \
+ rm -f $(srcdir)/src/stamp-h.in; \
+ $(MAKE) $(srcdir)/src/stamp-h.in; \
+ else :; fi
+$(srcdir)/src/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ @echo timestamp > $(srcdir)/src/stamp-h.in 2> /dev/null
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+ -rm -f src/config.h
+
+maintainer-clean-hdr:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+ rev="$$subdir $$rev"; \
+ test "$$subdir" = "." && dot_seen=yes; \
+ done; \
+ test "$$dot_seen" = "no" && rev=". $$rev"; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ -rm -rf $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+ mkdir $(distdir)/=build
+ mkdir $(distdir)/=inst
+ dc_install_base=`cd $(distdir)/=inst && pwd`; \
+ cd $(distdir)/=build \
+ && ../configure --srcdir=.. --prefix=$$dc_install_base \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) dist
+ -rm -rf $(distdir)
+ @banner="$(distdir).tar.gz is ready for distribution"; \
+ dashes=`echo "$$banner" | sed s/./=/g`; \
+ echo "$$dashes"; \
+ echo "$$banner"; \
+ echo "$$dashes"
+dist: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+dist-all: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+distdir: $(DISTFILES)
+ -rm -rf $(distdir)
+ mkdir $(distdir)
+ -chmod 777 $(distdir)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ for subdir in $(SUBDIRS); do \
+ if test "$$subdir" = .; then :; else \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ chmod 777 $(distdir)/$$subdir; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
+ || exit 1; \
+ fi; \
+ done
+info-am:
+info: info-recursive
+dvi-am:
+dvi: dvi-recursive
+check-am: all-am
+check: check-recursive
+installcheck-am:
+installcheck: installcheck-recursive
+install-exec-am:
+install-exec: install-exec-recursive
+
+install-data-am:
+install-data: install-data-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-recursive
+uninstall-am:
+uninstall: uninstall-recursive
+all-am: Makefile
+all-redirect: all-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs: installdirs-recursive
+installdirs-am:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-recursive
+
+clean-am: clean-hdr clean-tags clean-generic mostlyclean-am
+
+clean: clean-recursive
-SRC = main.o events.o manage.o list.o bar.o number.o input.o
-HEADERS = bar.h conf.h data.h events.h list.h manage.h ratpoison.h number.h input.h
+distclean-am: distclean-hdr distclean-tags distclean-generic clean-am
-all: ratpoison ratpoison.info
+distclean: distclean-recursive
+ -rm -f config.status
-ratpoison: $(SRC)
- gcc $(SRC) -o $@ $(CFLAGS) $(LDFLAGS) $(LIBS)
+maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
-ratpoison.info : ratpoison.texi
- makeinfo ratpoison.texi
+maintainer-clean: maintainer-clean-recursive
+ -rm -f config.status
-install: ratpoison
- cp ratpoison $(INSTALL_DIR)
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+install-data-recursive uninstall-data-recursive install-exec-recursive \
+uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
+all-recursive check-recursive installcheck-recursive info-recursive \
+dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs-am \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
-%.o : %.c $(HEADERS)
- $(CC) -c $(CFLAGS) $(DEBUG) $< -o $@
-clean :
- rm -f *.o ratpoison ratpoison.info
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..1c85a9d
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,2 @@
+
+SUBDIRS = doc src
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..9585897
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,3 @@
+* Features
+
+* Bugs
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..1e08bbe
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,35 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(src/main.c)
+AM_INIT_AUTOMAKE(ratpoison, 0.0.3)
+
+AM_CONFIG_HEADER(src/config.h)
+
+dnl Checks for programs.
+CFLAGS="$CFLAGS -Wall"
+AC_PROG_CC
+
+dnl Check for the X libs
+AC_PATH_X
+AC_PATH_XTRA
+
+if test "x$no_x" = "xyes"; then
+ AC_MSG_ERROR([*** Can't find X11 headers and libs])
+fi
+
+LDFLAGS="$LDFLAGS $X_LDFLAGS $X_LIBS $X_EXTRA_LIBS"
+CFLAGS="$CFLAGS $X_CFLAGS"
+
+AC_CHECK_LIB(X11, XOpenDisplay,,
+ AC_MSG_ERROR([*** Can't find libX11]))
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+
+dnl Checks for library functions.
+AC_TYPE_SIGNAL
+
+AC_OUTPUT(Makefile doc/Makefile src/Makefile)
diff --git a/doc/.cvsignore b/doc/.cvsignore
new file mode 100644
index 0000000..6c49f9d
--- /dev/null
+++ b/doc/.cvsignore
@@ -0,0 +1,4 @@
+ratpoison.info
+Makefile.in
+Makefile
+texinfo.tex
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..96a2f8b
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1 @@
+info_TEXINFOS = ratpoison.texi
diff --git a/doc/ratpoison.info b/doc/ratpoison.info
new file mode 100644
index 0000000..13e9059
--- /dev/null
+++ b/doc/ratpoison.info
@@ -0,0 +1,134 @@
+This is ratpoison.info, produced by makeinfo version 4.0 from
+ratpoison.texi.
+
+START-INFO-DIR-ENTRY
+* ratpoison: (ratpoison). A rat-free Window Manager.
+END-INFO-DIR-ENTRY
+
+ This is the ratpoison user manual.
+
+ Copyright (C) 2000 Shawn Betts
+
+ Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+ Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided also
+that the sections entitled "Copying" and "GNU General Public License"
+are included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+ Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Free Software Foundation.
+
+ This document explains how to use ratpoison.
+
+
+File: ratpoison.info, Node: Top, Next: About, Prev: (dir), Up: (dir)
+
+* Menu:
+
+* About:: What is ratpoison?
+* Contacting:: How do I contact the ratpoison developers?
+* Using ratpoison:: Key commands and functionality
+
+
+File: ratpoison.info, Node: About, Next: Contacting, Prev: Top, Up: Top
+
+About
+*****
+
+ ratpoison is a simple Window Manager with no fat library
+dependencies, no fancy graphics, no window decorations, and no flashy
+wank. It is largely modelled after GNU Screen which has done wonders in
+virtual terminal market.
+
+ All interaction with the window manager is done through keystrokes.
+ratpoison has a prefix map to minimize the key clobbering that cripples
+EMACS and other quality pieces of software.
+
+ You'll also be pleased to hear that there is NO ratpoison.conf to
+configure. If you want to configure ratpoison, edit the source.
+
+ ratpoison was written by Shawn Betts
+(<sabetts@users.sourceforge.net>).
+
+
+File: ratpoison.info, Node: Contacting, Next: Using ratpoison, Prev: About, Up: Top
+
+Contacting
+**********
+
+ ratpoison is hosted on <sourceforge.net>. To see the latest
+developments in ratpoison go to
+<http://www.sourceforge.net/projects/ratpoison> or visit the ratpoison
+webpage at <http://ratpoison.sourceforge.net>.
+
+ There is also a ratpoison mailing list:
+<ratpoison-devel@lists.sourceforge.net>. For details on subscribing and
+for the list archives go to the ratpoison sourceforge.net project.
+
+
+File: ratpoison.info, Node: Using ratpoison, Prev: Contacting, Up: Top
+
+Using ratpoison
+***************
+
+ ratpoison is a very simple window manager. Each window is maximized
+and has no border decorations. Here is a list of commands and what they
+do:
+
+`C-t C-c'
+ This opens a new XTerm.
+
+`C-t C-e'
+ This opens a new EMACS session. You will probably only need to do
+ this once.
+
+`C-t C-w'
+ This displays the Program Bar which displays the windows you
+ currently have running. The number before each window name is used
+ to jump to that window. You can to this by typing `C-t C-<n>'
+ where `<n>' is the number of the window. Note that only windows
+ with numbers from 0 to 9 can be referenced.
+
+ After 5 seconds the Program Bar disappears.
+
+`C-t C-p'
+ This jumps you to the previous window in the window list.
+
+`C-t C-n'
+ This jumps you to the next window in the window list.
+
+`C-t C-<n>'
+ This jumps you to window <n> where <n> is the window number as
+ shown in the Program Bar.
+
+`C-t C-t'
+ This toggles between the current window and the last window.
+
+`C-t t'
+ Sometimes you need to send a C-t to the current window. This
+ keystroke does just that.
+
+`C-t k'
+ This deletes the current window.
+
+`C-t K'
+ This destroys the current window. Normally you should only need to
+ use `C-t k', but just incase you need to rip the heart out of a
+ misbehaving window this command should do the trick.
+
+
+
+Tag Table:
+Node: Top1119
+Node: About1394
+Node: Contacting2112
+Node: Using ratpoison2623
+
+End Tag Table
diff --git a/doc/ratpoison.texi b/doc/ratpoison.texi
new file mode 100644
index 0000000..2cfe31a
--- /dev/null
+++ b/doc/ratpoison.texi
@@ -0,0 +1,171 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename ratpoison.info
+@settitle ratpoison manual
+@setchapternewpage odd
+@c %**end of header
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* ratpoison: (ratpoison). A rat-free Window Manager.
+END-INFO-DIR-ENTRY
+@end format
+
+@ifinfo
+This is the ratpoison user manual.
+
+Copyright @copyright{} 2000 Shawn Betts
+
+Permission is granted to make and distribute verbatim
+copies of this manual provided the copyright notice and
+this permission notice are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX
+and print the results, provided the printed document
+carries a copying permission notice identical to this
+one except for the removal of this paragraph (this
+paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified
+versions of this manual under the conditions for
+verbatim copying, provided also that the sections
+entitled ``Copying'' and ``GNU General Public License''
+are included exactly as in the original, and provided
+that the entire resulting derived work is distributed
+under the terms of a permission notice identical to this
+one.
+
+Permission is granted to copy and distribute
+translations of this manual into another language,
+under the above conditions for modified versions,
+except that this permission notice may be stated in a
+translation approved by the Free Software Foundation.
+@end ifinfo
+
+@titlepage
+@sp 10
+@titlefont{Ratpoison}
+@author Shawn Betts
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 2000 Shawn Betts
+
+Permission is granted to make and distribute verbatim
+copies of this manual provided the copyright notice and
+this permission notice are preserved on all copies.
+
+Permission is granted to copy and distribute modified
+versions of this manual under the conditions for
+verbatim copying, provided also that the sections
+entitled ``Copying'' and ``GNU General Public License''
+are included exactly as in the original, and provided
+that the entire resulting derived work is distributed
+under the terms of a permission notice identical to this
+one.
+
+Permission is granted to copy and distribute
+translations of this manual into another language,
+under the above conditions for modified versions,
+except that this permission notice may be stated in a
+translation approved by the Free Software Foundation.
+@end titlepage
+
+@end ifinfo
+
+@ifinfo
+This document explains how to use ratpoison.
+@end ifinfo
+
+@node Top, About, (dir), (dir)
+
+@menu
+* About:: What is ratpoison?
+* Contacting:: How do I contact the ratpoison developers?
+* Using ratpoison:: Key commands and functionality
+@end menu
+
+@node About, Contacting, Top, Top
+@chapter About
+
+ratpoison is a simple Window Manager with no fat library dependencies,
+no fancy graphics, no window decorations, and no flashy wank. It is
+largely modelled after GNU Screen which has done wonders in virtual
+terminal market.
+
+All interaction with the window manager is done through
+keystrokes. ratpoison has a prefix map to minimize the key clobbering
+that cripples EMACS and other quality pieces of software.
+
+You'll also be pleased to hear that there is NO ratpoison.conf to
+configure. If you want to configure ratpoison, edit the source.
+
+ratpoison was written by Shawn Betts (@email{sabetts@@users.sourceforge.net}).
+
+@node Contacting, Using ratpoison, About, Top
+@chapter Contacting
+ratpoison is hosted on @url{sourceforge.net}. To see the latest
+developments in ratpoison go to
+@url{http://www.sourceforge.net/projects/ratpoison} or visit the
+ratpoison webpage at @url{http://ratpoison.sourceforge.net}.
+
+There is also a ratpoison mailing list:
+@email{ratpoison-devel@@lists.sourceforge.net}. For details on subscribing
+and for the list archives go to the ratpoison sourceforge.net project.
+
+@node Using ratpoison, , Contacting, Top
+@chapter Using ratpoison
+
+ratpoison is a very simple window manager. Each window is maximized and
+has no border decorations. Here is a list of commands and what they do:
+
+@table @kbd
+
+@item C-t C-c
+This opens a new XTerm.
+
+@item C-t C-e
+This opens a new EMACS session. You will probably only need to do this
+once.
+
+@item C-t C-w
+This displays the Program Bar which displays the windows you currently
+have running. The number before each window name is used to jump to that
+window. You can to this by typing @kbd{C-t C-<n>} where @kbd{<n>} is the
+number of the window. Note that only windows with numbers from 0 to 9
+can be referenced.
+
+After 5 seconds the Program Bar disappears.
+
+@item C-t C-p
+This jumps you to the previous window in the window list.
+
+@item C-t C-n
+This jumps you to the next window in the window list.
+
+@item C-t C-<n>
+This jumps you to window <n> where <n> is the window number as shown in
+the Program Bar.
+
+@item C-t C-t
+This toggles between the current window and the last window.
+
+@item C-t t
+Sometimes you need to send a C-t to the current window. This keystroke
+does just that.
+
+@item C-t k
+This deletes the current window.
+
+@item C-t K
+This destroys the current window. Normally you should only need to use
+@kbd{C-t k}, but just incase you need to rip the heart out of a
+misbehaving window this command should do the trick.
+
+@end table
+
+@bye
+
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644
index 0000000..29c83c0
--- /dev/null
+++ b/src/.cvsignore
@@ -0,0 +1,8 @@
+Makefile.in
+Makefile
+*.in
+ratpoison
+config.h
+stamp-h
+stamp-h.in
+.deps
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..d3af0be
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,5 @@
+bin_PROGRAMS = ratpoison
+
+ratpoison_SOURCES = bar.c bar.h conf.h data.h events.c events.h \
+input.c input.h list.c list.h main.c manage.c manage.h number.c \
+number.h ratpoison.h
diff --git a/src/bar.c b/src/bar.c
new file mode 100644
index 0000000..d06dcc8
--- /dev/null
+++ b/src/bar.c
@@ -0,0 +1,141 @@
+/* Functionality for a bar across the bottom of the screen listing the
+ * windows currently managed.
+ *
+ * Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ratpoison.h"
+
+int
+hide_bar (screen_info *s)
+{
+ if (s->bar_is_raised)
+ {
+ s->bar_is_raised = 0;
+ XUnmapWindow (dpy, s->bar_window);
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+show_bar (screen_info *s)
+{
+ if (!s->bar_is_raised)
+ {
+ s->bar_is_raised = 1;
+ XMapWindow (dpy, s->bar_window);
+ update_window_names (s);
+
+ /* Set an alarm to auto-hide the bar BAR_TIMEOUT seconds later */
+ alarm (BAR_TIMEOUT);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Toggle the display of the program bar */
+void
+toggle_bar (screen_info *s)
+{
+ if (!hide_bar (s)) show_bar (s);
+}
+
+static int
+calc_bar_width (XFontStruct *font)
+{
+ char str[100]; /* window names are capped at 99 chars */
+ int size = 1;
+ rp_window *cur;
+
+ for (cur = rp_window_head; cur; cur = cur->next)
+ {
+ if (cur->state == STATE_UNMAPPED) continue;
+
+ sprintf (str, "%d-%s", cur->number, cur->name);
+ size += 10 + XTextWidth (font, str, strlen (str));
+ }
+
+ return size;
+}
+
+int
+bar_x (screen_info *s, int width)
+{
+ if (BAR_LOCATION >= 2) return s->root_attr.width - width;
+ else return 0;
+}
+
+int
+bar_y (screen_info *s)
+{
+ if (BAR_LOCATION % 2) return 0;
+ else return s->root_attr.height - (FONT_HEIGHT (s->font) + BAR_PADDING * 2) - 2;
+}
+
+void
+update_window_names (screen_info *s)
+{
+ char str[100]; /* window names are capped at 99 chars */
+ int width = calc_bar_width (s->font);
+ rp_window *cur;
+ int cur_x = 5;
+
+ if (!s->bar_is_raised) return;
+
+ XMoveResizeWindow (dpy, s->bar_window,
+ bar_x (s, width), bar_y (s),
+ width,
+ (FONT_HEIGHT (s->font) + BAR_PADDING * 2));
+ XClearWindow (dpy, s->bar_window);
+ XRaiseWindow (dpy, s->bar_window);
+
+ if (rp_window_head == NULL) return;
+
+ /* Draw them in reverse order they were added in, so the oldest
+ windows appear on the left and the newest on the right end of the
+ program bar. */
+ for (cur = rp_window_head; cur; cur = cur->next)
+ {
+ if (cur->state == STATE_UNMAPPED) continue;
+
+ sprintf (str, "%d-%s", cur->number, cur->name);
+ if ( rp_current_window == cur)
+ {
+ XDrawString (dpy, s->bar_window, s->bold_gc, cur_x,
+ BAR_PADDING + s->font->max_bounds.ascent, str, strlen (str));
+ }
+ else
+ {
+ XDrawString (dpy, s->bar_window, s->normal_gc, cur_x,
+ BAR_PADDING + s->font->max_bounds.ascent, str, strlen (str));
+ }
+
+ cur_x += 10 + XTextWidth (s->font, str, strlen (str));
+ }
+}
diff --git a/src/bar.h b/src/bar.h
new file mode 100644
index 0000000..6083762
--- /dev/null
+++ b/src/bar.h
@@ -0,0 +1,29 @@
+/* functions for managing the program bar
+ *
+ * Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#ifndef _BAR_H
+#define _BAR_H
+
+void update_window_names (screen_info *s);
+void toggle_bar (screen_info *s);
+int show_bar (screen_info *s);
+int hide_bar (screen_info *s);
+int bar_y (screen_info *s);
+int bar_x (screen_info *s, int width);
+#endif _BAR_H
diff --git a/src/conf.h b/src/conf.h
new file mode 100644
index 0000000..8efee2e
--- /dev/null
+++ b/src/conf.h
@@ -0,0 +1,44 @@
+/* Config file for ratpoison. Edit these values and recompile.
+ *
+ * Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#define KEY_PREFIX 't'
+#define MODIFIER_PREFIX ControlMask
+
+#define KEY_XTERM 'c'
+#define KEY_EMACS 'e'
+#define KEY_PREVWINDOW 'p'
+#define KEY_NEXTWINDOW 'n'
+#define KEY_LASTWINDOW 't' /* key to toggle between the current window and the last visitted one */
+#define KEY_TOGGLEBAR 'w' /* key to toggle the display of the program bar */
+#define KEY_DELETE 'k' /* delete a window SHIFT+key will Destroy the window */
+#define KEY_WINBYNAME '\'' /* key to jump to a window by name */
+#define KEY_RENAME 'a' /* key to rename a window. */
+
+#define TERM_PROG "xterm" /* command to boot an x term */
+#define EMACS_PROG "emacs" /* command to boot emacs */
+
+#define BAR_FG_COLOR "Gray60"
+#define BAR_BG_COLOR "Lightgreen"
+#define BAR_BOLD_COLOR "Black" /* To indicate the current window */
+
+#define FONT_NAME "fixed" /* The font you wish to use */
+#define BAR_PADDING 3 /* The amount of padding on the top and bottom of the program bar */
+#define BAR_LOCATION 3 /* 0=bottom-left 1=top-left 2=bottom-right 3=top-right */
+#define BAR_TIMEOUT 5 /* Number of seconds before the progam bar autohides 0=don't autohide */
+
diff --git a/src/data.h b/src/data.h
new file mode 100644
index 0000000..5623a58
--- /dev/null
+++ b/src/data.h
@@ -0,0 +1,78 @@
+/* our datatypes and global variables
+ *
+ * Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#ifndef _DATA_H
+#define _DATA_H
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+#define FONT_HEIGHT(f) ((f)->max_bounds.ascent + (f)->max_bounds.descent)
+
+#define STATE_UNMAPPED 0
+#define STATE_MAPPED 1
+
+
+typedef struct rp_window rp_window;
+typedef struct screen_info screen_info;
+
+struct rp_window
+{
+ screen_info *scr;
+ Window w;
+ int number;
+ char *name;
+ int state;
+ int last_access;
+ int named;
+ rp_window *next, *prev;
+};
+
+struct screen_info
+{
+ GC normal_gc;
+ GC bold_gc;
+ XFontStruct *font; /* The font we want to use. */
+ XWindowAttributes root_attr;
+ Window root, bar_window, key_window, input_window;
+ int bar_is_raised;
+ int screen_num; /* Our screen number as dictated my X */
+ Colormap def_cmap;
+};
+
+extern rp_window *rp_window_head, *rp_window_tail;
+extern rp_window *rp_current_window;
+extern screen_info *screens;
+extern int num_screens;
+
+extern Display *dpy;
+extern Atom rp_restart;
+
+extern Atom wm_state;
+extern Atom wm_change_state;
+extern Atom wm_protocols;
+extern Atom wm_delete;
+extern Atom wm_take_focus;
+extern Atom wm_colormaps;
+
+/* Set to 1 to indicate that the WM should exit at it's earliest
+ convenience. */
+extern int exit_signal;
+
+#endif /* _DATA_H */
diff --git a/src/events.c b/src/events.c
new file mode 100644
index 0000000..a835eb3
--- /dev/null
+++ b/src/events.c
@@ -0,0 +1,473 @@
+/* Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/keysymdef.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "ratpoison.h"
+
+extern Display *dpy;
+
+void
+spawn(char *prog)
+{
+ /*
+ * ugly dance to avoid leaving zombies. Could use SIGCHLD,
+ * but it's not very portable.
+ */
+ if (fork() == 0) {
+ if (fork() == 0) {
+ putenv(DisplayString(dpy));
+ execlp(prog, prog, 0);
+ fprintf(stderr, "ratpoison: exec %s ", prog);
+ perror(" failed");
+ exit(EXIT_FAILURE);
+ }
+ exit(0);
+ }
+ wait((int *) 0);
+#ifdef DEBUG
+ printf ("spawned %s\n", prog);
+#endif
+}
+
+void
+new_window (XCreateWindowEvent *e)
+{
+ rp_window *win;
+ screen_info *s;
+
+ if (e->override_redirect) return;
+
+ s = find_screen (e->parent);
+ win = find_window (e->window);
+
+ if (s && !win && e->window != s->key_window && e->window != s->bar_window
+ && e->window != s->input_window)
+ {
+ win = add_to_window_list (s, e->window);
+ win->state = STATE_UNMAPPED;
+ }
+}
+
+void
+unmap_notify (XEvent *ev)
+{
+ screen_info *s;
+ rp_window *win;
+
+ s = find_screen (ev->xunmap.event);
+ win = find_window (ev->xunmap.window);
+
+ if (s && win)
+ {
+ /* Give back the window number. the window will get another one,
+ if it in remapped. */
+ return_window_number (win->number);
+ win->number = -1;
+ win->state = STATE_UNMAPPED;
+ update_window_names (s);
+ }
+}
+
+void
+map_request (XEvent *ev)
+{
+ screen_info *s;
+ rp_window *win;
+
+ s = find_screen (ev->xmap.event);
+ win = find_window (ev->xmap.window);
+
+ if (s && win)
+ {
+ switch (win->state)
+ {
+ case STATE_UNMAPPED:
+ manage (win, s);
+ case STATE_MAPPED:
+ XMapRaised (dpy, win->w);
+ rp_current_window = win;
+ set_active_window (rp_current_window);
+ }
+ }
+ else
+ {
+ printf ("Not managed.\n");
+ XMapWindow (dpy, ev->xmap.window);
+ }
+}
+
+int
+more_destroy_events ()
+{
+ XEvent ev;
+
+ if (XCheckTypedEvent (dpy, DestroyNotify, &ev))
+ {
+ XPutBackEvent (dpy, &ev);
+ return 1;
+ }
+ return 0;
+}
+
+void
+destroy_window (XDestroyWindowEvent *ev)
+{
+ /* if there are multiple destroy events queued, and a mapped window
+ is deleted then switch_window_pending is set to 1 and the window
+ switch is done after all destroy events have been done. */
+ static int switch_window_pending = 0;
+ int last_destroy_event;
+ rp_window *win;
+
+ win = find_window (ev->window);
+
+ last_destroy_event = !more_destroy_events();
+ if (win)
+ {
+ /* Goto the last accessed window. */
+ if (win == rp_current_window)
+ {
+ printf ("Destroying current window.\n");
+
+ /* tell ratpoison to switch to the last window when all the
+ destroy events have been delt with. */
+ switch_window_pending = 1;
+ unmanage (win);
+ }
+ else
+ {
+ printf ("Destroying some other window.\n");
+ unmanage (win);
+ }
+ }
+
+ if (last_destroy_event && switch_window_pending)
+ {
+ last_window ();
+ switch_window_pending = 0;
+ }
+}
+
+void
+configure_request (XConfigureRequestEvent *e)
+{
+ XConfigureEvent ce;
+ rp_window *win;
+
+ win = find_window (e->window);
+
+ if (win)
+ {
+ ce.type = ConfigureNotify;
+ ce.event = e->window;
+ ce.window = e->window;
+ ce.x = 0;
+ ce.y = 0;
+ ce.width = win->scr->root_attr.width;
+ ce.height = win->scr->root_attr.height;
+ ce.border_width = 0;
+ ce.above = None;
+ ce.override_redirect = 0;
+
+ if (e->value_mask & CWStackMode && win->state == STATE_MAPPED)
+ {
+ if (e->detail == Above)
+ {
+ rp_current_window = win;
+ set_active_window (rp_current_window);
+ }
+ else if (e->detail == Below && win == rp_current_window)
+ {
+ last_window ();
+ }
+ }
+
+ XSendEvent(dpy, win->w, False, StructureNotifyMask, (XEvent*)&ce);
+ }
+}
+
+void
+delete_window ()
+{
+ XEvent ev;
+ int status;
+
+ if (rp_current_window == NULL) return;
+
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = rp_current_window->w;
+ ev.xclient.message_type = wm_protocols;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = wm_delete;
+ ev.xclient.data.l[1] = CurrentTime;
+
+ status = XSendEvent(dpy, rp_current_window->w, False, 0, &ev);
+ if (status == 0) fprintf(stderr, "ratpoison: XSendEvent failed\n");
+}
+
+void
+kill_window ()
+{
+ if (rp_current_window == NULL) return;
+
+ XKillClient(dpy, rp_current_window->w);
+}
+
+static void
+client_msg (XClientMessageEvent *ev)
+{
+ printf ("Recieved client message.\n");
+}
+
+static void
+goto_win_by_name (screen_info *s)
+{
+ char winname[100];
+
+ get_input (s, "Window: ", winname, 100);
+ printf ("user entered: %s\n", winname);
+
+ goto_window_name (winname);
+}
+
+static void
+handle_key (screen_info *s)
+{
+ int revert;
+ Window fwin;
+ XEvent ev;
+ int keysym;
+
+#ifdef DEBUG
+ printf ("handling key.\n");
+#endif
+
+ XGetInputFocus (dpy, &fwin, &revert);
+ XSetInputFocus (dpy, s->key_window, RevertToPointerRoot, CurrentTime);
+ XMaskEvent (dpy, KeyPressMask, &ev);
+ XSetInputFocus (dpy, fwin, revert, CurrentTime);
+
+ if (XLookupKeysym((XKeyEvent *) &ev, 0) == KEY_PREFIX && !ev.xkey.state)
+ {
+ /* Generate the prefix keystroke for the app */
+ ev.xkey.window = fwin;
+ ev.xkey.state = MODIFIER_PREFIX;
+ XSendEvent (dpy, fwin, False, KeyPressMask, &ev);
+ XSync (dpy, False);
+ return;
+ }
+
+ keysym = XLookupKeysym((XKeyEvent *) &ev, 0);
+
+ if (keysym == KEY_TOGGLEBAR)
+ {
+ toggle_bar (s);
+ return;
+ }
+
+ /* All functions tested for after this point hide the program bar. */
+ hide_bar (s);
+
+ if (keysym >= '0' && keysym <= '9')
+ {
+ goto_window_number (XLookupKeysym((XKeyEvent *) &ev, 0) - '0');
+ hide_bar (s);
+ return;
+ }
+
+ switch (keysym)
+ {
+ case KEY_XTERM:
+ spawn (TERM_PROG);
+ break;
+ case KEY_EMACS:
+ spawn (EMACS_PROG);
+ break;
+ case KEY_PREVWINDOW:
+ prev_window ();
+ break;
+ case KEY_NEXTWINDOW:
+ next_window ();
+ break;
+ case KEY_LASTWINDOW:
+ last_window ();
+ break;
+ case KEY_WINBYNAME:
+ goto_win_by_name (s);
+ break;
+ case KEY_RENAME:
+ rename_current_window ();
+ break;
+ case KEY_DELETE:
+ if (ev.xkey.state & ShiftMask) kill_window ();
+ else delete_window ();
+ break;
+ default:
+ fprintf (stderr, "Unknown key command '%c'\n", (char)keysym);
+ break;
+ }
+}
+
+void
+key_press (XEvent *ev)
+{
+ screen_info *s;
+ unsigned int modifier = ev->xkey.state;
+ int ks = XLookupKeysym((XKeyEvent *) ev, 0);
+
+ s = find_screen (ev->xkey.root);
+
+ if (s && ks == KEY_PREFIX && (modifier & MODIFIER_PREFIX))
+ {
+ handle_key (s);
+ }
+}
+
+void
+property_notify (XEvent *ev)
+{
+ rp_window *win;
+
+ printf ("atom: %ld\n", ev->xproperty.atom);
+
+ win = find_window (ev->xproperty.window);
+
+ if (win)
+ {
+ if (ev->xproperty.atom == XA_WM_NAME)
+ {
+ printf ("updating window name\n");
+ if (update_window_name (win))
+ {
+ update_window_names (win->scr);
+ }
+ }
+ }
+}
+
+/* Given an event, call the correct function to handle it. */
+void
+delegate_event (XEvent *ev)
+{
+ switch (ev->type)
+ {
+ case ConfigureRequest:
+ printf ("ConfigureRequest\n");
+ configure_request (&ev->xconfigurerequest);
+ break;
+ case CirculateRequest:
+ printf ("CirculateRequest\n");
+ break;
+ case CreateNotify:
+ printf ("CreateNotify\n");
+ new_window (&ev->xcreatewindow);
+ break;
+ case DestroyNotify:
+ printf ("DestroyNotify\n");
+ destroy_window (&ev->xdestroywindow);
+ break;
+ case ClientMessage:
+ client_msg (&ev->xclient);
+ printf ("ClientMessage\n");
+ break;
+ case ColormapNotify:
+ printf ("ColormapNotify\n");
+ break;
+ case PropertyNotify:
+ printf ("PropertyNotify\n");
+ property_notify (ev);
+ break;
+ case SelectionClear:
+ printf ("SelectionClear\n");
+ break;
+ case SelectionNotify:
+ printf ("SelectionNotify\n");
+ break;
+ case SelectionRequest:
+ printf ("SelectionRequest\n");
+ break;
+ case EnterNotify:
+ printf ("EnterNotify\n");
+ break;
+ case ReparentNotify:
+ printf ("ReparentNotify\n");
+ break;
+ case FocusIn:
+ printf ("FocusIn\n");
+ break;
+
+ case MapRequest:
+ printf ("MapRequest\n");
+ map_request (ev);
+ break;
+
+ case KeyPress:
+ printf ("KeyPress\n");
+ key_press (ev);
+ break;
+
+ case UnmapNotify:
+ printf ("UnmapNotify\n");
+ unmap_notify (ev);
+ break;
+
+ case MotionNotify:
+ printf ("MotionNotify\n");
+ break;
+ case Expose:
+ printf ("Expose\n");
+ break;
+ case FocusOut:
+ printf ("FocusOut\n");
+ break;
+ case ConfigureNotify:
+ printf ("ConfigureNotify\n");
+ break;
+ case MapNotify:
+ printf ("MapNotify\n");
+ break;
+ case MappingNotify:
+ printf ("MappingNotify\n");
+ break;
+ default:
+ printf ("Unhandled event %d\n", ev->type);
+ }
+}
+
+void
+handle_events ()
+{
+ XEvent ev;
+
+ for (;;)
+ {
+ XNextEvent (dpy, &ev);
+ delegate_event (&ev);
+ }
+}
+
+
diff --git a/src/events.h b/src/events.h
new file mode 100644
index 0000000..8751e68
--- /dev/null
+++ b/src/events.h
@@ -0,0 +1,29 @@
+/* Function prototypes
+ *
+ * Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#ifndef _EVENTS_H
+#define _EVENTS_H
+
+void handle_events ();
+void delegate_event (XEvent *ev);
+void key_press (XEvent *ev);
+void map_request (XEvent *ev);
+void unmap_notify (XEvent *ev);
+
+#endif _EVENTS_H
diff --git a/src/input.c b/src/input.c
new file mode 100644
index 0000000..ad8f093
--- /dev/null
+++ b/src/input.c
@@ -0,0 +1,75 @@
+/* for reading kdb input from the user. Currently only used to read in
+ the name of a window to jump to. */
+
+#include <X11/keysym.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "ratpoison.h"
+
+
+static int
+read_key ()
+{
+ XEvent ev;
+
+ XMaskEvent (dpy, KeyPressMask, &ev);
+ return XLookupKeysym ((XKeyEvent *)&ev, 0);
+}
+
+/* pass in a pointer a string and how much room we have, and fill it
+ in with text from the user. */
+void
+get_input (screen_info *s, char *prompt, char *str, int len)
+{
+ int cur_len; /* Current length of the string. */
+ int ch;
+ int revert;
+ Window fwin;
+ int prompt_width = XTextWidth (s->font, prompt, strlen (prompt));
+ int width = 100 + prompt_width;
+
+ /* We don't want to draw overtop of the program bar. */
+ hide_bar (s);
+
+ XMapWindow (dpy, s->input_window);
+ XMoveResizeWindow (dpy, s->input_window,
+ bar_x (s, width), bar_y (s), width, (FONT_HEIGHT (s->font) + BAR_PADDING * 2));
+ XClearWindow (dpy, s->input_window);
+ XRaiseWindow (dpy, s->input_window);
+
+ /* draw the window prompt. */
+ XDrawString (dpy, s->input_window, s->bold_gc, 5,
+ BAR_PADDING + s->font->max_bounds.ascent, prompt, strlen (prompt));
+
+ XGetInputFocus (dpy, &fwin, &revert);
+ XSetInputFocus (dpy, s->input_window, RevertToPointerRoot, CurrentTime);
+
+ cur_len = 0;
+ while ((ch = read_key ()) != XK_Return)
+ {
+ printf ("key %d\n", ch);
+ if (ch == XK_BackSpace)
+ {
+ if (cur_len > 0) cur_len--;
+ XClearWindow (dpy, s->input_window);
+ XDrawString (dpy, s->input_window, s->bold_gc, 5,
+ BAR_PADDING + s->font->max_bounds.ascent, prompt, strlen (prompt));
+ XDrawString (dpy, s->input_window, s->bold_gc, 5 + prompt_width,
+ BAR_PADDING + s->font->max_bounds.ascent, str, cur_len);
+ }
+ else if (ch >= ' ')
+ {
+ str[cur_len] = ch;
+ if (cur_len < len - 1) cur_len++;
+
+ XDrawString (dpy, s->input_window, s->bold_gc, 5 + prompt_width,
+ BAR_PADDING + s->font->max_bounds.ascent, str, cur_len);
+ }
+ }
+
+ str[cur_len] = 0;
+ XSetInputFocus (dpy, fwin, RevertToPointerRoot, CurrentTime);
+ XUnmapWindow (dpy, s->input_window);
+}
+
diff --git a/src/input.h b/src/input.h
new file mode 100644
index 0000000..9d49bbf
--- /dev/null
+++ b/src/input.h
@@ -0,0 +1 @@
+void get_input (screen_info *s, char *prompt, char *str, int len);
diff --git a/src/list.c b/src/list.c
new file mode 100644
index 0000000..ee04b34
--- /dev/null
+++ b/src/list.c
@@ -0,0 +1,271 @@
+/* functions for handling the window list
+ *
+ * Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "ratpoison.h"
+
+rp_window *rp_window_head, *rp_window_tail;
+rp_window *rp_current_window;
+
+rp_window *
+add_to_window_list (screen_info *s, Window w)
+{
+ rp_window *new_window;
+
+ new_window = malloc (sizeof (rp_window));
+ if (new_window == NULL)
+ {
+ fprintf (stderr, "list.c:add_to_window_list():Out of memory!\n");
+ exit (EXIT_FAILURE);
+ }
+ new_window->w = w;
+ new_window->scr = s;
+ new_window->last_access = 0;
+ new_window->prev = NULL;
+ new_window->state = STATE_UNMAPPED;
+ new_window->number = -1;
+ new_window->named = 0;
+
+ if ((new_window->name = malloc (strlen ("Unnamed") + 1)) == NULL)
+ {
+ fprintf (stderr, "list.c:add_to_window_list():Out of memory.\n");
+ exit (EXIT_FAILURE);
+ }
+ strcpy (new_window->name, "Unnamed");
+
+ if (rp_window_head == NULL)
+ {
+ /* The list is empty. */
+ rp_window_head = new_window;
+ rp_window_tail = new_window;
+ new_window->next = NULL;
+ return new_window;
+ }
+
+ /* Add the window to the head of the list. */
+ new_window->next = rp_window_head;
+ rp_window_head->prev = new_window;
+ rp_window_head = new_window;
+
+ return new_window;
+}
+
+/* Check to see if the window is already in our list of managed windows. */
+rp_window *
+find_window (Window w)
+{
+ rp_window *cur;
+
+ for (cur = rp_window_head; cur; cur = cur->next)
+ if (cur->w == w) return cur;
+
+ return NULL;
+}
+
+void
+remove_from_window_list (rp_window *w)
+{
+ if (rp_window_head == w) rp_window_head = w->next;
+ if (rp_window_tail == w) rp_window_tail = w->prev;
+
+ if (w->prev != NULL) w->prev->next = w->next;
+ if (w->next != NULL) w->next->prev = w->prev;
+
+ /* set rp_current_window to NULL, so a dangling pointer is not
+ left. */
+ if (rp_current_window == w) rp_current_window = NULL;
+
+ free (w);
+#ifdef DEBUG
+ printf ("Removed window from list.\n");
+#endif
+}
+
+void
+set_current_window (rp_window *win)
+{
+ rp_current_window = win;
+}
+
+void
+init_window_list ()
+{
+ rp_window_head = rp_window_tail = NULL;
+ rp_current_window = NULL;
+}
+
+void
+next_window ()
+{
+ if (rp_current_window != NULL)
+ {
+ rp_current_window = rp_current_window->next;
+ if (rp_current_window == NULL)
+ {
+ rp_current_window = rp_window_head;
+ }
+ if (rp_current_window->state == STATE_UNMAPPED) next_window ();
+ set_active_window (rp_current_window);
+ }
+}
+
+void
+prev_window ()
+{
+ if (rp_current_window != NULL)
+ {
+ set_current_window (rp_current_window->prev);
+ if (rp_current_window == NULL)
+ {
+ rp_current_window = rp_window_tail;
+ }
+ if (rp_current_window->state == STATE_UNMAPPED) prev_window ();
+ set_active_window (rp_current_window);
+ }
+}
+
+rp_window *
+find_window_by_number (int n)
+{
+ rp_window *cur;
+
+ for (cur=rp_window_head; cur; cur=cur->next)
+ {
+ if (cur->state != STATE_MAPPED) continue;
+
+ if (n == cur->number) return cur;
+ }
+
+ return NULL;
+}
+
+/* A case insensitive strncmp. */
+static int
+str_comp (char *s1, char *s2, int len)
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ if (toupper (s1[i]) != toupper (s2[i])) return 0;
+
+ return 1;
+}
+
+static rp_window *
+find_window_by_name (char *name)
+{
+ rp_window *cur;
+
+ for (cur=rp_window_head; cur; cur=cur->next)
+ {
+ if (str_comp (name, cur->name, strlen (name))) return cur;
+ }
+
+ return NULL;
+}
+
+void
+goto_window_name (char *name)
+{
+ rp_window *win;
+
+ if ((win = find_window_by_name (name)) == NULL)
+ {
+ return;
+ }
+
+ rp_current_window = win;
+ set_active_window (rp_current_window);
+}
+
+void
+goto_window_number (int n)
+{
+ rp_window *win;
+
+ if ((win = find_window_by_number (n)) == NULL)
+ {
+ return;
+ }
+
+ rp_current_window = win;
+ set_active_window (rp_current_window);
+}
+
+rp_window *
+find_last_accessed_window ()
+{
+ int last_access = 0;
+ rp_window *cur, *most_recent;
+
+ /* Find the first mapped window */
+ for (most_recent = rp_window_head; most_recent; most_recent=most_recent->next)
+ {
+ if (most_recent->state == STATE_MAPPED) break;
+ }
+
+ /* If there are no mapped windows, don't bother with the next part */
+ if (most_recent == NULL) return NULL;
+
+ for (cur=rp_window_head; cur; cur=cur->next)
+ {
+ if (cur->last_access >= last_access
+ && cur != rp_current_window
+ && cur->state == STATE_MAPPED)
+ {
+ most_recent = cur;
+ last_access = cur->last_access;
+ }
+ }
+
+ return most_recent;
+}
+
+void
+last_window ()
+{
+ rp_current_window = find_last_accessed_window ();
+ set_active_window (rp_current_window);
+}
+
+void
+set_active_window (rp_window *rp_w)
+{
+ static int counter = 1; /* increments every time this function
+ is called. This way we can track
+ which window was last accessed. */
+
+ if (rp_w == NULL) return;
+
+ counter++;
+ rp_w->last_access = counter;
+
+ if (rp_w->scr->bar_is_raised) update_window_names (rp_w->scr);
+
+ XSetInputFocus (dpy, rp_w->w,
+ RevertToPointerRoot, CurrentTime);
+ XRaiseWindow (dpy, rp_w->w);
+
+ /* Make sure the program bar is always on the top */
+ update_window_names (rp_w->scr);
+}
diff --git a/src/list.h b/src/list.h
new file mode 100644
index 0000000..170c2e2
--- /dev/null
+++ b/src/list.h
@@ -0,0 +1,35 @@
+/* functions for managing the window list
+ *
+ * Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#ifndef _LIST_H
+#define _LIST_H
+
+rp_window *add_to_window_list (screen_info *s, Window w);
+void init_window_list ();
+void remove_from_window_list (rp_window *w);
+void next_window ();
+void prev_window ();
+void last_window ();
+rp_window *find_window (Window w);
+void maximize_current_window ();
+void set_active_window (rp_window *rp_w);
+void set_current_window (rp_window *win);
+void goto_window_number (int n);
+void goto_window_name (char *name);
+#endif /* _LIST_H */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..313d7fc
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/Xproto.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "ratpoison.h"
+
+static void init_screen (screen_info *s, int screen_num);
+
+Atom wm_state;
+Atom wm_change_state;
+Atom wm_protocols;
+Atom wm_delete;
+Atom wm_take_focus;
+Atom wm_colormaps;
+
+Atom rp_restart;
+
+screen_info *screens;
+int num_screens;
+Display *dpy;
+int exit_signal = 0; /* Set by the signal handler. if this
+ is set, quit. */
+static XFontStruct *font;
+
+char **myargv;
+
+void
+sighandler ()
+{
+ fprintf (stderr, "ratpoison: Agg! I've been SHOT!\n");
+ clean_up ();
+ exit (EXIT_FAILURE);
+}
+
+void
+hup_handler ()
+{
+ /* This doesn't seem to restart more than once for some reason...*/
+
+ fprintf (stderr, "ratpoison: Restarting with a fresh plate.\n");
+ clean_up ();
+ execvp(myargv[0], myargv);
+}
+
+void
+alrm_handler ()
+{
+ int i;
+
+#ifdef DEBUG
+ printf ("alarm recieved.\n");
+#endif
+
+ /* FIXME: should only hide 1 bar, but we hide them all. */
+ for (i=0; i<num_screens; i++)
+ {
+ hide_bar (&screens[i]);
+ }
+ XSync (dpy, False);
+}
+
+int
+handler (Display *d, XErrorEvent *e)
+{
+ char error_msg[100];
+
+ if (e->request_code == X_ChangeWindowAttributes && e->error_code == BadAccess) {
+ fprintf(stderr, "ratpoison: There can be only ONE.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ XGetErrorText (d, e->error_code, error_msg, sizeof (error_msg));
+ fprintf (stderr, "ratpoison: %s!\n", error_msg);
+
+ return 0;
+ // exit (EXIT_FAILURE);
+}
+
+int
+main (int argc, char *argv[])
+{
+ int i;
+
+ myargv = argv;
+
+ if (!(dpy = XOpenDisplay (NULL)))
+ {
+ fprintf (stderr, "Can't open display\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Setup signal handlers. */
+ XSetErrorHandler(handler);
+ if (signal (SIGALRM, alrm_handler) == SIG_IGN) signal (SIGALRM, SIG_IGN);
+ if (signal (SIGTERM, sighandler) == SIG_IGN) signal (SIGTERM, SIG_IGN);
+ if (signal (SIGINT, sighandler) == SIG_IGN) signal (SIGINT, SIG_IGN);
+ if (signal (SIGHUP, hup_handler) == SIG_IGN)
+ {
+ printf ("Ignoring HUP.\n");
+ signal (SIGHUP, SIG_IGN);
+ }
+
+ init_numbers ();
+ init_window_list ();
+
+ font = XLoadQueryFont (dpy, FONT_NAME);
+ if (font == NULL)
+ {
+ fprintf (stderr, "ratpoison: Cannot load font %s.\n", FONT_NAME);
+ exit (EXIT_FAILURE);
+ }
+
+ num_screens = ScreenCount (dpy);
+ if ((screens = (screen_info *)malloc (sizeof (screen_info) * num_screens)) == NULL)
+ {
+ fprintf (stderr, "ratpoison:main.c:Out of memory!\n");
+ exit (EXIT_FAILURE);
+ }
+
+ printf ("%d screens.\n", num_screens);
+
+ /* Initialize the screens */
+ for (i=0; i<num_screens; i++)
+ {
+ init_screen (&screens[i], i);
+ }
+
+ /* Set our Atoms */
+ wm_state = XInternAtom(dpy, "WM_STATE", False);
+ wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False);
+ wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False);
+ wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+ wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
+ wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False);
+
+ rp_restart = XInternAtom (dpy, "RP_RESTART", False);
+
+ XSync (dpy, False);
+
+ /* Set an initial window as active. */
+ rp_current_window = rp_window_head;
+ set_active_window (rp_current_window);
+
+ handle_events ();
+
+ return EXIT_SUCCESS;
+}
+
+static void
+init_screen (screen_info *s, int screen_num)
+{
+ XColor fg_color, bg_color, bold_color, junk;
+ XGCValues gv;
+
+ s->screen_num = screen_num;
+ s->root = RootWindow (dpy, screen_num);
+ s->def_cmap = DefaultColormap (dpy, screen_num);
+ s->font = font;
+ XGetWindowAttributes (dpy, s->root, &s->root_attr);
+
+ /* Get our program bar colors */
+ if (!XAllocNamedColor (dpy, s->def_cmap, BAR_FG_COLOR, &fg_color, &junk))
+ {
+ fprintf (stderr, "Unknown color '%s'\n", BAR_FG_COLOR);
+ }
+
+ if (!XAllocNamedColor (dpy, s->def_cmap, BAR_BG_COLOR, &bg_color, &junk))
+ {
+ fprintf (stderr, "Unknown color '%s'\n", BAR_BG_COLOR);
+ }
+
+ if (!XAllocNamedColor (dpy, s->def_cmap, BAR_BOLD_COLOR, &bold_color, &junk))
+ {
+ fprintf (stderr, "Unknown color '%s'\n", BAR_BOLD_COLOR);
+ }
+
+ /* Setup the GC for drawing the font. */
+ gv.foreground = fg_color.pixel;
+ gv.background = bg_color.pixel;
+ gv.function = GXcopy;
+ gv.line_width = 1;
+ gv.subwindow_mode = IncludeInferiors;
+ gv.font = font->fid;
+ s->normal_gc = XCreateGC(dpy, s->root,
+ GCForeground | GCBackground | GCFunction
+ | GCLineWidth | GCSubwindowMode | GCFont,
+ &gv);
+ gv.foreground = bold_color.pixel;
+ s->bold_gc = XCreateGC(dpy, s->root,
+ GCForeground | GCBackground | GCFunction
+ | GCLineWidth | GCSubwindowMode | GCFont,
+ &gv);
+
+ XSelectInput(dpy, s->root,
+ PropertyChangeMask | ColormapChangeMask
+ | SubstructureRedirectMask | KeyPressMask
+ | SubstructureNotifyMask );
+ XSync (dpy, 0);
+
+ /* Create the program bar window. */
+ s->bar_is_raised = 0;
+ s->bar_window = XCreateSimpleWindow (dpy, s->root, 0, 0,
+ 1, 1, 1, fg_color.pixel, bg_color.pixel);
+ XSelectInput (dpy, s->bar_window, StructureNotifyMask);
+
+ /* Setup the window that will recieve all keystrokes once the prefix
+ key has been pressed. */
+ s->key_window = XCreateSimpleWindow (dpy, s->root, 0, 0, 1, 1, 0, WhitePixel (dpy, 0), BlackPixel (dpy, 0));
+ XSelectInput (dpy, s->key_window, KeyPressMask);
+ XMapWindow (dpy, s->key_window);
+
+ /* Create the input window. */
+ s->input_window = XCreateSimpleWindow (dpy, s->root, 0, 0,
+ 1, 1, 1, fg_color.pixel, bg_color.pixel);
+ XSelectInput (dpy, s->input_window, KeyPressMask);
+ scanwins (s);
+}
+
+void
+clean_up ()
+{
+ XSetInputFocus (dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
+ XCloseDisplay (dpy);
+}
+
+/* Given a root window, return the screen_info struct */
+screen_info *
+find_screen (Window w)
+{
+ int i;
+
+ for (i=0; i<num_screens; i++)
+ if (screens[i].root == w) return &screens[i];
+
+ return NULL;
+}
diff --git a/src/manage.c b/src/manage.c
new file mode 100644
index 0000000..592e391
--- /dev/null
+++ b/src/manage.c
@@ -0,0 +1,175 @@
+/* Manage windows, such as Mapping them and making sure the proper key
+ * Grabs have been put in place.
+ *
+ * Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/keysymdef.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ratpoison.h"
+
+extern Atom wm_state;
+
+static void
+grab_prefix_key (Window w)
+{
+ XGrabKey(dpy, XKeysymToKeycode (dpy, KEY_PREFIX ), MODIFIER_PREFIX, w, True,
+ GrabModeAsync, GrabModeAsync);
+}
+
+/* Reget the WM_NAME property for the window and update its name. */
+int
+update_window_name (rp_window *win)
+{
+ XTextProperty text;
+ char **name_list;
+ int list_len;
+ int i;
+
+ /* Don't overwrite the window name if the user specified one. */
+ if (win->named) return 0;
+
+ if (!XGetWMName (dpy, win->w, &text))
+ {
+ fprintf (stderr, "ratpoison:manage.c: I can't get the WMName.\n");
+ return 0;
+ }
+
+ if (!XTextPropertyToStringList (&text, &name_list, &list_len))
+ {
+ fprintf (stderr, "ratpoison:manage.c:Error retrieving TextList.\n");
+ return 0;
+ }
+
+ for (i=0; i<list_len; i++)
+ {
+ printf ("WMName: %s\n", name_list[i]);
+ }
+
+ /* Set the window's name to the first in the name_list */
+ if (list_len > 0)
+ {
+ char *loc;
+
+ free (win->name);
+ if ((win->name = malloc (strlen (name_list[0]) + 1)) == NULL)
+ {
+ fprintf (stderr, "manage.c:update_window_name():Out of memory!\n");
+ exit (EXIT_FAILURE);
+ }
+ strcpy (win->name, name_list[0]);
+
+ /* A bit of a hack. If there's a : in the string, crop the
+ string off there. This is mostly brought on by netscape's
+ disgusting tendency to put its current URL in the WMName!!
+ arg! */
+ loc = strchr (win->name, ':');
+ if (loc) loc[0] = '\0';
+ }
+
+ /* Its our responsibility to free this. */
+ XFreeStringList (name_list);
+
+ return 1;
+}
+
+void
+rename_current_window ()
+{
+ char winname[100];
+
+ if (rp_current_window == NULL) return;
+
+ get_input (rp_current_window->scr, "Name: ", winname, 100);
+ printf ("user entered: %s\n", winname);
+
+ free (rp_current_window->name);
+ rp_current_window->name = malloc (sizeof (char) * strlen (winname) + 1);
+ if (rp_current_window->name == NULL)
+ {
+ fprintf (stderr, "ratpoison:rename_window(): Out of memory\n");
+ exit (EXIT_FAILURE);
+ }
+ strcpy (rp_current_window->name, winname);
+ rp_current_window->named = 1;
+
+ /* Update the program bar. */
+ update_window_names (rp_current_window->scr);
+}
+
+void
+manage (rp_window *win, screen_info *s)
+{
+ if (!update_window_name (win)) return;
+
+ /* We successfully got the name, which means we can start managing! */
+ XMapWindow (dpy, win->w);
+ XMoveResizeWindow (dpy, win->w, 0, 0, s->root_attr.width, s->root_attr.height);
+ XSelectInput (dpy, win->w, PropertyChangeMask);
+ XAddToSaveSet(dpy, win->w);
+ grab_prefix_key (win->w);
+
+ win->state = STATE_MAPPED;
+ win->number = get_unique_window_number ();
+
+#ifdef DEBUG
+ printf ("window '%s' managed.\n", win->name);
+#endif
+}
+
+void
+unmanage (rp_window *w)
+{
+ return_window_number (w->number);
+ remove_from_window_list (w);
+}
+
+/* When starting up scan existing windows and start managing them. */
+void
+scanwins(screen_info *s)
+{
+ rp_window *win;
+ XWindowAttributes attr;
+ unsigned int i, nwins;
+ Window dw1, dw2, *wins;
+
+ XQueryTree(dpy, s->root, &dw1, &dw2, &wins, &nwins);
+#ifdef DEBUG
+ printf ("windows: %d\n", nwins);
+#endif
+
+ for (i = 0; i < nwins; i++)
+ {
+ XGetWindowAttributes(dpy, wins[i], &attr);
+ if (wins[i] == s->bar_window || wins[i] == s->key_window || wins[i] == s->input_window) continue;
+
+ if (attr.override_redirect != True)
+ {
+ win = add_to_window_list (s, wins[i]);
+ if (attr.map_state != IsUnmapped) manage (win, s);
+ }
+ }
+ XFree((void *) wins); /* cast is to shut stoopid compiler up */
+}
diff --git a/src/manage.h b/src/manage.h
new file mode 100644
index 0000000..58a5590
--- /dev/null
+++ b/src/manage.h
@@ -0,0 +1,30 @@
+/* manage.h
+ *
+ * Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#ifndef _MANAGE_H
+#define _MANAGE_H
+
+#include "data.h"
+
+void scanwins(screen_info *s);
+void manage (rp_window *w, screen_info *s);
+void unmanage (rp_window *w);
+int update_window_name (rp_window *win);
+void rename_current_window ();
+#endif /* _MANAGE_H */
diff --git a/src/number.c b/src/number.c
new file mode 100644
index 0000000..6bd11c6
--- /dev/null
+++ b/src/number.c
@@ -0,0 +1,130 @@
+/* handles the handing out of and uniqueness of window numbers.
+
+ * Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "ratpoison.h"
+
+
+/* A list of the numbers taken. */
+static int *numbers_taken;
+
+/* the number of numbers currently stored in the numbers_taken
+ array. */
+static int num_taken;
+
+/* the size of the numbers_taken array. */
+static int max_taken;
+
+static int
+number_is_taken (int n)
+{
+ int i;
+
+ for (i=0; i<num_taken; i++)
+ {
+ if (numbers_taken[i] == n) return 1;
+ }
+ return 0;
+}
+
+/* returns index into numbers_taken that can be used. */
+static int
+find_empty_cell ()
+{
+ int i;
+
+ for (i=0; i<num_taken; i++)
+ {
+ if (numbers_taken[i] == -1) return i;
+ }
+
+ /* no vacant ones, so grow the array. */
+ if (num_taken >= max_taken)
+ {
+ max_taken *= 2;
+ numbers_taken = realloc (numbers_taken, sizeof (int) * max_taken);
+ if (numbers_taken == NULL)
+ {
+ fprintf (stderr, "numbers.c: Out of memory\n");
+ exit (EXIT_FAILURE);
+ }
+ }
+ num_taken++;
+
+ return num_taken-1;
+}
+
+static int
+add_to_list (int n)
+{
+ if (number_is_taken (n)) return 0; /* failed. */
+
+ numbers_taken[find_empty_cell()] = n;
+ return 1; /* success! */
+}
+
+/* returns a unique number that can be used as the window number in
+ the program bar. */
+int
+get_unique_window_number ()
+{
+ int i;
+
+ /* look for a unique number, and add it to the list of taken
+ numbers. */
+ i = 0;
+ while (!add_to_list (i)) i++;
+
+ return i;
+}
+
+/* When a window is destroyed, it gives back its window number with
+ this function. */
+void
+return_window_number (int n)
+{
+ int i;
+
+ for (i=0; i<num_taken; i++)
+ {
+ if (numbers_taken[i] == n)
+ {
+ numbers_taken[i] = -1;
+ return;
+ }
+ }
+}
+
+
+void
+init_numbers ()
+{
+ max_taken = 10;
+ num_taken = 0;
+
+ numbers_taken = malloc (max_taken * sizeof (int));
+ if (numbers_taken == NULL)
+ {
+ fprintf (stderr, "numbers.c: Cannot alloc numbers_taken.\n");
+ exit (EXIT_FAILURE);
+ }
+
+}
diff --git a/src/number.h b/src/number.h
new file mode 100644
index 0000000..f06fb53
--- /dev/null
+++ b/src/number.h
@@ -0,0 +1,3 @@
+int get_unique_window_number ();
+void return_window_number (int n);
+void init_numbers ();
diff --git a/src/ratpoison.h b/src/ratpoison.h
new file mode 100644
index 0000000..8b83866
--- /dev/null
+++ b/src/ratpoison.h
@@ -0,0 +1,40 @@
+/* Standard header for ratpoison.
+ *
+ * Copyright (C) 2000 Shawn Betts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA */
+
+#ifndef _RATPOISON_H
+#define _RATPOISON_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "conf.h"
+
+#include "data.h"
+#include "manage.h"
+#include "list.h"
+#include "bar.h"
+#include "events.h"
+#include "number.h"
+#include "input.h"
+
+void clean_up ();
+screen_info *find_screen (Window w);
+
+#endif /* _RATPOISON_H */