Mirror of Awesome WM window manager
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.

ewmh.c 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. /*
  2. * ewmh.c - EWMH support functions
  3. *
  4. * Copyright © 2007-2009 Julien Danjou <julien@danjou.info>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. */
  21. #include "ewmh.h"
  22. #include "objects/client.h"
  23. #include "objects/tag.h"
  24. #include "common/atoms.h"
  25. #include <sys/types.h>
  26. #include <unistd.h>
  27. #include <xcb/xcb.h>
  28. #include <xcb/xcb_atom.h>
  29. #define _NET_WM_STATE_REMOVE 0
  30. #define _NET_WM_STATE_ADD 1
  31. #define _NET_WM_STATE_TOGGLE 2
  32. /** Update client EWMH hints.
  33. * \param L The Lua VM state.
  34. */
  35. static int
  36. ewmh_client_update_hints(lua_State *L)
  37. {
  38. client_t *c = luaA_checkudata(L, 1, &client_class);
  39. xcb_atom_t state[10]; /* number of defined state atoms */
  40. int i = 0;
  41. if(c->modal)
  42. state[i++] = _NET_WM_STATE_MODAL;
  43. if(c->fullscreen)
  44. state[i++] = _NET_WM_STATE_FULLSCREEN;
  45. if(c->maximized_vertical)
  46. state[i++] = _NET_WM_STATE_MAXIMIZED_VERT;
  47. if(c->maximized_horizontal)
  48. state[i++] = _NET_WM_STATE_MAXIMIZED_HORZ;
  49. if(c->sticky)
  50. state[i++] = _NET_WM_STATE_STICKY;
  51. if(c->skip_taskbar)
  52. state[i++] = _NET_WM_STATE_SKIP_TASKBAR;
  53. if(c->above)
  54. state[i++] = _NET_WM_STATE_ABOVE;
  55. if(c->below)
  56. state[i++] = _NET_WM_STATE_BELOW;
  57. if(c->minimized)
  58. state[i++] = _NET_WM_STATE_HIDDEN;
  59. if(c->urgent)
  60. state[i++] = _NET_WM_STATE_DEMANDS_ATTENTION;
  61. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  62. c->window, _NET_WM_STATE, XCB_ATOM_ATOM, 32, i, state);
  63. return 0;
  64. }
  65. static int
  66. ewmh_update_net_active_window(lua_State *L)
  67. {
  68. xcb_window_t win;
  69. if(globalconf.focus.client)
  70. win = globalconf.focus.client->window;
  71. else
  72. win = XCB_NONE;
  73. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  74. globalconf.screen->root,
  75. _NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 32, 1, &win);
  76. return 0;
  77. }
  78. static int
  79. ewmh_update_net_client_list(lua_State *L)
  80. {
  81. xcb_window_t *wins = p_alloca(xcb_window_t, globalconf.clients.len);
  82. int n = 0;
  83. foreach(client, globalconf.clients)
  84. wins[n++] = (*client)->window;
  85. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  86. globalconf.screen->root,
  87. _NET_CLIENT_LIST, XCB_ATOM_WINDOW, 32, n, wins);
  88. return 0;
  89. }
  90. void
  91. ewmh_init(void)
  92. {
  93. lua_State *L = globalconf_get_lua_State();
  94. xcb_window_t father;
  95. xcb_screen_t *xscreen = globalconf.screen;
  96. xcb_atom_t atom[] =
  97. {
  98. _NET_SUPPORTED,
  99. _NET_SUPPORTING_WM_CHECK,
  100. _NET_STARTUP_ID,
  101. _NET_CLIENT_LIST,
  102. _NET_CLIENT_LIST_STACKING,
  103. _NET_NUMBER_OF_DESKTOPS,
  104. _NET_CURRENT_DESKTOP,
  105. _NET_DESKTOP_NAMES,
  106. _NET_ACTIVE_WINDOW,
  107. _NET_CLOSE_WINDOW,
  108. _NET_WM_NAME,
  109. _NET_WM_STRUT_PARTIAL,
  110. _NET_WM_ICON_NAME,
  111. _NET_WM_VISIBLE_ICON_NAME,
  112. _NET_WM_DESKTOP,
  113. _NET_WM_WINDOW_TYPE,
  114. _NET_WM_WINDOW_TYPE_DESKTOP,
  115. _NET_WM_WINDOW_TYPE_DOCK,
  116. _NET_WM_WINDOW_TYPE_TOOLBAR,
  117. _NET_WM_WINDOW_TYPE_MENU,
  118. _NET_WM_WINDOW_TYPE_UTILITY,
  119. _NET_WM_WINDOW_TYPE_SPLASH,
  120. _NET_WM_WINDOW_TYPE_DIALOG,
  121. _NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
  122. _NET_WM_WINDOW_TYPE_POPUP_MENU,
  123. _NET_WM_WINDOW_TYPE_TOOLTIP,
  124. _NET_WM_WINDOW_TYPE_NOTIFICATION,
  125. _NET_WM_WINDOW_TYPE_COMBO,
  126. _NET_WM_WINDOW_TYPE_DND,
  127. _NET_WM_WINDOW_TYPE_NORMAL,
  128. _NET_WM_ICON,
  129. _NET_WM_PID,
  130. _NET_WM_STATE,
  131. _NET_WM_STATE_STICKY,
  132. _NET_WM_STATE_SKIP_TASKBAR,
  133. _NET_WM_STATE_FULLSCREEN,
  134. _NET_WM_STATE_MAXIMIZED_HORZ,
  135. _NET_WM_STATE_MAXIMIZED_VERT,
  136. _NET_WM_STATE_ABOVE,
  137. _NET_WM_STATE_BELOW,
  138. _NET_WM_STATE_MODAL,
  139. _NET_WM_STATE_HIDDEN,
  140. _NET_WM_STATE_DEMANDS_ATTENTION
  141. };
  142. int i;
  143. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  144. xscreen->root, _NET_SUPPORTED, XCB_ATOM_ATOM, 32,
  145. countof(atom), atom);
  146. /* create our own window */
  147. father = xcb_generate_id(globalconf.connection);
  148. xcb_create_window(globalconf.connection, xscreen->root_depth,
  149. father, xscreen->root, -1, -1, 1, 1, 0,
  150. XCB_COPY_FROM_PARENT, xscreen->root_visual, 0, NULL);
  151. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  152. xscreen->root, _NET_SUPPORTING_WM_CHECK, XCB_ATOM_WINDOW, 32,
  153. 1, &father);
  154. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  155. father, _NET_SUPPORTING_WM_CHECK, XCB_ATOM_WINDOW, 32,
  156. 1, &father);
  157. /* set the window manager name */
  158. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  159. father, _NET_WM_NAME, UTF8_STRING, 8, 7, "awesome");
  160. /* set the window manager PID */
  161. i = getpid();
  162. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  163. father, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &i);
  164. luaA_class_connect_signal(L, &client_class, "focus", ewmh_update_net_active_window);
  165. luaA_class_connect_signal(L, &client_class, "unfocus", ewmh_update_net_active_window);
  166. luaA_class_connect_signal(L, &client_class, "manage", ewmh_update_net_client_list);
  167. luaA_class_connect_signal(L, &client_class, "unmanage", ewmh_update_net_client_list);
  168. luaA_class_connect_signal(L, &client_class, "property::modal" , ewmh_client_update_hints);
  169. luaA_class_connect_signal(L, &client_class, "property::fullscreen" , ewmh_client_update_hints);
  170. luaA_class_connect_signal(L, &client_class, "property::maximized_horizontal" , ewmh_client_update_hints);
  171. luaA_class_connect_signal(L, &client_class, "property::maximized_vertical" , ewmh_client_update_hints);
  172. luaA_class_connect_signal(L, &client_class, "property::sticky" , ewmh_client_update_hints);
  173. luaA_class_connect_signal(L, &client_class, "property::skip_taskbar" , ewmh_client_update_hints);
  174. luaA_class_connect_signal(L, &client_class, "property::above" , ewmh_client_update_hints);
  175. luaA_class_connect_signal(L, &client_class, "property::below" , ewmh_client_update_hints);
  176. luaA_class_connect_signal(L, &client_class, "property::minimized" , ewmh_client_update_hints);
  177. luaA_class_connect_signal(L, &client_class, "property::urgent" , ewmh_client_update_hints);
  178. }
  179. /** Set the client list in stacking order, bottom to top.
  180. */
  181. void
  182. ewmh_update_net_client_list_stacking(void)
  183. {
  184. int n = 0;
  185. xcb_window_t *wins = p_alloca(xcb_window_t, globalconf.stack.len);
  186. foreach(client, globalconf.stack)
  187. wins[n++] = (*client)->window;
  188. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  189. globalconf.screen->root,
  190. _NET_CLIENT_LIST_STACKING, XCB_ATOM_WINDOW, 32, n, wins);
  191. }
  192. void
  193. ewmh_update_net_numbers_of_desktop(void)
  194. {
  195. uint32_t count = globalconf.tags.len;
  196. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  197. globalconf.screen->root,
  198. _NET_NUMBER_OF_DESKTOPS, XCB_ATOM_CARDINAL, 32, 1, &count);
  199. }
  200. void
  201. ewmh_update_net_current_desktop(void)
  202. {
  203. uint32_t idx = tags_get_first_selected_index();
  204. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  205. globalconf.screen->root,
  206. _NET_CURRENT_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, &idx);
  207. }
  208. void
  209. ewmh_update_net_desktop_names(void)
  210. {
  211. buffer_t buf;
  212. buffer_inita(&buf, BUFSIZ);
  213. foreach(tag, globalconf.tags)
  214. {
  215. buffer_adds(&buf, tag_get_name(*tag));
  216. buffer_addc(&buf, '\0');
  217. }
  218. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  219. globalconf.screen->root,
  220. _NET_DESKTOP_NAMES, UTF8_STRING, 8, buf.len, buf.s);
  221. buffer_wipe(&buf);
  222. }
  223. static void
  224. ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
  225. {
  226. lua_State *L = globalconf_get_lua_State();
  227. luaA_object_push(L, c);
  228. if(state == _NET_WM_STATE_STICKY)
  229. {
  230. if(set == _NET_WM_STATE_REMOVE)
  231. client_set_sticky(L, -1, false);
  232. else if(set == _NET_WM_STATE_ADD)
  233. client_set_sticky(L, -1, true);
  234. else if(set == _NET_WM_STATE_TOGGLE)
  235. client_set_sticky(L, -1, !c->sticky);
  236. }
  237. else if(state == _NET_WM_STATE_SKIP_TASKBAR)
  238. {
  239. if(set == _NET_WM_STATE_REMOVE)
  240. client_set_skip_taskbar(L, -1, false);
  241. else if(set == _NET_WM_STATE_ADD)
  242. client_set_skip_taskbar(L, -1, true);
  243. else if(set == _NET_WM_STATE_TOGGLE)
  244. client_set_skip_taskbar(L, -1, !c->skip_taskbar);
  245. }
  246. else if(state == _NET_WM_STATE_FULLSCREEN)
  247. {
  248. if(set == _NET_WM_STATE_REMOVE)
  249. client_set_fullscreen(L, -1, false);
  250. else if(set == _NET_WM_STATE_ADD)
  251. client_set_fullscreen(L, -1, true);
  252. else if(set == _NET_WM_STATE_TOGGLE)
  253. client_set_fullscreen(L, -1, !c->fullscreen);
  254. }
  255. else if(state == _NET_WM_STATE_MAXIMIZED_HORZ)
  256. {
  257. if(set == _NET_WM_STATE_REMOVE)
  258. client_set_maximized_horizontal(L, -1, false);
  259. else if(set == _NET_WM_STATE_ADD)
  260. client_set_maximized_horizontal(L, -1, true);
  261. else if(set == _NET_WM_STATE_TOGGLE)
  262. client_set_maximized_horizontal(L, -1, !c->maximized_horizontal);
  263. }
  264. else if(state == _NET_WM_STATE_MAXIMIZED_VERT)
  265. {
  266. if(set == _NET_WM_STATE_REMOVE)
  267. client_set_maximized_vertical(L, -1, false);
  268. else if(set == _NET_WM_STATE_ADD)
  269. client_set_maximized_vertical(L, -1, true);
  270. else if(set == _NET_WM_STATE_TOGGLE)
  271. client_set_maximized_vertical(L, -1, !c->maximized_vertical);
  272. }
  273. else if(state == _NET_WM_STATE_ABOVE)
  274. {
  275. if(set == _NET_WM_STATE_REMOVE)
  276. client_set_above(L, -1, false);
  277. else if(set == _NET_WM_STATE_ADD)
  278. client_set_above(L, -1, true);
  279. else if(set == _NET_WM_STATE_TOGGLE)
  280. client_set_above(L, -1, !c->above);
  281. }
  282. else if(state == _NET_WM_STATE_BELOW)
  283. {
  284. if(set == _NET_WM_STATE_REMOVE)
  285. client_set_below(L, -1, false);
  286. else if(set == _NET_WM_STATE_ADD)
  287. client_set_below(L, -1, true);
  288. else if(set == _NET_WM_STATE_TOGGLE)
  289. client_set_below(L, -1, !c->below);
  290. }
  291. else if(state == _NET_WM_STATE_MODAL)
  292. {
  293. if(set == _NET_WM_STATE_REMOVE)
  294. client_set_modal(L, -1, false);
  295. else if(set == _NET_WM_STATE_ADD)
  296. client_set_modal(L, -1, true);
  297. else if(set == _NET_WM_STATE_TOGGLE)
  298. client_set_modal(L, -1, !c->modal);
  299. }
  300. else if(state == _NET_WM_STATE_HIDDEN)
  301. {
  302. if(set == _NET_WM_STATE_REMOVE)
  303. client_set_minimized(L, -1, false);
  304. else if(set == _NET_WM_STATE_ADD)
  305. client_set_minimized(L, -1, true);
  306. else if(set == _NET_WM_STATE_TOGGLE)
  307. client_set_minimized(L, -1, !c->minimized);
  308. }
  309. else if(state == _NET_WM_STATE_DEMANDS_ATTENTION)
  310. {
  311. if(set == _NET_WM_STATE_REMOVE)
  312. client_set_urgent(L, -1, false);
  313. else if(set == _NET_WM_STATE_ADD)
  314. client_set_urgent(L, -1, true);
  315. else if(set == _NET_WM_STATE_TOGGLE)
  316. client_set_urgent(L, -1, !c->urgent);
  317. }
  318. lua_pop(L, 1);
  319. }
  320. static void
  321. ewmh_process_desktop(client_t *c, uint32_t desktop)
  322. {
  323. lua_State *L = globalconf_get_lua_State();
  324. int idx = desktop;
  325. if(desktop == 0xffffffff)
  326. {
  327. luaA_object_push(L, c);
  328. lua_pushnil(L);
  329. luaA_object_emit_signal(L, -2, "request::tag", 1);
  330. /* Pop the client, arguments are already popped */
  331. lua_pop(L, 1);
  332. }
  333. else if (idx >= 0 && idx < globalconf.tags.len)
  334. {
  335. luaA_object_push(L, c);
  336. luaA_object_push(L, globalconf.tags.tab[idx]);
  337. luaA_object_emit_signal(L, -2, "request::tag", 1);
  338. /* Pop the client, arguments are already popped */
  339. lua_pop(L, 1);
  340. }
  341. }
  342. int
  343. ewmh_process_client_message(xcb_client_message_event_t *ev)
  344. {
  345. client_t *c;
  346. if(ev->type == _NET_CURRENT_DESKTOP)
  347. {
  348. int idx = ev->data.data32[0];
  349. if (idx >= 0 && idx < globalconf.tags.len)
  350. {
  351. lua_State *L = globalconf_get_lua_State();
  352. luaA_object_push(L, globalconf.tags.tab[idx]);
  353. luaA_object_emit_signal(L, -1, "request::select", 0);
  354. lua_pop(L, 1);
  355. }
  356. }
  357. else if(ev->type == _NET_CLOSE_WINDOW)
  358. {
  359. if((c = client_getbywin(ev->window)))
  360. client_kill(c);
  361. }
  362. else if(ev->type == _NET_WM_DESKTOP)
  363. {
  364. if((c = client_getbywin(ev->window)))
  365. {
  366. ewmh_process_desktop(c, ev->data.data32[0]);
  367. }
  368. }
  369. else if(ev->type == _NET_WM_STATE)
  370. {
  371. if((c = client_getbywin(ev->window)))
  372. {
  373. ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[1], ev->data.data32[0]);
  374. if(ev->data.data32[2])
  375. ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[2],
  376. ev->data.data32[0]);
  377. }
  378. }
  379. else if(ev->type == _NET_ACTIVE_WINDOW)
  380. {
  381. if((c = client_getbywin(ev->window))) {
  382. lua_State *L = globalconf_get_lua_State();
  383. luaA_object_push(L, c);
  384. lua_pushstring(L, "ewmh");
  385. luaA_object_emit_signal(L, -2, "request::activate", 1);
  386. lua_pop(L, 1);
  387. }
  388. }
  389. return 0;
  390. }
  391. /** Update the client active desktop.
  392. * This is "wrong" since it can be on several tags, but EWMH has a strict view
  393. * of desktop system so just take the first tag.
  394. * \param c The client.
  395. */
  396. void
  397. ewmh_client_update_desktop(client_t *c)
  398. {
  399. int i;
  400. for(i = 0; i < globalconf.tags.len; i++)
  401. if(is_client_tagged(c, globalconf.tags.tab[i]))
  402. {
  403. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  404. c->window, _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, &i);
  405. return;
  406. }
  407. /* It doesn't have any tags, remove the property */
  408. xcb_delete_property(globalconf.connection, c->window, _NET_WM_DESKTOP);
  409. }
  410. /** Update the client struts.
  411. * \param window The window to update the struts for.
  412. * \param strut The strut type to update the window with.
  413. */
  414. void
  415. ewmh_update_strut(xcb_window_t window, strut_t *strut)
  416. {
  417. if(window)
  418. {
  419. const uint32_t state[] =
  420. {
  421. strut->left,
  422. strut->right,
  423. strut->top,
  424. strut->bottom,
  425. strut->left_start_y,
  426. strut->left_end_y,
  427. strut->right_start_y,
  428. strut->right_end_y,
  429. strut->top_start_x,
  430. strut->top_end_x,
  431. strut->bottom_start_x,
  432. strut->bottom_end_x
  433. };
  434. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  435. window, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, countof(state), state);
  436. }
  437. }
  438. /** Update the window type.
  439. * \param window The window to update.
  440. * \param type The new type to set.
  441. */
  442. void
  443. ewmh_update_window_type(xcb_window_t window, uint32_t type)
  444. {
  445. xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
  446. window, _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32, 1, &type);
  447. }
  448. void
  449. ewmh_client_check_hints(client_t *c)
  450. {
  451. xcb_atom_t *state;
  452. void *data = NULL;
  453. xcb_get_property_cookie_t c0, c1, c2;
  454. xcb_get_property_reply_t *reply;
  455. /* Send the GetProperty requests which will be processed later */
  456. c0 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
  457. _NET_WM_DESKTOP, XCB_GET_PROPERTY_TYPE_ANY, 0, 1);
  458. c1 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
  459. _NET_WM_STATE, XCB_ATOM_ATOM, 0, UINT32_MAX);
  460. c2 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
  461. _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 0, UINT32_MAX);
  462. reply = xcb_get_property_reply(globalconf.connection, c0, NULL);
  463. if(reply && reply->value_len && (data = xcb_get_property_value(reply)))
  464. {
  465. ewmh_process_desktop(c, *(uint32_t *) data);
  466. }
  467. p_delete(&reply);
  468. reply = xcb_get_property_reply(globalconf.connection, c1, NULL);
  469. if(reply && (data = xcb_get_property_value(reply)))
  470. {
  471. state = (xcb_atom_t *) data;
  472. for(int i = 0; i < xcb_get_property_value_length(reply) / ssizeof(xcb_atom_t); i++)
  473. ewmh_process_state_atom(c, state[i], _NET_WM_STATE_ADD);
  474. }
  475. p_delete(&reply);
  476. reply = xcb_get_property_reply(globalconf.connection, c2, NULL);
  477. if(reply && (data = xcb_get_property_value(reply)))
  478. {
  479. state = (xcb_atom_t *) data;
  480. for(int i = 0; i < xcb_get_property_value_length(reply) / ssizeof(xcb_atom_t); i++)
  481. if(state[i] == _NET_WM_WINDOW_TYPE_DESKTOP)
  482. c->type = MAX(c->type, WINDOW_TYPE_DESKTOP);
  483. else if(state[i] == _NET_WM_WINDOW_TYPE_DIALOG)
  484. c->type = MAX(c->type, WINDOW_TYPE_DIALOG);
  485. else if(state[i] == _NET_WM_WINDOW_TYPE_SPLASH)
  486. c->type = MAX(c->type, WINDOW_TYPE_SPLASH);
  487. else if(state[i] == _NET_WM_WINDOW_TYPE_DOCK)
  488. c->type = MAX(c->type, WINDOW_TYPE_DOCK);
  489. else if(state[i] == _NET_WM_WINDOW_TYPE_MENU)
  490. c->type = MAX(c->type, WINDOW_TYPE_MENU);
  491. else if(state[i] == _NET_WM_WINDOW_TYPE_TOOLBAR)
  492. c->type = MAX(c->type, WINDOW_TYPE_TOOLBAR);
  493. else if(state[i] == _NET_WM_WINDOW_TYPE_UTILITY)
  494. c->type = MAX(c->type, WINDOW_TYPE_UTILITY);
  495. }
  496. p_delete(&reply);
  497. }
  498. /** Process the WM strut of a client.
  499. * \param c The client.
  500. */
  501. void
  502. ewmh_process_client_strut(client_t *c)
  503. {
  504. void *data;
  505. xcb_get_property_reply_t *strut_r;
  506. xcb_get_property_cookie_t strut_q = xcb_get_property_unchecked(globalconf.connection, false, c->window,
  507. _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 0, 12);
  508. strut_r = xcb_get_property_reply(globalconf.connection, strut_q, NULL);
  509. if(strut_r
  510. && strut_r->value_len
  511. && (data = xcb_get_property_value(strut_r)))
  512. {
  513. uint32_t *strut = data;
  514. if(c->strut.left != strut[0]
  515. || c->strut.right != strut[1]
  516. || c->strut.top != strut[2]
  517. || c->strut.bottom != strut[3]
  518. || c->strut.left_start_y != strut[4]
  519. || c->strut.left_end_y != strut[5]
  520. || c->strut.right_start_y != strut[6]
  521. || c->strut.right_end_y != strut[7]
  522. || c->strut.top_start_x != strut[8]
  523. || c->strut.top_end_x != strut[9]
  524. || c->strut.bottom_start_x != strut[10]
  525. || c->strut.bottom_end_x != strut[11])
  526. {
  527. c->strut.left = strut[0];
  528. c->strut.right = strut[1];
  529. c->strut.top = strut[2];
  530. c->strut.bottom = strut[3];
  531. c->strut.left_start_y = strut[4];
  532. c->strut.left_end_y = strut[5];
  533. c->strut.right_start_y = strut[6];
  534. c->strut.right_end_y = strut[7];
  535. c->strut.top_start_x = strut[8];
  536. c->strut.top_end_x = strut[9];
  537. c->strut.bottom_start_x = strut[10];
  538. c->strut.bottom_end_x = strut[11];
  539. lua_State *L = globalconf_get_lua_State();
  540. luaA_object_push(L, c);
  541. luaA_object_emit_signal(L, -1, "property::struts", 0);
  542. lua_pop(L, 1);
  543. }
  544. }
  545. p_delete(&strut_r);
  546. }
  547. /** Send request to get NET_WM_ICON (EWMH)
  548. * \param w The window.
  549. * \return The cookie associated with the request.
  550. */
  551. xcb_get_property_cookie_t
  552. ewmh_window_icon_get_unchecked(xcb_window_t w)
  553. {
  554. return xcb_get_property_unchecked(globalconf.connection, false, w,
  555. _NET_WM_ICON, XCB_ATOM_CARDINAL, 0, UINT32_MAX);
  556. }
  557. static cairo_surface_t *
  558. ewmh_window_icon_from_reply(xcb_get_property_reply_t *r)
  559. {
  560. uint32_t *data;
  561. uint64_t len;
  562. if(!r || r->type != XCB_ATOM_CARDINAL || r->format != 32 || r->length < 2)
  563. return 0;
  564. data = (uint32_t *) xcb_get_property_value(r);
  565. if (!data)
  566. return 0;
  567. /* Check that the property is as long as it should be, handling integer
  568. * overflow. <uint32_t> times <another uint32_t casted to uint64_t> always
  569. * fits into an uint64_t and thus this multiplication cannot overflow.
  570. */
  571. len = data[0] * (uint64_t) data[1];
  572. if (!data[0] || !data[1] || len > r->length - 2)
  573. return 0;
  574. return draw_surface_from_data(data[0], data[1], data + 2);
  575. }
  576. /** Get NET_WM_ICON.
  577. * \param cookie The cookie.
  578. * \return The number of elements on stack.
  579. */
  580. cairo_surface_t *
  581. ewmh_window_icon_get_reply(xcb_get_property_cookie_t cookie)
  582. {
  583. xcb_get_property_reply_t *r = xcb_get_property_reply(globalconf.connection, cookie, NULL);
  584. cairo_surface_t *surface = ewmh_window_icon_from_reply(r);
  585. p_delete(&r);
  586. return surface;
  587. }
  588. // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80