about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--bar.c18
-rw-r--r--client.c89
-rw-r--r--config.h4
-rw-r--r--draw.c6
-rw-r--r--draw.h1
-rw-r--r--event.c264
-rw-r--r--menu.c9
-rw-r--r--util.c23
-rw-r--r--util.h6
-rw-r--r--wm.c51
-rw-r--r--wm.h40
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);