event.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. /*
  2. * event.c
  3. * Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are
  8. * met:
  9. *
  10. * * Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above
  13. * copyright notice, this list of conditions and the following disclaimer
  14. * in the documentation and/or other materials provided with the
  15. * distribution.
  16. * * Neither the name of the nor the names of its
  17. * contributors may be used to endorse or promote products derived from
  18. * this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #include "wmfs.h"
  33. /** ButtonPress handle event
  34. * \param ev XButtonEvent pointer
  35. */
  36. void
  37. buttonpress(XButtonEvent *ev)
  38. {
  39. Client *c;
  40. int i, j, n;
  41. screen_get_sel();
  42. /* If the mouse is on a not selected client and you click on it. */
  43. if(((c = client_gb_win(ev->window)) || (c = client_gb_titlebar(ev->window))) && c != sel
  44. && (ev->button == Button1 || ev->button == Button2 || ev->button == Button3))
  45. {
  46. client_focus(c);
  47. client_raise(c);
  48. }
  49. /* Titlebar */
  50. if((c = client_gb_titlebar(ev->window)) && c == sel)
  51. for(i = 0; i < conf.titlebar.nmouse; ++i)
  52. if(ev->button == conf.titlebar.mouse[i].button)
  53. if(conf.titlebar.mouse[i].func)
  54. conf.titlebar.mouse[i].func(conf.titlebar.mouse[i].cmd);
  55. /* Titlebar buttons */
  56. if((c = client_gb_button(ev->window, &n)))
  57. for(i = 0; i < conf.titlebar.button[n].nmouse; ++i)
  58. if(ev->button == conf.titlebar.button[n].mouse[i].button)
  59. if(conf.titlebar.button[n].mouse[i].func)
  60. conf.titlebar.button[n].mouse[i].func(conf.titlebar.button[n].mouse[i].cmd);
  61. /* Frame Resize Area */
  62. if((c = client_gb_resize(ev->window)))
  63. mouse_resize(c);
  64. /* Client */
  65. if((c = client_gb_win(ev->window)) && c == sel)
  66. for(i = 0; i < conf.client.nmouse; ++i)
  67. if(ev->button == conf.client.mouse[i].button)
  68. if(conf.client.mouse[i].func)
  69. conf.client.mouse[i].func(conf.client.mouse[i].cmd);
  70. /* Root */
  71. if(ev->window == ROOT)
  72. for(i = 0; i < conf.root.nmouse; ++i)
  73. if(conf.root.mouse[i].tag == seltag[conf.root.mouse[i].screen]
  74. || conf.root.mouse[i].tag < 0)
  75. if(ev->button == conf.root.mouse[i].button)
  76. if(conf.root.mouse[i].func)
  77. conf.root.mouse[i].func(conf.root.mouse[i].cmd);
  78. /* Infobars */
  79. for(i = 0; i < screen_count(); ++i)
  80. if(ev->window == infobar[i].bar->win)
  81. for(j = 0; j < conf.bars.nmouse; ++j)
  82. if(conf.bars.mouse[j].screen == i
  83. || conf.bars.mouse[j].screen < 0)
  84. if(conf.bars.mouse[j].tag == seltag[i]
  85. || conf.bars.mouse[j].tag < 0)
  86. if(ev->button == conf.bars.mouse[j].button)
  87. if(conf.bars.mouse[j].func)
  88. conf.bars.mouse[j].func(conf.bars.mouse[j].cmd);
  89. /* Tags */
  90. for(i = 1; i < conf.ntag[selscreen] + 1; ++i)
  91. if(ev->window == infobar[selscreen].tags[i]->win)
  92. switch(ev->button)
  93. {
  94. case Button1: tag_set(i); break;
  95. case Button3: tag_transfert(sel, i); break;
  96. case Button4: tag_set(seltag[selscreen] + 1); break;
  97. case Button5: tag_set(seltag[selscreen] - 1); break;
  98. }
  99. /* Layout button */
  100. if(ev->window == infobar[selscreen].layout_button->win && conf.nlayout > 1)
  101. {
  102. if(conf.layout_system && (ev->button == Button1 || ev->button == Button3)) /* True -> menu */
  103. {
  104. menulayout.y = spgeo[selscreen].y + infobar[selscreen].layout_button->geo.y + INFOBARH;
  105. menulayout.x = infobar[selscreen].layout_button->geo.x + (sgeo[selscreen].x - BORDH);
  106. if(infobar[selscreen].geo.y != spgeo[selscreen].y)
  107. menulayout.y = infobar[selscreen].geo.y - (INFOBARH * menulayout.nitem) - SHADH;
  108. uicb_menu("menulayout");
  109. }
  110. else
  111. {
  112. switch(ev->button)
  113. {
  114. case Button1: case Button4: layoutswitch(True); break;
  115. case Button3: case Button5: layoutswitch(False); break;
  116. }
  117. }
  118. }
  119. return;
  120. }
  121. /* ClientMessage handle event
  122. *\param ev XClientMessageEvent pointer
  123. */
  124. void
  125. clientmessageevent(XClientMessageEvent *ev)
  126. {
  127. Client *c;
  128. int i, mess_t = 0;
  129. Atom rt;
  130. int rf;
  131. ulong ir, il;
  132. uchar *ret = NULL;
  133. uchar *ret_cmd = NULL;
  134. void (*func)(uicb_t);
  135. if(ev->format != 32)
  136. return;
  137. for(i = 0; i < net_last + screen_count(); ++i)
  138. if(net_atom[i] == ev->message_type)
  139. mess_t = i;
  140. if(ev->window == ROOT)
  141. {
  142. /* Manage _NET_CURRENT_DESKTOP */
  143. if(mess_t == net_current_desktop
  144. && ev->data.l[0] >= 0
  145. && ev->data.l[0] < conf.ntag[selscreen])
  146. tag_set((int)(ev->data.l[0] + 1));
  147. /* Manage _WMFS_SET_SCREEN */
  148. if(mess_t == wmfs_set_screen
  149. && ev->data.l[0] >= 0
  150. && ev->data.l[0] <= screen_count())
  151. screen_set_sel((int)(ev->data.l[0]));
  152. /* Manage _NET_ACTIVE_WINDOW */
  153. else if(mess_t == net_active_window)
  154. if((c = client_gb_win(ev->window)))
  155. client_focus(c);
  156. }
  157. /* Manage _NET_WM_STATE */
  158. if(mess_t == net_wm_state)
  159. if((c = client_gb_win(ev->window)))
  160. ewmh_manage_net_wm_state(ev->data.l, c);
  161. /* Manage _NET_CLOSE_WINDOW */
  162. if(mess_t == net_close_window)
  163. if((c = client_gb_win(ev->window)))
  164. client_kill(c);
  165. /* Manage _NET_WM_DESKTOP */
  166. if(mess_t == net_wm_desktop)
  167. if((c = client_gb_win(ev->window)))
  168. tag_transfert(c, ev->data.l[0]);
  169. /* Manage _WMFS_STATUSTEXT_x */
  170. if(mess_t >= wmfs_statustext && ev->data.l[4] == True)
  171. {
  172. if(XGetWindowProperty(dpy, ROOT, net_atom[mess_t], 0, 4096,
  173. False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret) == Success)
  174. {
  175. infobar_draw_statustext(mess_t - wmfs_statustext, (char*)ret);
  176. XFree(ret);
  177. }
  178. }
  179. /* Manage _WMFS_FUNCTION && _WMFS_CMD */
  180. if((mess_t == wmfs_function && ev->data.l[4] == True)
  181. || (mess_t == wmfs_cmd && ev->data.l[4] == True))
  182. {
  183. XGetWindowProperty(dpy, ROOT, net_atom[wmfs_function], 0, 4096,
  184. False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret);
  185. XGetWindowProperty(dpy, ROOT, net_atom[wmfs_cmd], 0, 4096,
  186. False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret_cmd);
  187. if((func = name_to_func((char*)ret, func_list)))
  188. func((uicb_t)ret_cmd);
  189. XFree(ret_cmd);
  190. XFree(ret);
  191. }
  192. /* Manage _WMFS_UPDATE_HINTS */
  193. if(mess_t == wmfs_update_hints)
  194. {
  195. ewmh_get_number_of_desktop();
  196. ewmh_update_current_tag_prop();
  197. ewmh_get_client_list();
  198. ewmh_get_desktop_names();
  199. ewmh_set_desktop_geometry();
  200. ewmh_set_workarea();
  201. screen_count();
  202. screen_get_sel();
  203. }
  204. if(mess_t == wmfs_update_status
  205. && estatus)
  206. spawn(status_path);
  207. return;
  208. }
  209. /** ConfigureRequest & ConfigureNotify handle events
  210. * \param ev XEvent pointer
  211. */
  212. void
  213. configureevent(XConfigureRequestEvent *ev)
  214. {
  215. XWindowChanges wc;
  216. Client *c;
  217. /* Check part */
  218. if((c = client_gb_win(ev->window))
  219. || (c = client_gb_win(ev->window)))
  220. {
  221. CHECK(!(c->flags & TileFlag));
  222. CHECK(!(c->flags & LMaxFlag));
  223. CHECK(!(c->flags & MaxFlag));
  224. CHECK(!(c->flags & FSSFlag));
  225. }
  226. if((c = client_gb_win(ev->window)))
  227. {
  228. if(ev->value_mask & CWX)
  229. c->geo.x = ev->x + BORDH;
  230. if(ev->value_mask & CWY)
  231. c->geo.y = ev->y + TBARH;
  232. if(ev->value_mask & CWWidth)
  233. c->geo.width = ev->width;
  234. if(ev->value_mask & CWHeight)
  235. c->geo.height = ev->height;
  236. if(c->flags & FreeFlag)
  237. client_moveresize(c, c->geo, False);
  238. }
  239. else
  240. {
  241. wc.x = ev->x;
  242. wc.y = ev->y;
  243. wc.width = ev->width;
  244. wc.height = ev->height;
  245. wc.border_width = ev->border_width;
  246. wc.sibling = ev->above;
  247. wc.stack_mode = ev->detail;
  248. XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
  249. }
  250. return;
  251. }
  252. /** DestroyNotify handle event
  253. * \param ev XDestroyWindowEvent pointer
  254. */
  255. void
  256. destroynotify(XDestroyWindowEvent *ev)
  257. {
  258. Client *c;
  259. if((c = client_gb_win(ev->window)))
  260. {
  261. client_unmanage(c);
  262. XSetErrorHandler(errorhandler);
  263. }
  264. return;
  265. }
  266. /** EnterNotify handle event
  267. * \param ev XCrossingEvent pointer
  268. */
  269. void
  270. enternotify(XCrossingEvent *ev)
  271. {
  272. Client *c;
  273. int n;
  274. if((ev->mode != NotifyNormal
  275. || ev->detail == NotifyInferior)
  276. && ev->window != ROOT)
  277. return;
  278. if(conf.focus_fmouse)
  279. {
  280. if((c = client_gb_win(ev->window))
  281. || (c = client_gb_frame(ev->window))
  282. || (c = client_gb_titlebar(ev->window))
  283. || (c = client_gb_button(ev->window, &n)))
  284. client_focus(c);
  285. else
  286. client_focus(NULL);
  287. }
  288. return;
  289. }
  290. /** ExposeEvent handle event
  291. * \param ev XExposeEvent pointer
  292. */
  293. void
  294. expose(XExposeEvent *ev)
  295. {
  296. Client *c;
  297. int i, sc;
  298. /* InfoBar member */
  299. for(sc = 0; sc < screen_count(); ++sc)
  300. {
  301. if(ev->window == infobar[sc].bar->win)
  302. barwin_refresh(infobar[sc].bar);
  303. if(ev->window == infobar[sc].layout_button->win)
  304. barwin_refresh(infobar[sc].layout_button);
  305. for(i = 1; i < conf.ntag[sc] + 1; ++i)
  306. if(ev->window == infobar[sc].tags[i]->win)
  307. barwin_refresh(infobar[sc].tags[i]);
  308. }
  309. /* Client frame */
  310. if((c = client_gb_titlebar(ev->window)))
  311. frame_update(c);
  312. return;
  313. }
  314. /** FocusChange handle event
  315. * \param ev XFocusChangeEvent pointer
  316. * \return
  317. */
  318. void
  319. focusin(XFocusChangeEvent *ev)
  320. {
  321. if(sel && ev->window != sel->win)
  322. client_focus(sel);
  323. return;
  324. }
  325. /** Key grabbing function
  326. */
  327. void
  328. grabkeys(void)
  329. {
  330. uint i;
  331. KeyCode code;
  332. XUngrabKey(dpy, AnyKey, AnyModifier, ROOT);
  333. for(i = 0; i < conf.nkeybind; ++i)
  334. {
  335. code = XKeysymToKeycode(dpy, keys[i].keysym);
  336. XGrabKey(dpy, code, keys[i].mod, ROOT, True, GrabModeAsync, GrabModeAsync);
  337. XGrabKey(dpy, code, keys[i].mod | LockMask, ROOT, True, GrabModeAsync, GrabModeAsync);
  338. XGrabKey(dpy, code, keys[i].mod | numlockmask, ROOT, True, GrabModeAsync, GrabModeAsync);
  339. XGrabKey(dpy, code, keys[i].mod | LockMask | numlockmask, ROOT, True, GrabModeAsync, GrabModeAsync);
  340. }
  341. return;
  342. }
  343. /** KeyPress handle event
  344. * \param ev XKeyPressedEvent pointer
  345. */
  346. void
  347. keypress(XKeyPressedEvent *ev)
  348. {
  349. uint i;
  350. KeySym keysym;
  351. keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
  352. for(i = 0; i < conf.nkeybind; ++i)
  353. if(keysym == keys[i].keysym
  354. && (keys[i].mod & ~(numlockmask | LockMask))
  355. == (ev->state & ~(numlockmask | LockMask))
  356. && keys[i].func)
  357. keys[i].func(keys[i].cmd);
  358. return;
  359. }
  360. /** MapNotify handle event
  361. * \param ev XMappingEvent pointer
  362. */
  363. void
  364. mappingnotify(XMappingEvent *ev)
  365. {
  366. if(ev->request == MappingKeyboard)
  367. grabkeys();
  368. return;
  369. }
  370. /** MapRequest handle event
  371. * \param ev XMapRequestEvent pointer
  372. */
  373. void
  374. maprequest(XMapRequestEvent *ev)
  375. {
  376. XWindowAttributes at;
  377. Client *c;
  378. CHECK(XGetWindowAttributes(dpy, ev->window, &at));
  379. CHECK(!at.override_redirect);
  380. if(!(c = client_gb_win(ev->window)))
  381. client_manage(ev->window, &at, True);
  382. return;
  383. }
  384. /** PropertyNotify handle event
  385. * \param ev XPropertyEvent pointer
  386. */
  387. void
  388. propertynotify(XPropertyEvent *ev)
  389. {
  390. Client *c;
  391. Window trans;
  392. if(ev->state == PropertyDelete)
  393. return;
  394. if((c = client_gb_win(ev->window)))
  395. {
  396. switch(ev->atom)
  397. {
  398. default: break;
  399. case XA_WM_TRANSIENT_FOR:
  400. XGetTransientForHint(dpy, c->win, &trans);
  401. if((c->flags & TileFlag || c->flags & MaxFlag))
  402. if(((c->flags & HintFlag && (client_gb_win(trans) != NULL)))
  403. || (!(c->flags & HintFlag && (client_gb_win(trans) != NULL))))
  404. arrange(c->screen, True);
  405. break;
  406. case XA_WM_NORMAL_HINTS:
  407. client_size_hints(c);
  408. break;
  409. case XA_WM_NAME:
  410. client_get_name(c);
  411. break;
  412. }
  413. if(ev->atom == net_atom[net_wm_name])
  414. client_get_name(c);
  415. }
  416. return;
  417. }
  418. /** UnmapNotify handle event
  419. * \param ev XUnmapEvent pointer
  420. */
  421. void
  422. unmapnotify(XUnmapEvent *ev)
  423. {
  424. Client *c;
  425. if((c = client_gb_win(ev->window))
  426. && ev->send_event
  427. && !(c->flags & HideFlag))
  428. {
  429. client_unmanage(c);
  430. XSetErrorHandler(errorhandler);
  431. }
  432. return;
  433. }
  434. /** Send a client event
  435. *\param data Event data
  436. *\param atom_name Event atom name
  437. */
  438. void
  439. send_client_event(long data[5], char *atom_name)
  440. {
  441. XEvent ev;
  442. int i;
  443. ev.xclient.type = ClientMessage;
  444. ev.xclient.serial = 0;
  445. ev.xclient.send_event = True;
  446. ev.xclient.message_type = ATOM(atom_name);
  447. ev.xclient.window = ROOT;
  448. ev.xclient.format = 32;
  449. for(i = 0; i < 5; ++i, ev.xclient.data.l[i] = data[i]);
  450. XSendEvent(dpy, ROOT, False, SubstructureRedirectMask | SubstructureNotifyMask, &ev);
  451. XSync(dpy, False);
  452. return;
  453. }
  454. /** Event handle function: execute every function
  455. * handle by event
  456. * \param ev Event
  457. */
  458. void
  459. getevent(XEvent ev)
  460. {
  461. switch(ev.type)
  462. {
  463. case ButtonPress: buttonpress(&ev.xbutton); break;
  464. case ClientMessage: clientmessageevent(&ev.xclient); break;
  465. case ConfigureRequest: configureevent(&ev.xconfigurerequest); break;
  466. case DestroyNotify: destroynotify(&ev.xdestroywindow); break;
  467. case EnterNotify: enternotify(&ev.xcrossing); break;
  468. case Expose: expose(&ev.xexpose); break;
  469. case FocusIn: focusin(&ev.xfocus); break;
  470. case KeyPress: keypress(&ev.xkey); break;
  471. case MapRequest: maprequest(&ev.xmaprequest); break;
  472. case MappingNotify: mappingnotify(&ev.xmapping); break;
  473. case PropertyNotify: propertynotify(&ev.xproperty); break;
  474. case UnmapNotify: unmapnotify(&ev.xunmap); break;
  475. default:
  476. #ifdef HAVE_XRANDR
  477. /* Check Xrandr event */
  478. if(ev.type == xrandr_event)
  479. {
  480. /* Update xrandr configuration */
  481. XRRUpdateConfiguration(&ev);
  482. /* Reload WMFS to update the screen(s) geometry changement */
  483. quit();
  484. for(; argv_global[0] && argv_global[0] == ' '; ++argv_global);
  485. execlp(argv_global, argv_global, NULL);
  486. }
  487. #endif /* HAVE_XRANDR */
  488. break;
  489. }
  490. wait((int[]){0});
  491. return;
  492. }