summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsabetts <sabetts>2000-08-25 05:06:20 +0000
committersabetts <sabetts>2000-08-25 05:06:20 +0000
commitd8a5963532fb35687bedee59f2235144f3930fbd (patch)
tree0fe07517902d532361e049ebe774f62c3ec23d09
downloadratpoison-d8a5963532fb35687bedee59f2235144f3930fbd.zip
initial checkin
-rw-r--r--Makefile19
-rw-r--r--bar.c117
-rw-r--r--bar.h10
-rw-r--r--conf.h23
-rw-r--r--data.h52
-rw-r--r--events.c354
-rw-r--r--events.h12
-rw-r--r--list.c170
-rw-r--r--list.h16
-rw-r--r--main.c229
-rw-r--r--manage.c108
-rw-r--r--manage.h13
-rw-r--r--ratpoison.h17
13 files changed, 1140 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2453f96
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+CC = gcc
+
+SRC = main.o events.o manage.o list.o bar.o
+
+LIBS = -lX11
+
+LDFLAGS = -L/usr/X11R6/lib
+CFLAGS = -g -Wall -I/usr/X11R6/include
+
+DEBUG = -DDEBUG
+
+ratpoison: $(SRC)
+ gcc $(SRC) -o $@ $(CFLAGS) $(LDFLAGS) $(LIBS)
+
+%.o : %.c ratpoison.h conf.h
+ $(CC) -c $(CFLAGS) $(DEBUG) $< -o $@
+
+clean :
+ rm -f *.o ratpoison
diff --git a/bar.c b/bar.c
new file mode 100644
index 0000000..d5ac700
--- /dev/null
+++ b/bar.c
@@ -0,0 +1,117 @@
+/* Functionality for a bar across the bottom of the screen listing the
+ windows currently managed. */
+
+#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)
+{
+ int size = 1;
+ rp_window *cur;
+
+ for (cur = rp_window_head; cur; cur = cur->next)
+ {
+ if (cur->state == STATE_UNMAPPED) continue;
+ size += 10 + XTextWidth (font, cur->name, strlen (cur->name));
+ }
+
+ return size;
+}
+
+static int
+bar_x (screen_info *s, int width)
+{
+ if (BAR_LOCATION >= 2) return s->root_attr.width - width;
+ else return 0;
+}
+
+static 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)
+{
+ 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;
+ for (cur = rp_window_head; cur; cur = cur->next)
+ {
+ if (cur->state == STATE_UNMAPPED) continue;
+
+ if ( rp_current_window == cur)
+ {
+ XDrawString (dpy, s->bar_window, s->bold_gc, cur_x,
+ BAR_PADDING + s->font->max_bounds.ascent, cur->name, strlen (cur->name));
+ }
+ else
+ {
+ XDrawString (dpy, s->bar_window, s->normal_gc, cur_x,
+ BAR_PADDING + s->font->max_bounds.ascent, cur->name, strlen (cur->name));
+ }
+ cur_x += 10 + XTextWidth (s->font, cur->name, strlen (cur->name));
+ }
+}
+
+
+
diff --git a/bar.h b/bar.h
new file mode 100644
index 0000000..4509b0f
--- /dev/null
+++ b/bar.h
@@ -0,0 +1,10 @@
+/* functions for managing the program bar */
+
+#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);
+#endif _BAR_H
diff --git a/conf.h b/conf.h
new file mode 100644
index 0000000..b12953f
--- /dev/null
+++ b/conf.h
@@ -0,0 +1,23 @@
+/* Config file for ratpoison. Edit these values and recompile. */
+
+#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 TERM_PROG "xterm" /* command to boot an xterm */
+#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/data.h b/data.h
new file mode 100644
index 0000000..05cbbb2
--- /dev/null
+++ b/data.h
@@ -0,0 +1,52 @@
+/* our datatypes and global variables */
+
+#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;
+ char *name;
+ int state;
+ int last_access;
+ 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;
+ 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;
+
+/* 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/events.c b/events.c
new file mode 100644
index 0000000..f148314
--- /dev/null
+++ b/events.c
@@ -0,0 +1,354 @@
+#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)
+ {
+ 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)
+ {
+ 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);
+ }
+}
+
+void
+destroy_window (XDestroyWindowEvent *ev)
+{
+ int tmp;
+ Window fwin;
+ screen_info *s;
+ rp_window *win;
+
+ s = find_screen (ev->event);
+ win = find_window (ev->window);
+ if (s && win)
+ {
+ unmanage (win);
+ }
+
+ XGetInputFocus (dpy, &fwin, &tmp);
+ win = find_window (fwin);
+
+ if (win)
+ {
+ rp_current_window = win;
+ set_active_window (win);
+ }
+ else
+ {
+ update_window_names (s);
+ }
+
+#ifdef DEBUG
+ printf ("Remove window event.\n");
+#endif
+}
+
+void
+configure_request (XConfigureRequestEvent *e)
+{
+ XConfigureEvent ce;
+ // XWindowChanges wc;
+ rp_window *win;
+
+ win = find_window (e->window);
+
+ if (win)
+ {
+/* if (e->value_mask & CWX) */
+/* wc->x = e->x; */
+/* if (e->value_mask & CWY) */
+/* wc->y = e->y; */
+/* if (e->value_mask & CWWidth) */
+/* wc->dx = e->width; */
+/* if (e->value_mask & CWHeight) */
+/* wc->dy = e->height; */
+/* if (e->value_mask & CWBorderWidth) */
+/* wc->border_width = e->border_width; */
+
+/* if (e->value_mask & CWStackMode) { */
+/* if (wc.stack_mode == Above); */
+/* else */
+/* we->value_mask &= ~CWStackMode; */
+/* } */
+
+/* wc.sibling = None; */
+/* wc.stack_mode = e.detail; */
+
+/* XConfigureWindow (dpy, e->window, e->value_mask, &wc); */
+
+
+ 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;
+ XSendEvent(dpy, win->w, False, StructureNotifyMask, (XEvent*)&ce);
+ }
+}
+
+static void
+client_msg (XClientMessageEvent *ev)
+{
+}
+
+static void
+handle_key (screen_info *s)
+{
+ int revert;
+ Window fwin;
+ XEvent ev;
+
+#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;
+ }
+
+ switch (XLookupKeysym((XKeyEvent *) &ev, 0))
+ {
+ 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_TOGGLEBAR:
+ toggle_bar (s);
+ break;
+ case KEY_LASTWINDOW:
+ last_window ();
+ break;
+ default:
+ fprintf (stderr, "Unknown key command %c", (char)XKeycodeToKeysym(dpy, ev.xkey.keycode, 0));
+ 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);
+ }
+}
+
+/* Given an event, call the correct function to handle it. */
+void
+delegate_event (XEvent *ev)
+{
+ switch (ev->type)
+ {
+ case ConfigureRequest:
+ configure_request (&ev->xconfigurerequest);
+ printf ("ConfigureRequest\n");
+ 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");
+ 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:
+ unmap_notify (ev);
+ printf ("UnmapNotify\n");
+ 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/events.h b/events.h
new file mode 100644
index 0000000..b92fe81
--- /dev/null
+++ b/events.h
@@ -0,0 +1,12 @@
+/* Function prototypes */
+
+#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/list.c b/list.c
new file mode 100644
index 0000000..ff38476
--- /dev/null
+++ b/list.c
@@ -0,0 +1,170 @@
+/* functions for handling the window list */
+
+#include <stdio.h>
+#include <stdlib.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;
+ 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;
+
+ if (rp_current_window == w) rp_current_window = rp_window_head;
+ if (rp_current_window && rp_current_window->state == STATE_UNMAPPED) next_window ();
+
+ 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_last_accessed_window ()
+{
+ int last_access = 0;
+ rp_window *cur, *most_recent = 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 = most_recent->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/list.h b/list.h
new file mode 100644
index 0000000..bbbea95
--- /dev/null
+++ b/list.h
@@ -0,0 +1,16 @@
+/* functions for managing the window list */
+
+#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);
+#endif /* _LIST_H */
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..5038d93
--- /dev/null
+++ b/main.c
@@ -0,0 +1,229 @@
+#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)
+{
+ if (e->request_code == X_ChangeWindowAttributes && e->error_code == BadAccess) {
+ fprintf(stderr, "ratpoison: There can be only ONE.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf (stderr, "ratpoison: Ya some error happened, but whatever.\n");
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int i;
+
+ myargv = argv;
+
+ if (!(dpy = XOpenDisplay (NULL)))
+ {
+ fprintf (stderr, "Can't open display\n");
+ return EXIT_FAILURE;
+ }
+
+ 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);
+ }
+
+ /* 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) signal (SIGHUP, SIG_IGN);
+
+ /* 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);
+
+ /* 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->bar_window, StructureNotifyMask);
+ XMapWindow (dpy, s->key_window);
+ grab_keys (s);
+
+ 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/manage.c b/manage.c
new file mode 100644
index 0000000..59dc185
--- /dev/null
+++ b/manage.c
@@ -0,0 +1,108 @@
+/* Manage windows, such as Mapping them and making sure the proper key
+ Grabs have been put in place. */
+
+#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 "ratpoison.h"
+
+extern Atom wm_state;
+
+void
+grab_keys (screen_info *s)
+{
+ XGrabKey(dpy, XKeysymToKeycode (dpy, KEY_XTERM ), AnyModifier, s->key_window, True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey(dpy, XKeysymToKeycode (dpy, KEY_EMACS ), AnyModifier, s->key_window, True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey(dpy, XKeysymToKeycode (dpy, KEY_PREVWINDOW ), AnyModifier, s->key_window, True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey(dpy, XKeysymToKeycode (dpy, KEY_NEXTWINDOW ), AnyModifier, s->key_window, True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey(dpy, XKeysymToKeycode (dpy, KEY_TOGGLEBAR ), AnyModifier, s->key_window, True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey(dpy, XKeysymToKeycode (dpy, KEY_LASTWINDOW ), AnyModifier, s->key_window, True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey(dpy, XKeysymToKeycode (dpy, KEY_PREFIX ), AnyModifier, s->key_window, True,
+ GrabModeAsync, GrabModeAsync);
+}
+
+static void
+grab_prefix_key (Window w)
+{
+ XGrabKey(dpy, XKeysymToKeycode (dpy, KEY_PREFIX ), MODIFIER_PREFIX, w, True,
+ GrabModeAsync, GrabModeAsync);
+}
+
+void
+manage (rp_window *win, screen_info *s)
+{
+ XClassHint hint;
+
+ 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;
+
+ if (!XGetClassHint (dpy, win->w, &hint))
+ {
+ fprintf (stderr, "ratpoison: I can't get the ClassHint, I don't what to do!\n");
+ exit (EXIT_FAILURE);
+ }
+
+ free (win->name);
+ if ((win->name = malloc (strlen (hint.res_name) + 1)) == NULL)
+ {
+ fprintf (stderr, "manage.c:manage():Out of memory!\n");
+ exit (EXIT_FAILURE);
+ }
+ strcpy (win->name, hint.res_name);
+
+ /* Its our responsibility to free these. */
+ XFree (hint.res_name);
+ XFree (hint.res_class);
+
+#ifdef DEBUG
+ printf ("window '%s' managed.\n", win->name);
+#endif
+}
+
+void
+unmanage (rp_window *w)
+{
+ 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) continue;
+
+ win = add_to_window_list (s, wins[i]);
+ manage (win, s);
+ }
+ XFree((void *) wins); /* cast is to shut stoopid compiler up */
+}
diff --git a/manage.h b/manage.h
new file mode 100644
index 0000000..de58131
--- /dev/null
+++ b/manage.h
@@ -0,0 +1,13 @@
+/* manage.h */
+
+#ifndef _MANAGE_H
+#define _MANAGE_H
+
+#include "data.h"
+
+void grab_keys ();
+void scanwins(screen_info *s);
+void manage (rp_window *w, screen_info *s);
+void unmanage (rp_window *w);
+
+#endif /* _MANAGE_H */
diff --git a/ratpoison.h b/ratpoison.h
new file mode 100644
index 0000000..a8ab47a
--- /dev/null
+++ b/ratpoison.h
@@ -0,0 +1,17 @@
+/* Some standard datatypes for ratpoison */
+
+#ifndef _RATPOISON_H
+#define _RATPOISON_H
+
+#include "conf.h"
+
+#include "data.h"
+#include "manage.h"
+#include "list.h"
+#include "bar.h"
+#include "events.h"
+
+void clean_up ();
+screen_info *find_screen (Window w);
+
+#endif /* _RATPOISON_H */