diff options
-rw-r--r-- | Makefile | 19 | ||||
-rw-r--r-- | bar.c | 117 | ||||
-rw-r--r-- | bar.h | 10 | ||||
-rw-r--r-- | conf.h | 23 | ||||
-rw-r--r-- | data.h | 52 | ||||
-rw-r--r-- | events.c | 354 | ||||
-rw-r--r-- | events.h | 12 | ||||
-rw-r--r-- | list.c | 170 | ||||
-rw-r--r-- | list.h | 16 | ||||
-rw-r--r-- | main.c | 229 | ||||
-rw-r--r-- | manage.c | 108 | ||||
-rw-r--r-- | manage.h | 13 | ||||
-rw-r--r-- | ratpoison.h | 17 |
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 @@ -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)); + } +} + + + @@ -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 @@ -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 */ @@ -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 @@ -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); +} @@ -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 */ @@ -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 */ |