Xinqi Bao's Git

cfe2d2aec5fda89529f12fd827884f150ea01a46
[dwm.git] / event.c
1 /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
2 * See LICENSE file for license details.
3 */
4 #include "dwm.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 | ExposureMask | SubstructureRedirectMask, &ev);
39 switch (ev.type) {
40 case ButtonRelease:
41 resize(c, True);
42 XUngrabPointer(dpy, CurrentTime);
43 return;
44 case ConfigureRequest:
45 case Expose:
46 case MapRequest:
47 handler[ev.type](&ev);
48 break;
49 case MotionNotify:
50 XSync(dpy, False);
51 c->x = ocx + (ev.xmotion.x - x1);
52 c->y = ocy + (ev.xmotion.y - y1);
53 if(abs(wax + c->x) < SNAP)
54 c->x = wax;
55 else if(abs((wax + waw) - (c->x + c->w + 2 * c->border)) < SNAP)
56 c->x = wax + waw - c->w - 2 * c->border;
57 if(abs(way - c->y) < SNAP)
58 c->y = way;
59 else if(abs((way + wah) - (c->y + c->h + 2 * c->border)) < SNAP)
60 c->y = way + wah - c->h - 2 * c->border;
61 resize(c, False);
62 break;
63 }
64 }
65 }
66
67 static void
68 resizemouse(Client *c) {
69 int ocx, ocy;
70 int nw, nh;
71 XEvent ev;
72
73 ocx = c->x;
74 ocy = c->y;
75 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
76 None, cursor[CurResize], CurrentTime) != GrabSuccess)
77 return;
78 c->ismax = False;
79 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
80 for(;;) {
81 XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
82 switch(ev.type) {
83 case ButtonRelease:
84 resize(c, True);
85 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
86 c->w + c->border - 1, c->h + c->border - 1);
87 XUngrabPointer(dpy, CurrentTime);
88 return;
89 case ConfigureRequest:
90 case Expose:
91 case MapRequest:
92 handler[ev.type](&ev);
93 break;
94 case MotionNotify:
95 XSync(dpy, False);
96 nw = ev.xmotion.x - ocx - 2 * c->border + 1;
97 c->w = nw > 0 ? nw : 1;
98 nh = ev.xmotion.y - ocy - 2 * c->border + 1;
99 c->h = nh > 0 ? nh : 1;
100 resize(c, True);
101 break;
102 }
103 }
104 }
105
106 static void
107 buttonpress(XEvent *e) {
108 int x;
109 Arg a;
110 Client *c;
111 XButtonPressedEvent *ev = &e->xbutton;
112
113 if(barwin == ev->window) {
114 x = 0;
115 for(a.i = 0; a.i < ntags; a.i++) {
116 x += textw(tags[a.i]);
117 if(ev->x < x) {
118 if(ev->button == Button1) {
119 if(ev->state & MODKEY)
120 tag(&a);
121 else
122 view(&a);
123 }
124 else if(ev->button == Button3) {
125 if(ev->state & MODKEY)
126 toggletag(&a);
127 else
128 toggleview(&a);
129 }
130 return;
131 }
132 }
133 if(ev->x < x + bmw)
134 switch(ev->button) {
135 case Button1:
136 togglemode(NULL);
137 break;
138 case Button4:
139 a.i = 1;
140 incnmaster(&a);
141 break;
142 case Button5:
143 a.i = -1;
144 incnmaster(&a);
145 break;
146 }
147 }
148 else if((c = getclient(ev->window))) {
149 focus(c);
150 if(CLEANMASK(ev->state) != MODKEY)
151 return;
152 if(ev->button == Button1 && (arrange == dofloat || c->isfloat)) {
153 restack();
154 movemouse(c);
155 }
156 else if(ev->button == Button2)
157 zoom(NULL);
158 else if(ev->button == Button3 && (arrange == dofloat || c->isfloat) &&
159 !c->isfixed) {
160 restack();
161 resizemouse(c);
162 }
163 }
164 }
165
166 static void
167 configurerequest(XEvent *e) {
168 unsigned long newmask;
169 Client *c;
170 XConfigureRequestEvent *ev = &e->xconfigurerequest;
171 XWindowChanges wc;
172
173 if((c = getclient(ev->window))) {
174 c->ismax = False;
175 if(ev->value_mask & CWX)
176 c->x = ev->x;
177 if(ev->value_mask & CWY)
178 c->y = ev->y;
179 if(ev->value_mask & CWWidth)
180 c->w = ev->width;
181 if(ev->value_mask & CWHeight)
182 c->h = ev->height;
183 if(ev->value_mask & CWBorderWidth)
184 c->border = ev->border_width;
185 wc.x = c->x;
186 wc.y = c->y;
187 wc.width = c->w;
188 wc.height = c->h;
189 newmask = ev->value_mask & (~(CWSibling | CWStackMode | CWBorderWidth));
190 if(newmask)
191 XConfigureWindow(dpy, c->win, newmask, &wc);
192 else
193 configure(c);
194 XSync(dpy, False);
195 if(c->isfloat) {
196 resize(c, False);
197 if(!isvisible(c))
198 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
199 }
200 else
201 arrange();
202 }
203 else {
204 wc.x = ev->x;
205 wc.y = ev->y;
206 wc.width = ev->width;
207 wc.height = ev->height;
208 wc.border_width = ev->border_width;
209 wc.sibling = ev->above;
210 wc.stack_mode = ev->detail;
211 XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
212 XSync(dpy, False);
213 }
214 }
215
216 static void
217 destroynotify(XEvent *e) {
218 Client *c;
219 XDestroyWindowEvent *ev = &e->xdestroywindow;
220
221 if((c = getclient(ev->window)))
222 unmanage(c);
223 }
224
225 static void
226 enternotify(XEvent *e) {
227 Client *c;
228 XCrossingEvent *ev = &e->xcrossing;
229
230 if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
231 return;
232 if((c = getclient(ev->window)) && isvisible(c))
233 focus(c);
234 else if(ev->window == root) {
235 selscreen = True;
236 for(c = stack; c && !isvisible(c); c = c->snext);
237 focus(c);
238 }
239 }
240
241 static void
242 expose(XEvent *e) {
243 XExposeEvent *ev = &e->xexpose;
244
245 if(ev->count == 0) {
246 if(barwin == ev->window)
247 drawstatus();
248 }
249 }
250
251 static void
252 keypress(XEvent *e) {
253 static unsigned int len = sizeof key / sizeof key[0];
254 unsigned int i;
255 KeySym keysym;
256 XKeyEvent *ev = &e->xkey;
257
258 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
259 for(i = 0; i < len; i++) {
260 if(keysym == key[i].keysym
261 && CLEANMASK(key[i].mod) == CLEANMASK(ev->state))
262 {
263 if(key[i].func)
264 key[i].func(&key[i].arg);
265 }
266 }
267 }
268
269 static void
270 leavenotify(XEvent *e) {
271 XCrossingEvent *ev = &e->xcrossing;
272
273 if((ev->window == root) && !ev->same_screen) {
274 selscreen = False;
275 focus(NULL);
276 }
277 }
278
279 static void
280 mappingnotify(XEvent *e) {
281 XMappingEvent *ev = &e->xmapping;
282
283 XRefreshKeyboardMapping(ev);
284 if(ev->request == MappingKeyboard)
285 grabkeys();
286 }
287
288 static void
289 maprequest(XEvent *e) {
290 static XWindowAttributes wa;
291 XMapRequestEvent *ev = &e->xmaprequest;
292
293 if(!XGetWindowAttributes(dpy, ev->window, &wa))
294 return;
295 if(wa.override_redirect) {
296 XSelectInput(dpy, ev->window,
297 (StructureNotifyMask | PropertyChangeMask));
298 return;
299 }
300 if(!getclient(ev->window))
301 manage(ev->window, &wa);
302 }
303
304 static void
305 propertynotify(XEvent *e) {
306 Client *c;
307 Window trans;
308 XPropertyEvent *ev = &e->xproperty;
309
310 if(ev->state == PropertyDelete)
311 return; /* ignore */
312 if((c = getclient(ev->window))) {
313 switch (ev->atom) {
314 default: break;
315 case XA_WM_TRANSIENT_FOR:
316 XGetTransientForHint(dpy, c->win, &trans);
317 if(!c->isfloat && (c->isfloat = (trans != 0)))
318 arrange();
319 break;
320 case XA_WM_NORMAL_HINTS:
321 updatesizehints(c);
322 break;
323 }
324 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
325 updatetitle(c);
326 if(c == sel)
327 drawstatus();
328 }
329 }
330 }
331
332 static void
333 unmapnotify(XEvent *e) {
334 Client *c;
335 XUnmapEvent *ev = &e->xunmap;
336
337 if((c = getclient(ev->window)))
338 unmanage(c);
339 }
340
341 /* extern */
342
343 void (*handler[LASTEvent]) (XEvent *) = {
344 [ButtonPress] = buttonpress,
345 [ConfigureRequest] = configurerequest,
346 [DestroyNotify] = destroynotify,
347 [EnterNotify] = enternotify,
348 [LeaveNotify] = leavenotify,
349 [Expose] = expose,
350 [KeyPress] = keypress,
351 [MappingNotify] = mappingnotify,
352 [MapRequest] = maprequest,
353 [PropertyNotify] = propertynotify,
354 [UnmapNotify] = unmapnotify
355 };
356
357 void
358 grabkeys(void) {
359 static unsigned int len = sizeof key / sizeof key[0];
360 unsigned int i;
361 KeyCode code;
362
363 XUngrabKey(dpy, AnyKey, AnyModifier, root);
364 for(i = 0; i < len; i++) {
365 code = XKeysymToKeycode(dpy, key[i].keysym);
366 XGrabKey(dpy, code, key[i].mod, root, True,
367 GrabModeAsync, GrabModeAsync);
368 XGrabKey(dpy, code, key[i].mod | LockMask, root, True,
369 GrabModeAsync, GrabModeAsync);
370 XGrabKey(dpy, code, key[i].mod | numlockmask, root, True,
371 GrabModeAsync, GrabModeAsync);
372 XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True,
373 GrabModeAsync, GrabModeAsync);
374 }
375 }
376
377 void
378 procevent(void) {
379 XEvent ev;
380
381 while(XPending(dpy)) {
382 XNextEvent(dpy, &ev);
383 if(handler[ev.type])
384 (handler[ev.type])(&ev); /* call handler */
385 }
386 }