Xinqi Bao's Git

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