aewl

view event.c @ 384:126e78129f1d

configurenotify remembers max geom now, and restores this if necessary, however it accepts to touch the max size on configurerequest, this shouldn't break fillscreen apps (tested with mplayer)
author Anselm R. Garbe <arg@10kloc.org>
date Tue, 29 Aug 2006 17:31:55 +0200
parents a9b4077ec058
children 37706ba7d492
line source
1 /*
2 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
3 * See LICENSE file for license details.
4 */
5 #include "dwm.h"
6 #include <stdlib.h>
7 #include <X11/keysym.h>
8 #include <X11/Xatom.h>
10 /* static */
12 typedef struct {
13 unsigned long mod;
14 KeySym keysym;
15 void (*func)(Arg *arg);
16 Arg arg;
17 } Key;
19 KEYS
21 #define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
23 static void
24 movemouse(Client *c)
25 {
26 int x1, y1, ocx, ocy, di;
27 unsigned int dui;
28 Window dummy;
29 XEvent ev;
31 ocx = c->x;
32 ocy = c->y;
33 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
34 None, cursor[CurMove], CurrentTime) != GrabSuccess)
35 return;
36 XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
37 for(;;) {
38 XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev);
39 switch (ev.type) {
40 default: break;
41 case Expose:
42 handler[Expose](&ev);
43 break;
44 case MotionNotify:
45 XSync(dpy, False);
46 c->x = ocx + (ev.xmotion.x - x1);
47 c->y = ocy + (ev.xmotion.y - y1);
48 resize(c, False, TopLeft);
49 break;
50 case ButtonRelease:
51 XUngrabPointer(dpy, CurrentTime);
52 return;
53 }
54 }
55 }
57 static void
58 resizemouse(Client *c)
59 {
60 int ocx, ocy;
61 int nw, nh;
62 Corner sticky;
63 XEvent ev;
65 ocx = c->x;
66 ocy = c->y;
67 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
68 None, cursor[CurResize], CurrentTime) != GrabSuccess)
69 return;
70 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w, c->h);
71 for(;;) {
72 XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev);
73 switch(ev.type) {
74 default: break;
75 case Expose:
76 handler[Expose](&ev);
77 break;
78 case MotionNotify:
79 XSync(dpy, False);
80 if((nw = abs(ocx - ev.xmotion.x)))
81 c->w = abs(ocx - ev.xmotion.x);
82 if((nh = abs(ocy - ev.xmotion.y)))
83 c->h = abs(ocy - ev.xmotion.y);
84 c->x = (ocx <= ev.xmotion.x) ? ocx : ocx - c->w;
85 c->y = (ocy <= ev.xmotion.y) ? ocy : ocy - c->h;
86 if(ocx <= ev.xmotion.x)
87 sticky = (ocy <= ev.xmotion.y) ? TopLeft : BotLeft;
88 else
89 sticky = (ocy <= ev.xmotion.y) ? TopRight : BotRight;
90 resize(c, True, sticky);
91 break;
92 case ButtonRelease:
93 XUngrabPointer(dpy, CurrentTime);
94 return;
95 }
96 }
97 }
99 static void
100 buttonpress(XEvent *e)
101 {
102 int x;
103 Arg a;
104 Client *c;
105 XButtonPressedEvent *ev = &e->xbutton;
107 if(barwin == ev->window) {
108 x = 0;
109 for(a.i = 0; a.i < ntags; a.i++) {
110 x += textw(tags[a.i]);
111 if(ev->x < x) {
112 if(ev->button == Button1)
113 view(&a);
114 else if(ev->button == Button3)
115 toggleview(&a);
116 return;
117 }
118 }
119 if(ev->x < x + bmw) {
120 if(ev->button == Button1)
121 togglemode(NULL);
122 }
123 }
124 else if((c = getclient(ev->window))) {
125 focus(c);
126 if(CLEANMASK(ev->state) != MODKEY)
127 return;
128 switch(ev->button) {
129 default:
130 break;
131 case Button1:
132 if(!c->ismax && (arrange == dofloat || c->isfloat)) {
133 restack(c);
134 movemouse(c);
135 }
136 break;
137 case Button2:
138 zoom(NULL);
139 break;
140 case Button3:
141 if(!c->ismax && (arrange == dofloat || c->isfloat)) {
142 restack(c);
143 resizemouse(c);
144 }
145 break;
146 }
147 }
148 }
150 static void
151 configurerequest(XEvent *e)
152 {
153 int ox, oy, ow, oh;
154 unsigned long newmask;
155 Client *c;
156 XConfigureRequestEvent *ev = &e->xconfigurerequest;
157 XEvent synev;
158 XWindowChanges wc;
160 if((c = getclient(ev->window))) {
161 ox = c->x;
162 oy = c->y;
163 ow = c->w;
164 oh = c->h;
165 gravitate(c, True);
166 if(ev->value_mask & CWX)
167 c->x = ev->x;
168 if(ev->value_mask & CWY)
169 c->y = ev->y;
170 if(ev->value_mask & CWWidth)
171 c->w = ev->width;
172 if(ev->value_mask & CWHeight)
173 c->h = ev->height;
174 if(ev->value_mask & CWBorderWidth)
175 c->border = ev->border_width;
176 gravitate(c, False);
177 wc.x = c->x;
178 wc.y = c->y;
179 wc.width = c->w;
180 wc.height = c->h;
181 newmask = ev->value_mask & (~(CWSibling | CWStackMode | CWBorderWidth));
182 if(newmask)
183 XConfigureWindow(dpy, c->win, newmask, &wc);
184 else {
185 synev.type = ConfigureNotify;
186 synev.xconfigure.display = dpy;
187 synev.xconfigure.event = c->win;
188 synev.xconfigure.window = c->win;
189 synev.xconfigure.x = c->x;
190 synev.xconfigure.y = c->y;
191 synev.xconfigure.width = c->w;
192 synev.xconfigure.height = c->h;
193 synev.xconfigure.border_width = c->border;
194 synev.xconfigure.above = None;
195 /* Send synthetic ConfigureNotify */
196 XSendEvent(dpy, c->win, True, NoEventMask, &synev);
197 }
198 XSync(dpy, False);
199 if(c->isfloat || c->ismax) {
200 resize(c, False, TopLeft);
201 c->x = ox;
202 c->y = oy;
203 c->w = ow;
204 c->h = oh;
205 }
206 else
207 arrange(NULL);
208 }
209 else {
210 wc.x = ev->x;
211 wc.y = ev->y;
212 wc.width = ev->width;
213 wc.height = ev->height;
214 wc.border_width = ev->border_width;
215 wc.sibling = ev->above;
216 wc.stack_mode = ev->detail;
217 XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
218 XSync(dpy, False);
219 }
220 }
222 static void
223 destroynotify(XEvent *e)
224 {
225 Client *c;
226 XDestroyWindowEvent *ev = &e->xdestroywindow;
228 if((c = getclient(ev->window)))
229 unmanage(c);
230 }
232 static void
233 enternotify(XEvent *e)
234 {
235 Client *c;
236 XCrossingEvent *ev = &e->xcrossing;
238 if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
239 return;
241 if((c = getclient(ev->window)) || (c = getctitle(ev->window)))
242 focus(c);
243 else if(ev->window == root) {
244 issel = True;
245 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
246 drawall();
247 }
248 }
250 static void
251 expose(XEvent *e)
252 {
253 Client *c;
254 XExposeEvent *ev = &e->xexpose;
256 if(ev->count == 0) {
257 if(barwin == ev->window)
258 drawstatus();
259 else if((c = getctitle(ev->window)))
260 drawtitle(c);
261 }
262 }
264 static void
265 keypress(XEvent *e)
266 {
267 static unsigned int len = sizeof(key) / sizeof(key[0]);
268 unsigned int i;
269 KeySym keysym;
270 XKeyEvent *ev = &e->xkey;
272 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
273 for(i = 0; i < len; i++) {
274 if(keysym == key[i].keysym &&
275 CLEANMASK(key[i].mod) == CLEANMASK(ev->state))
276 {
277 if(key[i].func)
278 key[i].func(&key[i].arg);
279 return;
280 }
281 }
282 }
284 static void
285 leavenotify(XEvent *e)
286 {
287 XCrossingEvent *ev = &e->xcrossing;
289 if((ev->window == root) && !ev->same_screen) {
290 issel = False;
291 drawall();
292 }
293 }
295 static void
296 mappingnotify(XEvent *e)
297 {
298 XMappingEvent *ev = &e->xmapping;
300 XRefreshKeyboardMapping(ev);
301 if(ev->request == MappingKeyboard)
302 grabkeys();
303 }
305 static void
306 maprequest(XEvent *e)
307 {
308 static XWindowAttributes wa;
309 XMapRequestEvent *ev = &e->xmaprequest;
311 if(!XGetWindowAttributes(dpy, ev->window, &wa))
312 return;
314 if(wa.override_redirect) {
315 XSelectInput(dpy, ev->window,
316 (StructureNotifyMask | PropertyChangeMask));
317 return;
318 }
320 if(!getclient(ev->window))
321 manage(ev->window, &wa);
322 }
324 static void
325 propertynotify(XEvent *e)
326 {
327 Client *c;
328 Window trans;
329 XPropertyEvent *ev = &e->xproperty;
331 if(ev->state == PropertyDelete)
332 return; /* ignore */
334 if((c = getclient(ev->window))) {
335 if(ev->atom == wmatom[WMProtocols]) {
336 c->proto = getproto(c->win);
337 return;
338 }
339 switch (ev->atom) {
340 default: break;
341 case XA_WM_TRANSIENT_FOR:
342 XGetTransientForHint(dpy, c->win, &trans);
343 if(!c->isfloat && (c->isfloat = (trans != 0)))
344 arrange(NULL);
345 break;
346 case XA_WM_NORMAL_HINTS:
347 setsize(c);
348 break;
349 }
350 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
351 settitle(c);
352 drawtitle(c);
353 }
354 }
355 }
357 static void
358 unmapnotify(XEvent *e)
359 {
360 Client *c;
361 XUnmapEvent *ev = &e->xunmap;
363 if((c = getclient(ev->window)))
364 unmanage(c);
365 }
367 /* extern */
369 void (*handler[LASTEvent]) (XEvent *) = {
370 [ButtonPress] = buttonpress,
371 [ConfigureRequest] = configurerequest,
372 [DestroyNotify] = destroynotify,
373 [EnterNotify] = enternotify,
374 [LeaveNotify] = leavenotify,
375 [Expose] = expose,
376 [KeyPress] = keypress,
377 [MappingNotify] = mappingnotify,
378 [MapRequest] = maprequest,
379 [PropertyNotify] = propertynotify,
380 [UnmapNotify] = unmapnotify
381 };
383 void
384 grabkeys()
385 {
386 static unsigned int len = sizeof(key) / sizeof(key[0]);
387 unsigned int i;
388 KeyCode code;
390 XUngrabKey(dpy, AnyKey, AnyModifier, root);
391 for(i = 0; i < len; i++) {
392 code = XKeysymToKeycode(dpy, key[i].keysym);
393 XGrabKey(dpy, code, key[i].mod, root, True,
394 GrabModeAsync, GrabModeAsync);
395 XGrabKey(dpy, code, key[i].mod | LockMask, root, True,
396 GrabModeAsync, GrabModeAsync);
397 XGrabKey(dpy, code, key[i].mod | numlockmask, root, True,
398 GrabModeAsync, GrabModeAsync);
399 XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True,
400 GrabModeAsync, GrabModeAsync);
401 }
402 }
404 void
405 procevent()
406 {
407 XEvent ev;
409 while(XPending(dpy)) {
410 XNextEvent(dpy, &ev);
411 if(handler[ev.type])
412 (handler[ev.type])(&ev); /* call handler */
413 }
414 }