2wm

dual window manager prototype (minimalist dwm with no tags, just one view)
git clone git://git.suckless.org/2wm
Log | Files | Refs | README | LICENSE

event.c (7116B)


      1 /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
      2  * See LICENSE file for license details.
      3  */
      4 #include "2wm.h"
      5 #include <stdlib.h>
      6 #include <X11/keysym.h>
      7 #include <X11/Xatom.h>
      8 
      9 /* static */
     10 
     11 typedef struct {
     12 	unsigned long mod;
     13 	KeySym keysym;
     14 	void (*func)(Arg *arg);
     15 	Arg arg;
     16 } Key;
     17 
     18 KEYS
     19 
     20 #define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
     21 #define MOUSEMASK		(BUTTONMASK | PointerMotionMask)
     22 
     23 static void
     24 movemouse(Client *c) {
     25 	int x1, y1, ocx, ocy, di;
     26 	unsigned int dui;
     27 	Window dummy;
     28 	XEvent ev;
     29 
     30 	ocx = c->x;
     31 	ocy = c->y;
     32 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
     33 			None, cursor[CurMove], CurrentTime) != GrabSuccess)
     34 		return;
     35 	c->ismax = False;
     36 	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
     37 	for(;;) {
     38 		XMaskEvent(dpy, MOUSEMASK | SubstructureRedirectMask, &ev);
     39 		switch (ev.type) {
     40 		case ButtonRelease:
     41 			resize(c, True);
     42 			XUngrabPointer(dpy, CurrentTime);
     43 			return;
     44 		case ConfigureRequest:
     45 		case MapRequest:
     46 			handler[ev.type](&ev);
     47 			break;
     48 		case MotionNotify:
     49 			XSync(dpy, False);
     50 			c->x = ocx + (ev.xmotion.x - x1);
     51 			c->y = ocy + (ev.xmotion.y - y1);
     52 			if(abs(sx + c->x) < SNAP)
     53 				c->x = sx;
     54 			else if(abs((sx + sw) - (c->x + c->w + 2 * c->border)) < SNAP)
     55 				c->x = sx + sw - c->w - 2 * c->border;
     56 			if(abs(sy - c->y) < SNAP)
     57 				c->y = sy;
     58 			else if(abs((sy + sh) - (c->y + c->h + 2 * c->border)) < SNAP)
     59 				c->y = sy + sh - c->h - 2 * c->border;
     60 			resize(c, False);
     61 			break;
     62 		}
     63 	}
     64 }
     65 
     66 static void
     67 resizemouse(Client *c) {
     68 	int ocx, ocy;
     69 	int nw, nh;
     70 	XEvent ev;
     71 
     72 	ocx = c->x;
     73 	ocy = c->y;
     74 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
     75 			None, cursor[CurResize], CurrentTime) != GrabSuccess)
     76 		return;
     77 	c->ismax = False;
     78 	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
     79 	for(;;) {
     80 		XMaskEvent(dpy, MOUSEMASK | SubstructureRedirectMask , &ev);
     81 		switch(ev.type) {
     82 		case ButtonRelease:
     83 			resize(c, True);
     84 			XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
     85 					c->w + c->border - 1, c->h + c->border - 1);
     86 			XUngrabPointer(dpy, CurrentTime);
     87 			while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
     88 			return;
     89 		case ConfigureRequest:
     90 		case MapRequest:
     91 			handler[ev.type](&ev);
     92 			break;
     93 		case MotionNotify:
     94 			XSync(dpy, False);
     95 			nw = ev.xmotion.x - ocx - 2 * c->border + 1;
     96 			c->w = nw > 0 ? nw : 1;
     97 			nh = ev.xmotion.y - ocy - 2 * c->border + 1;
     98 			c->h = nh > 0 ? nh : 1;
     99 			resize(c, True);
    100 			break;
    101 		}
    102 	}
    103 }
    104 
    105 static void
    106 buttonpress(XEvent *e) {
    107 	Client *c;
    108 	XButtonPressedEvent *ev = &e->xbutton;
    109 
    110 	if((c = getclient(ev->window))) {
    111 		focus(c);
    112 		if(CLEANMASK(ev->state) != MODKEY)
    113 			return;
    114 		if(ev->button == Button1 && c->isfloat) {
    115 			restack();
    116 			movemouse(c);
    117 		}
    118 		else if(ev->button == Button2)
    119 			zoom(NULL);
    120 		else if(ev->button == Button3 && c->isfloat && !c->isfixed) {
    121 			restack();
    122 			resizemouse(c);
    123 		}
    124 	}
    125 }
    126 
    127 static void
    128 configurerequest(XEvent *e) {
    129 	unsigned long newmask;
    130 	Client *c;
    131 	XConfigureRequestEvent *ev = &e->xconfigurerequest;
    132 	XWindowChanges wc;
    133 
    134 	if((c = getclient(ev->window))) {
    135 		c->ismax = False;
    136 		if(ev->value_mask & CWX)
    137 			c->x = ev->x;
    138 		if(ev->value_mask & CWY)
    139 			c->y = ev->y;
    140 		if(ev->value_mask & CWWidth)
    141 			c->w = ev->width;
    142 		if(ev->value_mask & CWHeight)
    143 			c->h = ev->height;
    144 		if(ev->value_mask & CWBorderWidth)
    145 			c->border = ev->border_width;
    146 		wc.x = c->x;
    147 		wc.y = c->y;
    148 		wc.width = c->w;
    149 		wc.height = c->h;
    150 		newmask = ev->value_mask & (~(CWSibling | CWStackMode | CWBorderWidth));
    151 		if(newmask)
    152 			XConfigureWindow(dpy, c->win, newmask, &wc);
    153 		else
    154 			configure(c);
    155 		XSync(dpy, False);
    156 		if(c->isfloat) {
    157 			resize(c, False);
    158 			if(c->view != view)
    159 				XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
    160 		}
    161 		else
    162 			arrange();
    163 	}
    164 	else {
    165 		wc.x = ev->x;
    166 		wc.y = ev->y;
    167 		wc.width = ev->width;
    168 		wc.height = ev->height;
    169 		wc.border_width = ev->border_width;
    170 		wc.sibling = ev->above;
    171 		wc.stack_mode = ev->detail;
    172 		XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
    173 		XSync(dpy, False);
    174 	}
    175 }
    176 
    177 static void
    178 destroynotify(XEvent *e) {
    179 	Client *c;
    180 	XDestroyWindowEvent *ev = &e->xdestroywindow;
    181 
    182 	if((c = getclient(ev->window)))
    183 		unmanage(c);
    184 }
    185 
    186 static void
    187 enternotify(XEvent *e) {
    188 	Client *c;
    189 	XCrossingEvent *ev = &e->xcrossing;
    190 
    191 	if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
    192 		return;
    193 	if((c = getclient(ev->window)) && c->view == view)
    194 		focus(c);
    195 	else if(ev->window == root) {
    196 		selscreen = True;
    197 		for(c = stack; c && c->view != view; c = c->snext);
    198 		focus(c);
    199 	}
    200 }
    201 
    202 static void
    203 keypress(XEvent *e) {
    204 	static unsigned int len = sizeof key / sizeof key[0];
    205 	unsigned int i;
    206 	KeySym keysym;
    207 	XKeyEvent *ev = &e->xkey;
    208 
    209 	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
    210 	for(i = 0; i < len; i++) {
    211 		if(keysym == key[i].keysym
    212 			&& CLEANMASK(key[i].mod) == CLEANMASK(ev->state))
    213 		{
    214 			if(key[i].func)
    215 				key[i].func(&key[i].arg);
    216 		}
    217 	}
    218 }
    219 
    220 static void
    221 leavenotify(XEvent *e) {
    222 	XCrossingEvent *ev = &e->xcrossing;
    223 
    224 	if((ev->window == root) && !ev->same_screen) {
    225 		selscreen = False;
    226 		focus(NULL);
    227 	}
    228 }
    229 
    230 static void
    231 mappingnotify(XEvent *e) {
    232 	XMappingEvent *ev = &e->xmapping;
    233 
    234 	XRefreshKeyboardMapping(ev);
    235 	if(ev->request == MappingKeyboard)
    236 		grabkeys();
    237 }
    238 
    239 static void
    240 maprequest(XEvent *e) {
    241 	static XWindowAttributes wa;
    242 	XMapRequestEvent *ev = &e->xmaprequest;
    243 
    244 	if(!XGetWindowAttributes(dpy, ev->window, &wa))
    245 		return;
    246 	if(wa.override_redirect)
    247 		return;
    248 	if(!getclient(ev->window))
    249 		manage(ev->window, &wa);
    250 }
    251 
    252 static void
    253 propertynotify(XEvent *e) {
    254 	Client *c;
    255 	Window trans;
    256 	XPropertyEvent *ev = &e->xproperty;
    257 
    258 	if(ev->state == PropertyDelete)
    259 		return; /* ignore */
    260 	if((c = getclient(ev->window))) {
    261 		switch (ev->atom) {
    262 			default: break;
    263 			case XA_WM_TRANSIENT_FOR:
    264 				XGetTransientForHint(dpy, c->win, &trans);
    265 				if(!c->isfloat && (c->isfloat = (trans != 0)))
    266 					arrange();
    267 				break;
    268 			case XA_WM_NORMAL_HINTS:
    269 				updatesizehints(c);
    270 				break;
    271 		}
    272 	}
    273 }
    274 
    275 static void
    276 unmapnotify(XEvent *e) {
    277 	Client *c;
    278 	XUnmapEvent *ev = &e->xunmap;
    279 
    280 	if((c = getclient(ev->window)))
    281 		unmanage(c);
    282 }
    283 
    284 /* extern */
    285 
    286 void (*handler[LASTEvent]) (XEvent *) = {
    287 	[ButtonPress] = buttonpress,
    288 	[ConfigureRequest] = configurerequest,
    289 	[DestroyNotify] = destroynotify,
    290 	[EnterNotify] = enternotify,
    291 	[LeaveNotify] = leavenotify,
    292 	[KeyPress] = keypress,
    293 	[MappingNotify] = mappingnotify,
    294 	[MapRequest] = maprequest,
    295 	[PropertyNotify] = propertynotify,
    296 	[UnmapNotify] = unmapnotify
    297 };
    298 
    299 void
    300 grabkeys(void) {
    301 	static unsigned int len = sizeof key / sizeof key[0];
    302 	unsigned int i;
    303 	KeyCode code;
    304 
    305 	XUngrabKey(dpy, AnyKey, AnyModifier, root);
    306 	for(i = 0; i < len; i++) {
    307 		code = XKeysymToKeycode(dpy, key[i].keysym);
    308 		XGrabKey(dpy, code, key[i].mod, root, True,
    309 				GrabModeAsync, GrabModeAsync);
    310 		XGrabKey(dpy, code, key[i].mod | LockMask, root, True,
    311 				GrabModeAsync, GrabModeAsync);
    312 		XGrabKey(dpy, code, key[i].mod | numlockmask, root, True,
    313 				GrabModeAsync, GrabModeAsync);
    314 		XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True,
    315 				GrabModeAsync, GrabModeAsync);
    316 	}
    317 }