event.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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>
  9. #define ButtonMask (ButtonPressMask | ButtonReleaseMask)
  10. #define MouseMask (ButtonMask | PointerMotionMask)
  11. /* CUSTOMIZE */
  12. const char *term[] = { "xterm", NULL };
  13. Key key[] = {
  14. /* modifier key function arguments */
  15. { ControlMask, XK_0, appendtag, { .i = Tscratch } },
  16. { ControlMask, XK_1, appendtag, { .i = Tdev } },
  17. { ControlMask, XK_2, appendtag, { .i = Twww } },
  18. { ControlMask, XK_3, appendtag, { .i = Twork } },
  19. { Mod1Mask, XK_0, view, { .i = Tscratch } },
  20. { Mod1Mask, XK_1, view, { .i = Tdev } },
  21. { Mod1Mask, XK_2, view, { .i = Twww } },
  22. { Mod1Mask, XK_3, view, { .i = Twork } },
  23. { Mod1Mask, XK_j, focusnext, { 0 } },
  24. { Mod1Mask, XK_k, focusprev, { 0 } },
  25. { Mod1Mask, XK_m, maximize, { 0 } },
  26. { Mod1Mask, XK_space, dotile, { 0 } },
  27. { Mod1Mask, XK_Return, zoom, { 0 } },
  28. { ControlMask|ShiftMask,XK_0, heretag, { .i = Tscratch } },
  29. { ControlMask|ShiftMask,XK_1, heretag, { .i = Tdev } },
  30. { ControlMask|ShiftMask,XK_2, heretag, { .i = Twww } },
  31. { ControlMask|ShiftMask,XK_3, heretag, { .i = Twork } },
  32. { Mod1Mask|ShiftMask, XK_0, replacetag, { .i = Tscratch } },
  33. { Mod1Mask|ShiftMask, XK_1, replacetag, { .i = Tdev } },
  34. { Mod1Mask|ShiftMask, XK_2, replacetag, { .i = Twww } },
  35. { Mod1Mask|ShiftMask, XK_3, replacetag, { .i = Twork } },
  36. { Mod1Mask|ShiftMask, XK_c, killclient, { 0 } },
  37. { Mod1Mask|ShiftMask, XK_q, quit, { 0 } },
  38. { Mod1Mask|ShiftMask, XK_space, dofloat, { 0 } },
  39. { Mod1Mask|ShiftMask, XK_Return, spawn, { .argv = term } },
  40. };
  41. /* static */
  42. static void
  43. movemouse(Client *c)
  44. {
  45. XEvent ev;
  46. int x1, y1, ocx, ocy, di;
  47. unsigned int dui;
  48. Window dummy;
  49. ocx = *c->x;
  50. ocy = *c->y;
  51. if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync,
  52. None, cursor[CurMove], CurrentTime) != GrabSuccess)
  53. return;
  54. XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
  55. for(;;) {
  56. XMaskEvent(dpy, MouseMask | ExposureMask, &ev);
  57. switch (ev.type) {
  58. default: break;
  59. case Expose:
  60. handler[Expose](&ev);
  61. break;
  62. case MotionNotify:
  63. XSync(dpy, False);
  64. *c->x = ocx + (ev.xmotion.x - x1);
  65. *c->y = ocy + (ev.xmotion.y - y1);
  66. resize(c, False, TopLeft);
  67. break;
  68. case ButtonRelease:
  69. XUngrabPointer(dpy, CurrentTime);
  70. return;
  71. }
  72. }
  73. }
  74. static void
  75. resizemouse(Client *c)
  76. {
  77. XEvent ev;
  78. int ocx, ocy;
  79. Corner sticky;
  80. ocx = *c->x;
  81. ocy = *c->y;
  82. if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync,
  83. None, cursor[CurResize], CurrentTime) != GrabSuccess)
  84. return;
  85. XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, *c->w, *c->h);
  86. for(;;) {
  87. XMaskEvent(dpy, MouseMask | ExposureMask, &ev);
  88. switch(ev.type) {
  89. default: break;
  90. case Expose:
  91. handler[Expose](&ev);
  92. break;
  93. case MotionNotify:
  94. XSync(dpy, False);
  95. *c->w = abs(ocx - ev.xmotion.x);
  96. *c->h = abs(ocy - ev.xmotion.y);
  97. *c->x = (ocx <= ev.xmotion.x) ? ocx : ocx - *c->w;
  98. *c->y = (ocy <= ev.xmotion.y) ? ocy : ocy - *c->h;
  99. if(ocx <= ev.xmotion.x)
  100. sticky = (ocy <= ev.xmotion.y) ? TopLeft : BotLeft;
  101. else
  102. sticky = (ocy <= ev.xmotion.y) ? TopRight : BotRight;
  103. resize(c, True, sticky);
  104. break;
  105. case ButtonRelease:
  106. XUngrabPointer(dpy, CurrentTime);
  107. return;
  108. }
  109. }
  110. }
  111. static void
  112. buttonpress(XEvent *e)
  113. {
  114. int x;
  115. Arg a;
  116. XButtonPressedEvent *ev = &e->xbutton;
  117. Client *c;
  118. if(barwin == ev->window) {
  119. switch(ev->button) {
  120. default:
  121. x = 0;
  122. for(a.i = 0; a.i < TLast; a.i++) {
  123. x += textw(tags[a.i]);
  124. if(ev->x < x) {
  125. view(&a);
  126. break;
  127. }
  128. }
  129. break;
  130. case Button4:
  131. a.i = (tsel + 1 < TLast) ? tsel + 1 : 0;
  132. view(&a);
  133. break;
  134. case Button5:
  135. a.i = (tsel - 1 >= 0) ? tsel - 1 : TLast - 1;
  136. view(&a);
  137. break;
  138. }
  139. }
  140. else if((c = getclient(ev->window))) {
  141. switch(ev->button) {
  142. default:
  143. break;
  144. case Button1:
  145. if(arrange == dotile && !c->isfloat) {
  146. if((ev->state & ControlMask) && (ev->button == Button1))
  147. zoom(NULL);
  148. }
  149. else {
  150. higher(c);
  151. movemouse(c);
  152. }
  153. break;
  154. case Button2:
  155. lower(c);
  156. break;
  157. case Button3:
  158. if(arrange == dofloat || c->isfloat) {
  159. higher(c);
  160. resizemouse(c);
  161. }
  162. break;
  163. }
  164. }
  165. }
  166. static void
  167. configurerequest(XEvent *e)
  168. {
  169. XConfigureRequestEvent *ev = &e->xconfigurerequest;
  170. XWindowChanges wc;
  171. Client *c;
  172. ev->value_mask &= ~CWSibling;
  173. if((c = getclient(ev->window))) {
  174. gravitate(c, True);
  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 = 1;
  185. gravitate(c, False);
  186. resize(c, True, TopLeft);
  187. }
  188. wc.x = ev->x;
  189. wc.y = ev->y;
  190. wc.width = ev->width;
  191. wc.height = ev->height;
  192. wc.border_width = 1;
  193. wc.sibling = None;
  194. wc.stack_mode = Above;
  195. ev->value_mask &= ~CWStackMode;
  196. ev->value_mask |= CWBorderWidth;
  197. XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
  198. XSync(dpy, False);
  199. }
  200. static void
  201. destroynotify(XEvent *e)
  202. {
  203. Client *c;
  204. XDestroyWindowEvent *ev = &e->xdestroywindow;
  205. if((c = getclient(ev->window)))
  206. unmanage(c);
  207. }
  208. static void
  209. enternotify(XEvent *e)
  210. {
  211. XCrossingEvent *ev = &e->xcrossing;
  212. Client *c;
  213. if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
  214. return;
  215. if((c = getclient(ev->window)))
  216. focus(c);
  217. else if(ev->window == root)
  218. issel = True;
  219. }
  220. static void
  221. expose(XEvent *e)
  222. {
  223. XExposeEvent *ev = &e->xexpose;
  224. Client *c;
  225. if(ev->count == 0) {
  226. if(barwin == ev->window)
  227. drawstatus();
  228. else if((c = getctitle(ev->window)))
  229. drawtitle(c);
  230. }
  231. }
  232. static void
  233. keypress(XEvent *e)
  234. {
  235. XKeyEvent *ev = &e->xkey;
  236. static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0;
  237. unsigned int i;
  238. KeySym keysym;
  239. keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
  240. for(i = 0; i < len; i++)
  241. if((keysym == key[i].keysym) && (key[i].mod == ev->state)) {
  242. if(key[i].func)
  243. key[i].func(&key[i].arg);
  244. return;
  245. }
  246. }
  247. static void
  248. leavenotify(XEvent *e)
  249. {
  250. XCrossingEvent *ev = &e->xcrossing;
  251. if((ev->window == root) && !ev->same_screen)
  252. issel = True;
  253. }
  254. static void
  255. maprequest(XEvent *e)
  256. {
  257. XMapRequestEvent *ev = &e->xmaprequest;
  258. static XWindowAttributes wa;
  259. if(!XGetWindowAttributes(dpy, ev->window, &wa))
  260. return;
  261. if(wa.override_redirect) {
  262. XSelectInput(dpy, ev->window,
  263. (StructureNotifyMask | PropertyChangeMask));
  264. return;
  265. }
  266. if(!getclient(ev->window))
  267. manage(ev->window, &wa);
  268. }
  269. static void
  270. propertynotify(XEvent *e)
  271. {
  272. XPropertyEvent *ev = &e->xproperty;
  273. Window trans;
  274. Client *c;
  275. if(ev->state == PropertyDelete)
  276. return; /* ignore */
  277. if((c = getclient(ev->window))) {
  278. if(ev->atom == wmatom[WMProtocols]) {
  279. c->proto = getproto(c->win);
  280. return;
  281. }
  282. switch (ev->atom) {
  283. default: break;
  284. case XA_WM_TRANSIENT_FOR:
  285. XGetTransientForHint(dpy, c->win, &trans);
  286. if(!c->isfloat && (c->isfloat = (trans != 0)))
  287. arrange(NULL);
  288. break;
  289. case XA_WM_NORMAL_HINTS:
  290. setsize(c);
  291. break;
  292. }
  293. if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  294. settitle(c);
  295. drawtitle(c);
  296. }
  297. }
  298. }
  299. static void
  300. unmapnotify(XEvent *e)
  301. {
  302. Client *c;
  303. XUnmapEvent *ev = &e->xunmap;
  304. if((c = getclient(ev->window)))
  305. unmanage(c);
  306. }
  307. /* extern */
  308. void (*handler[LASTEvent]) (XEvent *) = {
  309. [ButtonPress] = buttonpress,
  310. [ConfigureRequest] = configurerequest,
  311. [DestroyNotify] = destroynotify,
  312. [EnterNotify] = enternotify,
  313. [LeaveNotify] = leavenotify,
  314. [Expose] = expose,
  315. [KeyPress] = keypress,
  316. [MapRequest] = maprequest,
  317. [PropertyNotify] = propertynotify,
  318. [UnmapNotify] = unmapnotify
  319. };
  320. void
  321. grabkeys()
  322. {
  323. static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0;
  324. unsigned int i;
  325. KeyCode code;
  326. for(i = 0; i < len; i++) {
  327. code = XKeysymToKeycode(dpy, key[i].keysym);
  328. XUngrabKey(dpy, code, key[i].mod, root);
  329. XGrabKey(dpy, code, key[i].mod, root, True,
  330. GrabModeAsync, GrabModeAsync);
  331. }
  332. }