| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 | /* * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com> * See LICENSE file for license details. */#include <math.h>#include <stdlib.h>#include <string.h>#include <X11/Xatom.h>#include "util.h"#include "wm.h"voidmax(void *aux){	if(!stack)		return;	stack->x = sx;	stack->y = bh;	stack->w = sw - 2 * stack->border;	stack->h = sh - bh - 2 * stack->border;	resize(stack);	discard_events(EnterWindowMask);}voidarrange(void *aux){	Client *c;	int n, cols, rows, gw, gh, i, j;    float rt, fd;	if(!clients)		return;	for(n = 0, c = clients; c; c = c->next, n++);	rt = sqrt(n);	if(modff(rt, &fd) < 0.5)		rows = floor(rt);	else		rows = ceil(rt);	if(rows * rows < n)		cols = rows + 1;	else		cols = rows;	gw = (sw - 2)  / cols;	gh = (sh - bh - 2) / rows;	for(i = j = 0, c = clients; c; c = c->next) {		c->x = i * gw;		c->y = j * gh + bh;		c->w = gw;		c->h = gh;		resize(c);		if(++i == cols) {			j++;			i = 0;		}	}	discard_events(EnterWindowMask);}voidsel(void *aux){	const char *arg = aux;	Client *c = NULL;	if(!arg || !stack)		return;	if(!strncmp(arg, "next", 5))		c = stack->snext ? stack->snext : stack;	else if(!strncmp(arg, "prev", 5))		for(c = stack; c && c->snext; c = c->snext);	if(!c)		c = stack;	raise(c);	focus(c);}voidkill(void *aux){	Client *c = stack;	if(!c)		return;	if(c->proto & WM_PROTOCOL_DELWIN)		send_message(c->win, wm_atom[WMProtocols], wm_atom[WMDelete]);	else		XKillClient(dpy, c->win);}static voidresize_title(Client *c){	c->tw = textw(&brush.font, c->name) + bh;	if(c->tw > c->w)		c->tw = c->w + 2;	c->tx = c->x + c->w - c->tw + 2;	c->ty = c->y;	XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);}voidupdate_name(Client *c){	XTextProperty name;	int n;	char **list = NULL;	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);	resize_title(c);}voidupdate_size(Client *c){	XSizeHints size;	long msize;	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)		size.flags = PSize;	c->flags = size.flags;	if(c->flags & PBaseSize) {		c->basew = size.base_width;		c->baseh = size.base_height;	}	else		c->basew = c->baseh = 0;	if(c->flags & PResizeInc) {		c->incw = size.width_inc;		c->inch = size.height_inc;	}	else		c->incw = c->inch = 0;	if(c->flags & PMaxSize) {		c->maxw = size.max_width;		c->maxh = size.max_height;	}	else		c->maxw = c->maxh = 0;	if(c->flags & PMinSize) {		c->minw = size.min_width;		c->minh = size.min_height;	}	else		c->minw = c->minh = 0;	if(c->flags & PWinGravity)		c->grav = size.win_gravity;	else		c->grav = NorthWestGravity;}voidraise(Client *c){	XRaiseWindow(dpy, c->win);	XRaiseWindow(dpy, c->title);}voidlower(Client *c){	XLowerWindow(dpy, c->title);	XLowerWindow(dpy, c->win);}voidfocus(Client *c){	Client **l, *old;	old = stack;	for(l = &stack; *l && *l != c; l = &(*l)->snext);	eassert(*l == c);	*l = c->snext;	c->snext = stack;	stack = c;	if(old && old != c) {		XMapWindow(dpy, old->title);		draw_client(old);	}	XUnmapWindow(dpy, c->title);	draw_client(c);	XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);	XFlush(dpy);}voidmanage(Window w, XWindowAttributes *wa){	Client *c, **l;	XSetWindowAttributes twa;	c = emallocz(sizeof(Client));	c->win = w;	c->tx = c->x = wa->x;	c->ty = c->y = wa->y;	if(c->y < bh)		c->ty = c->y += bh;	c->tw = c->w = wa->width;	c->h = wa->height;	c->th = bh;	c->border = 1;	update_size(c);	XSetWindowBorderWidth(dpy, c->win, 1);	XSetWindowBorder(dpy, c->win, brush.border);	XSelectInput(dpy, c->win,			StructureNotifyMask | PropertyChangeMask | EnterWindowMask);	XGetTransientForHint(dpy, c->win, &c->trans);	twa.override_redirect = 1;	twa.background_pixmap = ParentRelative;	twa.event_mask = ExposureMask;	c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,			0, DefaultDepth(dpy, screen), CopyFromParent,			DefaultVisual(dpy, screen),			CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);	update_name(c);	for(l=&clients; *l; l=&(*l)->next);	c->next = *l; /* *l == nil */	*l = c;	c->snext = stack;	stack = c;	XMapRaised(dpy, c->win);	XMapRaised(dpy, c->title);	XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,			GrabModeAsync, GrabModeSync, None, None);	XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,			GrabModeAsync, GrabModeSync, None, None);	XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,			GrabModeAsync, GrabModeSync, None, None);	resize(c);	focus(c);}voidgravitate(Client *c, Bool invert){	int dx = 0, dy = 0;	switch(c->grav) {	case StaticGravity:	case NorthWestGravity:	case NorthGravity:	case NorthEastGravity:		dy = c->border;		break;	case EastGravity:	case CenterGravity:	case WestGravity:		dy = -(c->h / 2) + c->border;		break;	case SouthEastGravity:	case SouthGravity:	case SouthWestGravity:		dy = -c->h;		break;	default:		break;	}	switch (c->grav) {	case StaticGravity:	case NorthWestGravity:	case WestGravity:	case SouthWestGravity:		dx = c->border;		break;	case NorthGravity:	case CenterGravity:	case SouthGravity:		dx = -(c->w / 2) + c->border;		break;	case NorthEastGravity:	case EastGravity:	case SouthEastGravity:		dx = -(c->w + c->border);		break;	default:		break;	}	if(invert) {		dx = -dx;		dy = -dy;	}	c->x += dx;	c->y += dy;}voidresize(Client *c){	XConfigureEvent e;	resize_title(c);	XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);	e.type = ConfigureNotify;	e.event = c->win;	e.window = c->win;	e.x = c->x;	e.y = c->y;	e.width = c->w;	e.height = c->h;	e.border_width = c->border;	e.above = None;	e.override_redirect = False;	XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);	XFlush(dpy);}static intdummy_error_handler(Display *dpy, XErrorEvent *error){	return 0;}voidunmanage(Client *c){	Client **l;	XGrabServer(dpy);	XSetErrorHandler(dummy_error_handler);	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);	XDestroyWindow(dpy, c->title);	for(l=&clients; *l && *l != c; l=&(*l)->next);	eassert(*l == c);	*l = c->next;	for(l=&stack; *l && *l != c; l=&(*l)->snext);	eassert(*l == c);	*l = c->snext;	free(c);	XFlush(dpy);	XSetErrorHandler(error_handler);	XUngrabServer(dpy);	if(stack)		focus(stack);}Client *gettitle(Window w){	Client *c;	for(c = clients; c; c = c->next)		if(c->title == w)			return c;	return NULL;}Client *getclient(Window w){	Client *c;	for(c = clients; c; c = c->next)		if(c->win == w)			return c;	return NULL;}voiddraw_client(Client *c){	if(c == stack) {		draw_bar();		return;	}	brush.x = brush.y = 0;	brush.w = c->tw;	brush.h = c->th;	draw(dpy, &brush, True, c->name);	XCopyArea(dpy, brush.drawable, c->title, brush.gc,			0, 0, c->tw, c->th, 0, 0);	XFlush(dpy);}
 |