You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

375 lines
8.3 KiB

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