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
| @@ -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 @@ -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); +} @@ -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" @@ -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; +} @@ -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); @@ -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 +} @@ -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); @@ -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); +} @@ -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); @@ -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); @@ -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); | 
