ewmh.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /*
  2. * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
  3. * For license, see COPYING.
  4. */
  5. #include "ewmh.h"
  6. #include "util.h"
  7. #include "screen.h"
  8. #include "client.h"
  9. /* Taken From standards.freedesktop.org */
  10. #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
  11. #define _NET_WM_STATE_ADD 1 /* add/set property */
  12. #define _NET_WM_STATE_TOGGLE 2 /* toggle property */
  13. void
  14. ewmh_init(void)
  15. {
  16. int b = 1;
  17. W->net_atom = xcalloc(net_last, sizeof(Atom));
  18. /* EWMH hints */
  19. W->net_atom[wm_state] = ATOM("WM_STATE");
  20. W->net_atom[wm_class] = ATOM("WM_CLASS");
  21. W->net_atom[wm_name] = ATOM("WM_NAME");
  22. W->net_atom[net_supported] = ATOM("_NET_SUPPORTED");
  23. W->net_atom[net_client_list] = ATOM("_NET_CLIENT_LIST");
  24. W->net_atom[net_frame_extents] = ATOM("_NET_FRAME_EXTENTS");
  25. W->net_atom[net_number_of_desktops] = ATOM("_NET_NUMBER_OF_DESKTOPS");
  26. W->net_atom[net_current_desktop] = ATOM("_NET_CURRENT_DESKTOP");
  27. W->net_atom[net_desktop_names] = ATOM("_NET_DESKTOP_NAMES");
  28. W->net_atom[net_desktop_geometry] = ATOM("_NET_DESKTOP_GEOMETRY");
  29. W->net_atom[net_active_window] = ATOM("_NET_ACTIVE_WINDOW");
  30. W->net_atom[net_close_window] = ATOM("_NET_CLOSE_WINDOW");
  31. W->net_atom[net_wm_name] = ATOM("_NET_WM_NAME");
  32. W->net_atom[net_wm_pid] = ATOM("_NET_WM_PID");
  33. W->net_atom[net_wm_desktop] = ATOM("_NET_WM_DESKTOP");
  34. W->net_atom[net_showing_desktop] = ATOM("_NET_SHOWING_DESKTOP");
  35. W->net_atom[net_wm_icon_name] = ATOM("_NET_WM_ICON_NAME");
  36. W->net_atom[net_wm_window_type] = ATOM("_NET_WM_WINDOW_TYPE");
  37. W->net_atom[net_supporting_wm_check] = ATOM("_NET_SUPPORTING_WM_CHECK");
  38. W->net_atom[net_wm_window_opacity] = ATOM("_NET_WM_WINDOW_OPACITY");
  39. W->net_atom[net_wm_window_type_normal] = ATOM("_NET_WM_WINDOW_TYPE_NORMAL");
  40. W->net_atom[net_wm_window_type_desktop] = ATOM("_NET_WM_WINDOW_TYPE_DESKTOP");
  41. W->net_atom[net_wm_window_type_dock] = ATOM("_NET_WM_WINDOW_TYPE_DOCK");
  42. W->net_atom[net_wm_window_type_splash] = ATOM("_NET_WM_WINDOW_TYPE_SPLASH");
  43. W->net_atom[net_wm_window_type_dialog] = ATOM("_NET_WM_WINDOW_TYPE_DIALOG");
  44. W->net_atom[net_wm_icon] = ATOM("_NET_WM_ICON");
  45. W->net_atom[net_wm_state] = ATOM("_NET_WM_STATE");
  46. W->net_atom[net_wm_state_fullscreen] = ATOM("_NET_WM_STATE_FULLSCREEN");
  47. W->net_atom[net_wm_state_sticky] = ATOM("_NET_WM_STATE_STICKY");
  48. W->net_atom[net_wm_state_demands_attention] = ATOM("_NET_WM_STATE_DEMANDS_ATTENTION");
  49. W->net_atom[net_wm_state_hidden] = ATOM("_NET_WM_STATE_HIDDEN");
  50. W->net_atom[net_system_tray_s] = ATOM("_NET_SYSTEM_TRAY_S0");
  51. W->net_atom[net_system_tray_opcode] = ATOM("_NET_SYSTEM_TRAY_OPCODE");
  52. W->net_atom[net_system_tray_message_data] = ATOM("_NET_SYSTEM_TRAY_MESSAGE_DATA");
  53. W->net_atom[net_system_tray_visual] = ATOM("_NET_SYSTEM_TRAY_VISUAL");
  54. W->net_atom[net_system_tray_orientation] = ATOM("_NET_SYSTEM_TRAY_ORIENTATION");
  55. W->net_atom[xembed] = ATOM("_XEMBED");
  56. W->net_atom[xembedinfo] = ATOM("_XEMBED_INFO");
  57. W->net_atom[manager] = ATOM("MANAGER");
  58. W->net_atom[utf8_string] = ATOM("UTF8_STRING");
  59. /* WMFS hints */
  60. W->net_atom[wmfs_running] = ATOM("_WMFS_RUNNING");
  61. W->net_atom[wmfs_focus] = ATOM("_WMFS_FOCUS");
  62. W->net_atom[wmfs_update_hints] = ATOM("_WMFS_UPDATE_HINTS");
  63. W->net_atom[wmfs_set_screen] = ATOM("_WMFS_SET_SCREEN");
  64. W->net_atom[wmfs_screen_count] = ATOM("_WMFS_SCREEN_COUNT");
  65. W->net_atom[wmfs_current_tag] = ATOM("_WMFS_CURRENT_TAG");
  66. W->net_atom[wmfs_tag_list] = ATOM("_WMFS_TAG_LIST");
  67. W->net_atom[wmfs_current_screen] = ATOM("_WMFS_CURRENT_SCREEN");
  68. W->net_atom[wmfs_current_layout] = ATOM("_WMFS_CURRENT_LAYOUT");
  69. W->net_atom[wmfs_function] = ATOM("_WMFS_FUNCTION");
  70. W->net_atom[wmfs_cmd] = ATOM("_WMFS_CMD");
  71. XChangeProperty(W->dpy, W->root, W->net_atom[net_supported], XA_ATOM, 32,
  72. PropModeReplace, (unsigned char*)W->net_atom, net_last);
  73. XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_running], XA_CARDINAL, 32,
  74. PropModeReplace, (unsigned char*)&b, 1);
  75. /* Set _NET_SUPPORTING_WM_CHECK */
  76. XChangeProperty(W->dpy, W->root, W->net_atom[net_supporting_wm_check], XA_WINDOW, 32,
  77. PropModeReplace, (unsigned char*)&W->root, 1);
  78. XChangeProperty(W->dpy, W->root, ATOM("WM_CLASS"), XA_STRING, 8,
  79. PropModeReplace, (unsigned char*)&"wmfs", 4);
  80. XChangeProperty(W->dpy, W->root, W->net_atom[net_wm_name], W->net_atom[utf8_string], 8,
  81. PropModeReplace, (unsigned char*)&"wmfs2", 5);
  82. /*
  83. * Set _NET_WM_PID
  84. XChangeProperty(W->dpy, W->root, W->net_atom[net_wm_pid], XA_CARDINAL, 32,
  85. PropModeReplace, (unsigned char*)&pid, 1);
  86. * Set _NET_SHOWING_DESKTOP
  87. XChangeProperty(W->dpy, W->root, W->net_atom[net_showing_desktop], XA_CARDINAL, 32,
  88. PropModeReplace, (unsigned char*)&showing_desk, 1);
  89. */
  90. }
  91. void
  92. ewmh_set_wm_state(Window w, int state)
  93. {
  94. unsigned char d[] = { state, None };
  95. XChangeProperty(W->dpy, w, W->net_atom[wm_state],
  96. W->net_atom[wm_state], 32, PropModeReplace, d, 2);
  97. }
  98. /*
  99. * _NET_CLIENT_LIST
  100. */
  101. void
  102. ewmh_get_client_list(void)
  103. {
  104. Window *list;
  105. struct client *c;
  106. int win_n = 0;
  107. SLIST_FOREACH(c, &W->h.client, next)
  108. ++win_n;
  109. list = xcalloc(win_n, sizeof(Window));
  110. win_n = 0;
  111. SLIST_FOREACH(c, &W->h.client, next)
  112. list[win_n++] = c->win;
  113. XChangeProperty(W->dpy, W->root, W->net_atom[net_client_list], XA_WINDOW, 32,
  114. PropModeReplace, (unsigned char *)list, win_n);
  115. XFree(list);
  116. }
  117. /*
  118. * Get xembed state
  119. */
  120. long
  121. ewmh_get_xembed_state(Window win)
  122. {
  123. Atom rf;
  124. int f;
  125. long ret = 0;
  126. unsigned long n, il;
  127. unsigned char *data = NULL;
  128. if(XGetWindowProperty(W->dpy, win, W->net_atom[xembedinfo], 0L, 2, False,
  129. W->net_atom[xembedinfo], &rf, &f, &n, &il, &data) != Success)
  130. return 0;
  131. if(rf == W->net_atom[xembedinfo] && n == 2)
  132. ret = (long)data[1];
  133. if(n && data)
  134. XFree(data);
  135. return ret;
  136. }
  137. void
  138. ewmh_update_wmfs_props(void)
  139. {
  140. struct screen *s;
  141. int i, ns = 0;
  142. long *cts = NULL;
  143. SLIST_FOREACH(s, &W->h.screen, next)
  144. ++ns;
  145. cts = xcalloc(ns, sizeof(long));
  146. for(i = 0; i < ns; ++i)
  147. {
  148. s = screen_gb_id(i);
  149. cts[i] = (s->seltag ? s->seltag->id : 0);
  150. }
  151. XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_current_tag], XA_CARDINAL, 32,
  152. PropModeReplace, (unsigned char*)cts, ns);
  153. if(W->client)
  154. XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_focus], XA_WINDOW, 32,
  155. PropModeReplace, (unsigned char*)&W->client->win, 1);
  156. free(cts);
  157. }
  158. void
  159. ewmh_manage_state(long data[], struct client *c)
  160. {
  161. /* _NET_WM_STATE_FULLSCREEN */
  162. if(data[1] == (long)W->net_atom[net_wm_state_fullscreen]
  163. || data[2] == (long)W->net_atom[net_wm_state_fullscreen])
  164. {
  165. if(data[0] == _NET_WM_STATE_ADD
  166. || (data[0] == _NET_WM_STATE_TOGGLE && !(c->flags & CLIENT_FULLSCREEN)))
  167. {
  168. c->flags |= CLIENT_FULLSCREEN;
  169. XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace,
  170. (unsigned char*)&W->net_atom[net_wm_state_fullscreen], 1);
  171. XReparentWindow(W->dpy, c->win, W->root, c->screen->geo.x, c->screen->geo.y);
  172. XResizeWindow(W->dpy, c->win, c->screen->geo.w, c->screen->geo.h);
  173. if(c->tag)
  174. client_focus(c);
  175. XRaiseWindow(W->dpy, c->win);
  176. }
  177. else
  178. {
  179. c->flags &= ~CLIENT_FULLSCREEN;
  180. XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace,
  181. (unsigned char*)0, 0);
  182. XReparentWindow(W->dpy, c->win, c->frame, c->wgeo.x, c->wgeo.y);
  183. if(c->flags & CLIENT_FREE)
  184. client_moveresize(c, &c->geo);
  185. else
  186. layout_fix_hole(c);
  187. }
  188. }
  189. }
  190. bool
  191. ewmh_manage_state_sticky(Window win)
  192. {
  193. Atom *atom, rf;
  194. int f;
  195. unsigned long n, il, i;
  196. unsigned char *data = NULL;
  197. bool is_sticky = false;
  198. if(XGetWindowProperty(W->dpy, win, W->net_atom[net_wm_state], 0L, 0x7FFFFFFFL, false,
  199. XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
  200. {
  201. atom = (Atom*)data;
  202. for(i = 0; i < n; ++i)
  203. {
  204. /* manage _NET_WM_STATE_STICKY */
  205. if(atom[i] == W->net_atom[net_wm_state_sticky])
  206. {
  207. XWindowAttributes at;
  208. XMapWindow(W->dpy, win);
  209. XMapSubwindows(W->dpy, win);
  210. if(XGetWindowAttributes(W->dpy, win, &at))
  211. {
  212. struct geo g;
  213. if(at.x < W->screen->ugeo.x)
  214. g.x = W->screen->ugeo.x;
  215. else if((at.x + at.width) > W->screen->ugeo.w)
  216. g.x = W->screen->ugeo.w - at.width;
  217. else
  218. g.x = at.x;
  219. if(at.y < W->screen->ugeo.y)
  220. g.y = W->screen->ugeo.y;
  221. else if((at.y + at.height) > W->screen->ugeo.h)
  222. g.y = W->screen->ugeo.h - at.height;
  223. else
  224. g.y = at.y;
  225. XMoveWindow(W->dpy, win, g.x, g.y);
  226. }
  227. if(W->client)
  228. {
  229. XUngrabButton(W->dpy, AnyButton, AnyModifier, W->client->win);
  230. XGrabButton(W->dpy, AnyButton, AnyModifier, W->client->win, False,
  231. ButtonMask, GrabModeAsync, GrabModeSync, None, None);
  232. client_frame_update(W->client, &W->client->ncol);
  233. W->client = NULL;
  234. }
  235. XRaiseWindow(W->dpy, win);
  236. XSetInputFocus(W->dpy, win, RevertToPointerRoot, CurrentTime);
  237. XChangeProperty(W->dpy, W->root, W->net_atom[net_active_window], XA_WINDOW, 32,
  238. PropModeReplace, (unsigned char *)&win, 1);
  239. is_sticky = true;
  240. break;
  241. }
  242. }
  243. XFree(data);
  244. }
  245. return is_sticky;
  246. }
  247. void
  248. ewmh_manage_window_type(struct client *c)
  249. {
  250. Atom *atom, rf;
  251. int f;
  252. unsigned long n, il, i;
  253. unsigned char *data = NULL;
  254. long ldata[5] = { _NET_WM_STATE_ADD };
  255. if(XGetWindowProperty(W->dpy, c->win, W->net_atom[net_wm_window_type], 0L, 0x7FFFFFFFL,
  256. False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
  257. {
  258. atom = (Atom*)data;
  259. for(i = 0; i < n; ++i)
  260. {
  261. /* MANAGE _NET_WM_WINDOW_TYPE_DIALOG */
  262. if(atom[i] == W->net_atom[net_wm_window_type_dialog])
  263. c->flags |= CLIENT_FREE;
  264. }
  265. XFree(data);
  266. }
  267. /* _NET_WM_STATE at window mangement */
  268. if(XGetWindowProperty(W->dpy, c->win, W->net_atom[net_wm_state], 0L, 0x7FFFFFFFL, false,
  269. XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
  270. {
  271. atom = (Atom*)data;
  272. for(i = 0; i < n; ++i)
  273. {
  274. ldata[1] = atom[i];
  275. ewmh_manage_state(ldata, c);
  276. }
  277. XFree(data);
  278. }
  279. }
  280. bool
  281. ewmh_manage_window_type_desktop(Window win)
  282. {
  283. Atom *atom, rf;
  284. int f;
  285. unsigned long n, il, i;
  286. unsigned char *data = NULL;
  287. bool is_desktop = false;
  288. if(XGetWindowProperty(W->dpy, win, W->net_atom[net_wm_window_type], 0L, 0x7FFFFFFF,
  289. False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
  290. {
  291. atom = (Atom*)data;
  292. for(i = 0; i < n; ++i)
  293. {
  294. /* If it is a _NET_WM_WINDOW_TYPE_DESKTOP window */
  295. if(atom[i] == W->net_atom[net_wm_window_type_desktop])
  296. {
  297. /* map it, but don't manage it */
  298. XMapWindow(W->dpy, win);
  299. XMapSubwindows(W->dpy, win);
  300. is_desktop = true;
  301. break;
  302. }
  303. }
  304. XFree(data);
  305. }
  306. return is_desktop;
  307. }