event.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  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 s, 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. s = screen_count();
  138. for(i = 0; i < net_last + s; ++i)
  139. if(net_atom[i] == ev->message_type)
  140. mess_t = i;
  141. if(ev->window == ROOT)
  142. {
  143. /* Manage _NET_CURRENT_DESKTOP */
  144. if(mess_t == net_current_desktop
  145. && ev->data.l[0] >= 0
  146. && ev->data.l[0] < conf.ntag[selscreen])
  147. tag_set((int)(ev->data.l[0] + 1));
  148. /* Manage _WMFS_SET_SCREEN */
  149. if(mess_t == wmfs_set_screen
  150. && ev->data.l[0] >= 0
  151. && ev->data.l[0] <= s)
  152. screen_set_sel((int)(ev->data.l[0]));
  153. /* Manage _NET_ACTIVE_WINDOW */
  154. else if(mess_t == net_active_window)
  155. if((c = client_gb_win(ev->window)))
  156. client_focus(c);
  157. }
  158. /* Manage _NET_WM_STATE */
  159. if(mess_t == net_wm_state)
  160. if((c = client_gb_win(ev->window)))
  161. ewmh_manage_net_wm_state(ev->data.l, c);
  162. /* Manage _NET_CLOSE_WINDOW */
  163. if(mess_t == net_close_window)
  164. if((c = client_gb_win(ev->window)))
  165. client_kill(c);
  166. /* Manage _NET_WM_DESKTOP */
  167. if(mess_t == net_wm_desktop)
  168. if((c = client_gb_win(ev->window)))
  169. tag_transfert(c, ev->data.l[0]);
  170. /* Manage _WMFS_STATUSTEXT_x */
  171. if(mess_t >= wmfs_statustext && ev->data.l[4] == True)
  172. {
  173. if(XGetWindowProperty(dpy, ROOT, net_atom[mess_t], 0, 4096,
  174. False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret) == Success)
  175. {
  176. statustext_handle(mess_t - wmfs_statustext, (char*)ret);
  177. XFree(ret);
  178. }
  179. }
  180. /* Manage _WMFS_FUNCTION && _WMFS_CMD */
  181. if((mess_t == wmfs_function && ev->data.l[4] == True)
  182. || (mess_t == wmfs_cmd && ev->data.l[4] == True))
  183. {
  184. XGetWindowProperty(dpy, ROOT, net_atom[wmfs_function], 0, 4096,
  185. False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret);
  186. XGetWindowProperty(dpy, ROOT, net_atom[wmfs_cmd], 0, 4096,
  187. False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret_cmd);
  188. if((func = name_to_func((char*)ret, func_list)))
  189. func((uicb_t)ret_cmd);
  190. XFree(ret_cmd);
  191. XFree(ret);
  192. }
  193. /* Manage _WMFS_UPDATE_HINTS */
  194. if(mess_t == wmfs_update_hints)
  195. {
  196. ewmh_get_number_of_desktop();
  197. ewmh_update_current_tag_prop();
  198. ewmh_get_client_list();
  199. ewmh_get_desktop_names();
  200. ewmh_set_desktop_geometry();
  201. ewmh_set_workarea();
  202. screen_count();
  203. screen_get_sel();
  204. }
  205. if(mess_t == wmfs_update_status
  206. && estatus)
  207. spawn(conf.status_path);
  208. return;
  209. }
  210. /** ConfigureRequest & ConfigureNotify handle events
  211. * \param ev XEvent pointer
  212. */
  213. void
  214. configureevent(XConfigureRequestEvent *ev)
  215. {
  216. XWindowChanges wc;
  217. Client *c;
  218. /* Check part */
  219. if((c = client_gb_win(ev->window))
  220. || (c = client_gb_win(ev->window)))
  221. {
  222. CHECK(!(c->flags & TileFlag));
  223. CHECK(!(c->flags & LMaxFlag));
  224. CHECK(!(c->flags & MaxFlag));
  225. CHECK(!(c->flags & FSSFlag));
  226. }
  227. if((c = client_gb_win(ev->window)))
  228. {
  229. if(ev->value_mask & CWX)
  230. c->geo.x = ev->x + BORDH;
  231. if(ev->value_mask & CWY)
  232. c->geo.y = ev->y + TBARH;
  233. if(ev->value_mask & CWWidth)
  234. c->geo.width = ev->width;
  235. if(ev->value_mask & CWHeight)
  236. c->geo.height = ev->height;
  237. if(c->flags & FreeFlag)
  238. client_moveresize(c, c->geo, False);
  239. }
  240. else
  241. {
  242. wc.x = ev->x;
  243. wc.y = ev->y;
  244. wc.width = ev->width;
  245. wc.height = ev->height;
  246. wc.border_width = ev->border_width;
  247. wc.sibling = ev->above;
  248. wc.stack_mode = ev->detail;
  249. XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
  250. }
  251. return;
  252. }
  253. /** DestroyNotify handle event
  254. * \param ev XDestroyWindowEvent pointer
  255. */
  256. void
  257. destroynotify(XDestroyWindowEvent *ev)
  258. {
  259. Client *c;
  260. if((c = client_gb_win(ev->window)))
  261. {
  262. client_unmanage(c);
  263. XSetErrorHandler(errorhandler);
  264. }
  265. return;
  266. }
  267. /** EnterNotify handle event
  268. * \param ev XCrossingEvent pointer
  269. */
  270. void
  271. enternotify(XCrossingEvent *ev)
  272. {
  273. Client *c;
  274. int n;
  275. if((ev->mode != NotifyNormal
  276. || ev->detail == NotifyInferior)
  277. && ev->window != ROOT)
  278. return;
  279. if(conf.focus_fmouse)
  280. {
  281. if((c = client_gb_win(ev->window))
  282. || (c = client_gb_frame(ev->window))
  283. || (c = client_gb_titlebar(ev->window))
  284. || (c = client_gb_button(ev->window, &n)))
  285. client_focus(c);
  286. else
  287. client_focus(NULL);
  288. }
  289. return;
  290. }
  291. /** ExposeEvent handle event
  292. * \param ev XExposeEvent pointer
  293. */
  294. void
  295. expose(XExposeEvent *ev)
  296. {
  297. Client *c;
  298. int i, sc;
  299. /* InfoBar member */
  300. for(sc = 0; sc < screen_count(); ++sc)
  301. {
  302. if(ev->window == infobar[sc].bar->win)
  303. barwin_refresh(infobar[sc].bar);
  304. if(ev->window == infobar[sc].layout_button->win)
  305. barwin_refresh(infobar[sc].layout_button);
  306. if(conf.bars.selbar && ev->window == infobar[sc].selbar->win)
  307. barwin_refresh(infobar[sc].selbar);
  308. for(i = 1; i < conf.ntag[sc] + 1; ++i)
  309. if(ev->window == infobar[sc].tags[i]->win)
  310. barwin_refresh(infobar[sc].tags[i]);
  311. }
  312. /* Client frame */
  313. if((c = client_gb_titlebar(ev->window)))
  314. frame_update(c);
  315. return;
  316. }
  317. /** FocusChange handle event
  318. * \param ev XFocusChangeEvent pointer
  319. * \return
  320. */
  321. void
  322. focusin(XFocusChangeEvent *ev)
  323. {
  324. if(sel && ev->window != sel->win)
  325. client_focus(sel);
  326. return;
  327. }
  328. /** Key grabbing function
  329. */
  330. void
  331. grabkeys(void)
  332. {
  333. uint i;
  334. KeyCode code;
  335. XUngrabKey(dpy, AnyKey, AnyModifier, ROOT);
  336. for(i = 0; i < conf.nkeybind; ++i)
  337. {
  338. code = XKeysymToKeycode(dpy, keys[i].keysym);
  339. XGrabKey(dpy, code, keys[i].mod, ROOT, True, GrabModeAsync, GrabModeAsync);
  340. XGrabKey(dpy, code, keys[i].mod | LockMask, ROOT, True, GrabModeAsync, GrabModeAsync);
  341. XGrabKey(dpy, code, keys[i].mod | numlockmask, ROOT, True, GrabModeAsync, GrabModeAsync);
  342. XGrabKey(dpy, code, keys[i].mod | LockMask | numlockmask, ROOT, True, GrabModeAsync, GrabModeAsync);
  343. }
  344. return;
  345. }
  346. /** KeyPress handle event
  347. * \param ev XKeyPressedEvent pointer
  348. */
  349. void
  350. keypress(XKeyPressedEvent *ev)
  351. {
  352. uint i;
  353. KeySym keysym;
  354. keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
  355. for(i = 0; i < conf.nkeybind; ++i)
  356. if(keysym == keys[i].keysym
  357. && (keys[i].mod & ~(numlockmask | LockMask))
  358. == (ev->state & ~(numlockmask | LockMask))
  359. && keys[i].func)
  360. keys[i].func(keys[i].cmd);
  361. return;
  362. }
  363. /** MapNotify handle event
  364. * \param ev XMappingEvent pointer
  365. */
  366. void
  367. mappingnotify(XMappingEvent *ev)
  368. {
  369. if(ev->request == MappingKeyboard)
  370. grabkeys();
  371. return;
  372. }
  373. /** MapRequest handle event
  374. * \param ev XMapRequestEvent pointer
  375. */
  376. void
  377. maprequest(XMapRequestEvent *ev)
  378. {
  379. XWindowAttributes at;
  380. Client *c;
  381. CHECK(XGetWindowAttributes(dpy, ev->window, &at));
  382. CHECK(!at.override_redirect);
  383. if(!(c = client_gb_win(ev->window)))
  384. client_manage(ev->window, &at, True);
  385. return;
  386. }
  387. /** PropertyNotify handle event
  388. * \param ev XPropertyEvent pointer
  389. */
  390. void
  391. propertynotify(XPropertyEvent *ev)
  392. {
  393. Client *c;
  394. Window trans;
  395. if(ev->state == PropertyDelete)
  396. return;
  397. if((c = client_gb_win(ev->window)))
  398. {
  399. switch(ev->atom)
  400. {
  401. default: break;
  402. case XA_WM_TRANSIENT_FOR:
  403. XGetTransientForHint(dpy, c->win, &trans);
  404. if((c->flags & TileFlag || c->flags & MaxFlag))
  405. if(((c->flags & HintFlag && (client_gb_win(trans) != NULL)))
  406. || (!(c->flags & HintFlag && (client_gb_win(trans) != NULL))))
  407. arrange(c->screen, True);
  408. break;
  409. case XA_WM_NORMAL_HINTS:
  410. client_size_hints(c);
  411. break;
  412. case XA_WM_NAME:
  413. client_get_name(c);
  414. break;
  415. }
  416. if(ev->atom == net_atom[net_wm_name])
  417. client_get_name(c);
  418. }
  419. return;
  420. }
  421. /** UnmapNotify handle event
  422. * \param ev XUnmapEvent pointer
  423. */
  424. void
  425. unmapnotify(XUnmapEvent *ev)
  426. {
  427. Client *c;
  428. if((c = client_gb_win(ev->window))
  429. && ev->send_event
  430. && !(c->flags & HideFlag))
  431. {
  432. client_unmanage(c);
  433. XSetErrorHandler(errorhandler);
  434. }
  435. return;
  436. }
  437. /** Send a client event
  438. *\param data Event data
  439. *\param atom_name Event atom name
  440. */
  441. void
  442. send_client_event(long data[5], char *atom_name)
  443. {
  444. XEvent ev;
  445. int i;
  446. ev.xclient.type = ClientMessage;
  447. ev.xclient.serial = 0;
  448. ev.xclient.send_event = True;
  449. ev.xclient.message_type = ATOM(atom_name);
  450. ev.xclient.window = ROOT;
  451. ev.xclient.format = 32;
  452. for(i = 0; i < 5; ++i, ev.xclient.data.l[i] = data[i]);
  453. XSendEvent(dpy, ROOT, False, SubstructureRedirectMask | SubstructureNotifyMask, &ev);
  454. XSync(dpy, False);
  455. return;
  456. }
  457. /** Event handle function: execute every function
  458. * handle by event
  459. * \param ev Event
  460. */
  461. void
  462. getevent(XEvent ev)
  463. {
  464. switch(ev.type)
  465. {
  466. case ButtonPress: buttonpress(&ev.xbutton); break;
  467. case ClientMessage: clientmessageevent(&ev.xclient); break;
  468. case ConfigureRequest: configureevent(&ev.xconfigurerequest); break;
  469. case DestroyNotify: destroynotify(&ev.xdestroywindow); break;
  470. case EnterNotify: enternotify(&ev.xcrossing); break;
  471. case Expose: expose(&ev.xexpose); break;
  472. case FocusIn: focusin(&ev.xfocus); break;
  473. case KeyPress: keypress(&ev.xkey); break;
  474. case MapRequest: maprequest(&ev.xmaprequest); break;
  475. case MappingNotify: mappingnotify(&ev.xmapping); break;
  476. case PropertyNotify: propertynotify(&ev.xproperty); break;
  477. case UnmapNotify: unmapnotify(&ev.xunmap); break;
  478. default:
  479. #ifdef HAVE_XRANDR
  480. /* Check Xrandr event */
  481. if(ev.type == xrandr_event)
  482. {
  483. /* Update xrandr configuration */
  484. XRRUpdateConfiguration(&ev);
  485. /* Reload WMFS to update the screen(s) geometry changement */
  486. quit();
  487. for(; argv_global[0] && argv_global[0] == ' '; ++argv_global);
  488. execlp(argv_global, argv_global, NULL);
  489. }
  490. #endif /* HAVE_XRANDR */
  491. break;
  492. }
  493. wait((int[]){0});
  494. return;
  495. }