diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | bar.c | 18 | ||||
-rw-r--r-- | client.c | 89 | ||||
-rw-r--r-- | config.h | 4 | ||||
-rw-r--r-- | draw.c | 6 | ||||
-rw-r--r-- | draw.h | 1 | ||||
-rw-r--r-- | event.c | 264 | ||||
-rw-r--r-- | menu.c | 9 | ||||
-rw-r--r-- | util.c | 23 | ||||
-rw-r--r-- | util.h | 6 | ||||
-rw-r--r-- | wm.c | 51 | ||||
-rw-r--r-- | wm.h | 40 |
12 files changed, 476 insertions, 39 deletions
diff --git a/Makefile b/Makefile index 7a74149..c5c8db4 100644 --- a/Makefile +++ b/Makefile @@ -3,11 +3,11 @@ include config.mk -WMSRC = wm.c draw.c util.c +WMSRC = bar.c client.c draw.c event.c util.c wm.c WMOBJ = ${WMSRC:.c=.o} MENSRC = menu.c draw.c util.c MENOBJ = ${MENSRC:.c=.o} -MAN = gridwm.1 +MAN1 = gridwm.1 gridmenu.1 BIN = gridwm gridmenu all: config gridwm gridmenu diff --git a/bar.c b/bar.c new file mode 100644 index 0000000..8d4fb36 --- /dev/null +++ b/bar.c @@ -0,0 +1,18 @@ +/* + * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include "wm.h" + +void +draw_bar() +{ + brush.rect = barrect; + brush.rect.x = brush.rect.y = 0; + draw(dpy, &brush, False, 0); + + XCopyArea(dpy, brush.drawable, barwin, brush.gc, 0, 0, barrect.width, + barrect.height, 0, 0); + XFlush(dpy); +} diff --git a/client.c b/client.c new file mode 100644 index 0000000..a5141ea --- /dev/null +++ b/client.c @@ -0,0 +1,89 @@ +/* + * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <string.h> +#include <X11/Xatom.h> + +#include "util.h" +#include "wm.h" + +static void +update_client_name(Client *c) +{ + XTextProperty name; + int n; + char **list = 0; + + name.nitems = 0; + c->name[0] = 0; + XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]); + if(!name.nitems) + XGetWMName(dpy, c->win, &name); + if(!name.nitems) + return; + if(name.encoding == XA_STRING) + strncpy(c->name, (char *)name.value, sizeof(c->name)); + else { + if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success + && n > 0 && *list) + { + strncpy(c->name, *list, sizeof(c->name)); + XFreeStringList(list); + } + } + XFree(name.value); +} + +Client * +create_client(Window w, XWindowAttributes *wa) +{ + Client *c; + XSetWindowAttributes twa; + long msize; + + c = emallocz(sizeof(Client)); + c->win = w; + c->r[RFloat].x = wa->x; + c->r[RFloat].y = wa->y; + c->r[RFloat].width = wa->width; + c->r[RFloat].height = wa->height; + c->border = wa->border_width; + XSetWindowBorderWidth(dpy, c->win, 0); + c->proto = win_proto(c->win); + XGetTransientForHint(dpy, c->win, &c->trans); + if(!XGetWMNormalHints(dpy, c->win, &c->size, &msize) || !c->size.flags) + c->size.flags = PSize; + c->fixedsize = + (c->size.flags & PMinSize && c->size.flags & PMaxSize + && c->size.min_width == c->size.max_width + && c->size.min_height == c->size.max_height); + XAddToSaveSet(dpy, c->win); + update_client_name(c); + twa.override_redirect = 1; + twa.background_pixmap = ParentRelative; + twa.event_mask = ExposureMask; + + c->title = XCreateWindow(dpy, root, c->r[RFloat].x, c->r[RFloat].y, + c->r[RFloat].width, barrect.height, 0, + DefaultDepth(dpy, screen), CopyFromParent, + DefaultVisual(dpy, screen), + CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa); + XFlush(dpy); + +#if 0 + for(t=&client, i=0; *t; t=&(*t)->next, i++); + c->next = *t; /* *t == nil */ + *t = c; +#endif + return c; +} + +void +manage(Client *c) +{ + XMapRaised(dpy, c->win); + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XFlush(dpy); +} diff --git a/config.h b/config.h index 6a768b6..ca05aa2 100644 --- a/config.h +++ b/config.h @@ -4,6 +4,6 @@ */ #define FONT "-*-terminus-medium-*-*-*-14-*-*-*-*-*-iso10646-*" -#define FGCOLOR "#000000" -#define BGCOLOR "#ffaa00" +#define BGCOLOR "#000000" +#define FGCOLOR "#ffaa00" #define BORDERCOLOR "#000000" diff --git a/draw.c b/draw.c index cf7f14e..b89c365 100644 --- a/draw.c +++ b/draw.c @@ -162,3 +162,9 @@ loadfont(Display *dpy, Fnt *font, const char *fontstr) } font->height = font->ascent + font->descent; } + +unsigned int +labelheight(Fnt *font) +{ + return font->height + 4; +} diff --git a/draw.h b/draw.h index 710087f..6c3d886 100644 --- a/draw.h +++ b/draw.h @@ -33,3 +33,4 @@ extern void loadcolors(Display *dpy, int screen, Brush *b, extern void loadfont(Display *dpy, Fnt *font, const char *fontstr); extern unsigned int textwidth_l(Fnt *font, char *text, unsigned int len); extern unsigned int textwidth(Fnt *font, char *text); +extern unsigned int labelheight(Fnt *font); diff --git a/event.c b/event.c new file mode 100644 index 0000000..d6977d3 --- /dev/null +++ b/event.c @@ -0,0 +1,264 @@ +/* + * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <X11/keysym.h> + +#include "wm.h" + +/* local functions */ +static void configurerequest(XEvent *e); +static void destroynotify(XEvent *e); +static void enternotify(XEvent *e); +static void leavenotify(XEvent *e); +static void expose(XEvent *e); +static void keypress(XEvent *e); +static void keymapnotify(XEvent *e); +static void maprequest(XEvent *e); +static void propertynotify(XEvent *e); +static void unmapnotify(XEvent *e); + +void (*handler[LASTEvent]) (XEvent *) = { + [ConfigureRequest] = configurerequest, + [DestroyNotify] = destroynotify, + [EnterNotify] = enternotify, + [LeaveNotify] = leavenotify, + [Expose] = expose, + [KeyPress] = keypress, + [KeymapNotify] = keymapnotify, + [MapRequest] = maprequest, + [PropertyNotify] = propertynotify, + [UnmapNotify] = unmapnotify +}; + +unsigned int +flush_masked_events(long even_mask) +{ + XEvent ev; + unsigned int n = 0; + while(XCheckMaskEvent(dpy, even_mask, &ev)) n++; + return n; +} + +static void +configurerequest(XEvent *e) +{ +#if 0 + XConfigureRequestEvent *ev = &e->xconfigurerequest; + XWindowChanges wc; + XRectangle *frect; + Client *c; + + c = client_of_win(ev->window); + ev->value_mask &= ~CWSibling; + if(c) { + gravitate_client(c, True); + + if(ev->value_mask & CWX) + c->rect.x = ev->x; + if(ev->value_mask & CWY) + c->rect.y = ev->y; + if(ev->value_mask & CWWidth) + c->rect.width = ev->width; + if(ev->value_mask & CWHeight) + c->rect.height = ev->height; + if(ev->value_mask & CWBorderWidth) + c->border = ev->border_width; + + gravitate_client(c, False); + + if(c->frame) { + if(c->sel->area->floating) + frect=&c->sel->rect; + else + frect=&c->sel->revert; + + if(c->rect.width >= screen->rect.width && c->rect.height >= screen->rect.height) { + frect->y = wc.y = -height_of_bar(); + frect->x = wc.x = -def.border; + } + else { + frect->y = wc.y = c->rect.y - height_of_bar(); + frect->x = wc.x = c->rect.x - def.border; + } + frect->width = wc.width = c->rect.width + 2 * def.border; + frect->height = wc.height = c->rect.height + def.border + + height_of_bar(); + wc.border_width = 1; + wc.sibling = None; + wc.stack_mode = ev->detail; + if(c->sel->area->view != screen->sel) + wc.x += 2 * screen->rect.width; + if(c->sel->area->floating) { + XConfigureWindow(dpy, c->framewin, ev->value_mask, &wc); + configure_client(c); + } + } + } + + wc.x = ev->x; + wc.y = ev->y; + wc.width = ev->width; + wc.height = ev->height; + + if(c && c->frame) { + wc.x = def.border; + wc.y = height_of_bar(); + wc.width = c->sel->rect.width - 2 * def.border; + wc.height = c->sel->rect.height - def.border - height_of_bar(); + } + + wc.border_width = 0; + wc.sibling = None; + wc.stack_mode = Above; + ev->value_mask &= ~CWStackMode; + ev->value_mask |= CWBorderWidth; + XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); + + XFlush(dpy); +#endif +} + +static void +destroynotify(XEvent *e) +{ +#if 0 + Client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + if((c = client_of_win(ev->window))) + destroy_client(c); +#endif +} + +static void +enternotify(XEvent *e) +{ +#if 0 + XCrossingEvent *ev = &e->xcrossing; + Client *c; + + if(ev->mode != NotifyNormal || ev->detail == NotifyInferior) + return; + + if((c = client_of_win(ev->window))) { + Frame *f = c->sel; + Area *a = f->area; + if(a->mode == Colmax) + c = a->sel->client; + focus(c, False); + } + else if(ev->window == root) { + sel_screen = True; + draw_frames(); + } +#endif +} + +static void +leavenotify(XEvent *e) +{ + XCrossingEvent *ev = &e->xcrossing; + + if((ev->window == root) && !ev->same_screen) { + sel_screen = True; + /*draw_frames();*/ + } +} + +static void +expose(XEvent *e) +{ + XExposeEvent *ev = &e->xexpose; + + if(ev->count == 0) { + if(ev->window == barwin) + draw_bar(); + } +} + +static void +keypress(XEvent *e) +{ +#if 0 + XKeyEvent *ev = &e->xkey; + KeySym k = 0; + char buf[32]; + int n; + static Frame *f; + + + ev->state &= valid_mask; + if((f = frame_of_win(ev->window))) { + buf[0] = 0; + n = XLookupString(ev, buf, sizeof(buf), &k, 0); + if(IsFunctionKey(k) || IsKeypadKey(k) || IsMiscFunctionKey(k) + || IsPFKey(k) || IsPrivateKeypadKey(k)) + return; + buf[n] = 0; + blitz_kpress_input(&f->tagbar, ev->state, k, buf); + } + else + key(root, ev->state, (KeyCode) ev->keycode); +#endif +} + +static void +keymapnotify(XEvent *e) +{ +#if 0 + update_keys(); +#endif +} + +static void +maprequest(XEvent *e) +{ +#if 0 + XMapRequestEvent *ev = &e->xmaprequest; + static XWindowAttributes wa; + + if(!XGetWindowAttributes(dpy, ev->window, &wa)) + return; + + if(wa.override_redirect) { + XSelectInput(dpy, ev->window, + (StructureNotifyMask | PropertyChangeMask)); + return; + } + + if(!client_of_win(ev->window)) + manage_client(create_client(ev->window, &wa)); +#endif +} + +static void +propertynotify(XEvent *e) +{ +#if 0 + XPropertyEvent *ev = &e->xproperty; + Client *c; + + if(ev->state == PropertyDelete) + return; /* ignore */ + + if((c = client_of_win(ev->window))) + prop_client(c, ev); +#endif +} + +static void +unmapnotify(XEvent *e) +{ +#if 0 + Client *c; + XUnmapEvent *ev = &e->xunmap; + + if((c = client_of_win(ev->window))) + destroy_client(c); +#endif +} diff --git a/menu.c b/menu.c index b4e08d4..7c84305 100644 --- a/menu.c +++ b/menu.c @@ -53,7 +53,7 @@ static const int seek = 30; /* 30px */ static Brush brush = {0}; -static void draw_menu(void); +static void draw_menu(); static void kpress(XKeyEvent * e); static char version[] = "gridmenu - " VERSION ", (C)opyright MMVI Anselm R. Garbe\n"; @@ -397,11 +397,10 @@ main(int argc, char *argv[]) wa.override_redirect = 1; wa.background_pixmap = ParentRelative; - wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask - | SubstructureRedirectMask | SubstructureNotifyMask; + wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask; rect.width = DisplayWidth(dpy, screen); - rect.height = brush.font.height + 4; + rect.height = labelheight(&brush.font); rect.y = DisplayHeight(dpy, screen) - rect.height; rect.x = 0; @@ -413,7 +412,7 @@ main(int argc, char *argv[]) XFlush(dpy); /* pixmap */ - brush.gc = XCreateGC(dpy, win, 0, 0); + brush.gc = XCreateGC(dpy, root, 0, 0); brush.drawable = XCreatePixmap(dpy, win, rect.width, rect.height, DefaultDepth(dpy, screen)); XFlush(dpy); diff --git a/util.c b/util.c index 99842e9..435069f 100644 --- a/util.c +++ b/util.c @@ -7,6 +7,11 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "util.h" void error(char *errstr, ...) { @@ -75,3 +80,21 @@ swap(void **p1, void **p2) *p1 = *p2; *p2 = tmp; } + +void +spawn(Display *dpy, const char *shell, const char *cmd) +{ + if(!cmd || !shell) + return; + if(fork() == 0) { + if(fork() == 0) { + if(dpy) + close(ConnectionNumber(dpy)); + execl(shell, shell, "-c", cmd, (const char *)0); + fprintf(stderr, "gridwm: execl %s", shell); + perror(" failed"); + } + exit (0); + } + wait(0); +} diff --git a/util.h b/util.h index 8ba444b..cac3df0 100644 --- a/util.h +++ b/util.h @@ -2,6 +2,7 @@ * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> * See LICENSE file for license details. */ +#include <X11/Xlib.h> extern void error(char *errstr, ...); extern void *emallocz(unsigned int size); @@ -12,5 +13,6 @@ extern char *estrdup(const char *str); if(!(a)) \ failed_assert(#a, __FILE__, __LINE__); \ } while (0) -void failed_assert(char *a, char *file, int line); -void swap(void **p1, void **p2); +extern void failed_assert(char *a, char *file, int line); +extern void swap(void **p1, void **p2); +extern void spawn(Display *dpy, const char *shell, const char *cmd); diff --git a/wm.c b/wm.c index c8bb0a4..b8b3053 100644 --- a/wm.c +++ b/wm.c @@ -15,15 +15,15 @@ /* X structs */ Display *dpy; -Window root; -XRectangle rect; -Pixmap pmap; -Atom wm_atom[WMLast]; -Atom net_atom[NetLast]; +Window root, barwin; +Atom wm_atom[WMLast], net_atom[NetLast]; Cursor cursor[CurLast]; +XRectangle rect, barrect; +Bool running = True; +char *bartext, *shell; int screen, sel_screen; -unsigned int kmask, numlock_mask; +unsigned int lock_mask, numlock_mask; /* draw structs */ Brush brush = {0}; @@ -166,7 +166,7 @@ init_lock_keys() } XFreeModifiermap(modmap); - kmask = 255 & ~(numlock_mask | LockMask); + lock_mask = 255 & ~(numlock_mask | LockMask); } static void @@ -187,6 +187,7 @@ main(int argc, char *argv[]) XSetWindowAttributes wa; unsigned int mask; Window w; + XEvent ev; /* command line args */ for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) { @@ -218,6 +219,9 @@ main(int argc, char *argv[]) if(other_wm_running) error("gridwm: another window manager is already running\n"); + if(!(shell = getenv("SHELL"))) + shell = "/bin/sh"; + rect.x = rect.y = 0; rect.width = DisplayWidth(dpy, screen); rect.height = DisplayHeight(dpy, screen); @@ -244,19 +248,42 @@ main(int argc, char *argv[]) init_lock_keys(); - pmap = XCreatePixmap(dpy, root, rect.width, rect.height, + brush.drawable = XCreatePixmap(dpy, root, rect.width, rect.height, DefaultDepth(dpy, screen)); - - wa.event_mask = SubstructureRedirectMask | EnterWindowMask | LeaveWindowMask; - wa.cursor = cursor[CurNormal]; - XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); + brush.gc = XCreateGC(dpy, root, 0, 0); /* style */ loadcolors(dpy, screen, &brush, BGCOLOR, FGCOLOR, BORDERCOLOR); loadfont(dpy, &brush.font, FONT); + wa.override_redirect = 1; + wa.background_pixmap = ParentRelative; + wa.event_mask = ExposureMask; + + barrect = rect; + barrect.height = labelheight(&brush.font); + barrect.y = rect.height - barrect.height; + barwin = XCreateWindow(dpy, root, barrect.x, barrect.y, + barrect.width, barrect.height, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); + bartext = 0; + XDefineCursor(dpy, barwin, cursor[CurNormal]); + XMapRaised(dpy, barwin); + draw_bar(); + + wa.event_mask = SubstructureRedirectMask | EnterWindowMask | LeaveWindowMask; + wa.cursor = cursor[CurNormal]; + XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); + scan_wins(); + while(running) { + XNextEvent(dpy, &ev); + if(handler[ev.type]) + (handler[ev.type]) (&ev); /* call handler */ + } + cleanup(); XCloseDisplay(dpy); diff --git a/wm.h b/wm.h index 6bf0d5e..038078f 100644 --- a/wm.h +++ b/wm.h @@ -9,16 +9,14 @@ #include <X11/Xutil.h> -/* WM atoms */ +/* atoms */ enum { WMState, WMProtocols, WMDelete, WMLast }; - -/* NET atoms */ enum { NetSupported, NetWMName, NetLast }; -/* Cursor */ +/* cursor */ enum { CurNormal, CurResize, CurMove, CurInput, CurLast }; -/* Rects */ +/* rects */ enum { RFloat, RGrid, RLast }; typedef struct Client Client; @@ -28,35 +26,45 @@ struct Client { Tag *tag; char name[256]; int proto; + unsigned int border; + Bool fixedsize; Window win; Window trans; Window title; - GC gc; XSizeHints size; XRectangle r[RLast]; Client *next; - Client *tnext; - Client *tprev; + Client *snext; }; struct Tag { char name[256]; - Client *clients; - Client *sel; + Client *stack; XRectangle r; + Tag *next; + Tag *cnext; }; extern Display *dpy; -extern Window root; -extern XRectangle rect; -extern Atom wm_atom[WMLast]; -extern Atom net_atom[NetLast]; +extern Window root, barwin; +extern Atom wm_atom[WMLast], net_atom[NetLast]; extern Cursor cursor[CurLast]; -extern Pixmap pmap; +extern XRectangle rect, barrect; +extern Bool running; +extern void (*handler[LASTEvent]) (XEvent *); extern int screen, sel_screen; -extern unsigned int kmask, numlock_mask; +extern unsigned int lock_mask, numlock_mask; +extern char *bartext, *shell; extern Brush brush; +/* bar.c */ +extern void draw_bar(); + +/* client.c */ +extern Client *create_client(Window w, XWindowAttributes *wa); +extern void manage(Client *c); + /* wm.c */ +extern int win_proto(Window w); |