+ } else if (event->type == A__NET_CURRENT_DESKTOP) {
+ /* This request is used by pagers and bars to change the current
+ * desktop likely as a result of some user action. We interpret this as
+ * a request to focus the given workspace. See
+ * http://standards.freedesktop.org/wm-spec/latest/ar01s03.html#idm140251368135008
+ * */
+ Con *output;
+ uint32_t idx = 0;
+ DLOG("Request to change current desktop to index %d\n", event->data.data32[0]);
+
+ TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
+ Con *ws;
+ TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) {
+ if (STARTS_WITH(ws->name, "__"))
+ continue;
+
+ if (idx == event->data.data32[0]) {
+ /* data32[1] is a timestamp used to prevent focus race conditions */
+ if (event->data.data32[1])
+ last_timestamp = event->data.data32[1];
+
+ DLOG("Handling request to focus workspace %s\n", ws->name);
+
+ workspace_show(ws);
+ tree_render();
+
+ return;
+ }
+
+ ++idx;
+ }
+ }
+ } else if (event->type == A__NET_CLOSE_WINDOW) {
+ /*
+ * Pagers wanting to close a window MUST send a _NET_CLOSE_WINDOW
+ * client message request to the root window.
+ * http://standards.freedesktop.org/wm-spec/wm-spec-latest.html#idm140200472668896
+ */
+ Con *con = con_by_window_id(event->window);
+ if (con) {
+ DLOG("Handling _NET_CLOSE_WINDOW request (con = %p)\n", con);
+
+ if (event->data.data32[0])
+ last_timestamp = event->data.data32[0];
+
+ tree_close(con, KILL_WINDOW, false, false);
+ tree_render();
+ } else {
+ DLOG("Couldn't find con for _NET_CLOSE_WINDOW request. (window = %d)\n", event->window);
+ }
+ } else if (event->type == A__NET_WM_MOVERESIZE) {
+ /*
+ * Client-side decorated Gtk3 windows emit this signal when being
+ * dragged by their GtkHeaderBar
+ */
+ Con *con = con_by_window_id(event->window);
+ if (!con || !con_is_floating(con)) {
+ DLOG("Couldn't find con for _NET_WM_MOVERESIZE request, or con not floating (window = %d)\n", event->window);
+ return;
+ }
+ DLOG("Handling _NET_WM_MOVERESIZE request (con = %p)\n", con);
+ uint32_t direction = event->data.data32[2];
+ uint32_t x_root = event->data.data32[0];
+ uint32_t y_root = event->data.data32[1];
+ /* construct fake xcb_button_press_event_t */
+ xcb_button_press_event_t fake = {
+ .root_x = x_root,
+ .root_y = y_root,
+ .event_x = x_root - (con->rect.x),
+ .event_y = y_root - (con->rect.y)};
+ if (direction == _NET_WM_MOVERESIZE_MOVE) {
+ floating_drag_window(con->parent, &fake);
+ } else if (direction >= _NET_WM_MOVERESIZE_SIZE_TOPLEFT && direction <= _NET_WM_MOVERESIZE_SIZE_LEFT) {
+ floating_resize_window(con->parent, FALSE, &fake);
+ } else {
+ DLOG("_NET_WM_MOVERESIZE direction %d not implemented\n", direction);
+ }