]> git.sur5r.net Git - i3/i3/blobdiff - src/handlers.c
Handle WM_CHANGE_STATE requests for iconic state
[i3/i3] / src / handlers.c
index ba9b12117ad53a1727f164783b8ba8df3552985d..5d21a9855b0031a577342b9cd1acf78e9ae7829b 100644 (file)
@@ -21,6 +21,8 @@
 #include <libsn/sn-monitor.h>
 
 int randr_base = -1;
+int xkb_base = -1;
+int xkb_current_group;
 
 /* After mapping/unmapping windows, a notify event is generated. However, we don’t want it,
    since it’d trigger an infinite loop of switching between the different windows when
@@ -282,7 +284,6 @@ static void handle_map_request(xcb_map_request_event_t *event) {
     add_ignore_event(event->sequence, -1);
 
     manage_window(event->window, cookie, false);
-    x_push_changes(croot);
     return;
 }
 
@@ -487,7 +488,6 @@ static void handle_unmap_notify_event(xcb_unmap_notify_event_t *event) {
 
     tree_close(con, DONT_KILL_WINDOW, false, false);
     tree_render();
-    x_push_changes(croot);
 
 ignore_end:
     /* If the client (as opposed to i3) destroyed or unmapped a window, an
@@ -791,6 +791,21 @@ static void handle_client_message(xcb_client_message_event_t *event) {
             XCB_ATOM_CARDINAL, 32, 4,
             &r);
         xcb_flush(conn);
+    } else if (event->type == A_WM_CHANGE_STATE) {
+        /* http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.4 */
+        Con *con = con_by_window_id(event->window);
+
+        if (con && event->data.data32[0] == 3) {
+            /* this request is so we can play some animiation showing the
+             * window physically moving to the tray before we close it (I
+             * think) */
+            DLOG("Client has requested iconic state. Closing this con. (con = %p)\n", con);
+            tree_close(con, DONT_KILL_WINDOW, false, false);
+            tree_render();
+        } else {
+            DLOG("Not handling WM_CHANGE_STATE request. (window = %d, state = %d)\n", event->window, event->data.data32[0]);
+        }
+
     } else {
         DLOG("unhandled clientmessage\n");
         return;
@@ -1115,12 +1130,50 @@ static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom)
  *
  */
 void handle_event(int type, xcb_generic_event_t *event) {
+    DLOG("event type %d, xkb_base %d\n", type, xkb_base);
     if (randr_base > -1 &&
         type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
         handle_screen_change(event);
         return;
     }
 
+    if (xkb_base > -1 && type == xkb_base) {
+        DLOG("xkb event, need to handle it.\n");
+
+        xcb_xkb_state_notify_event_t *state = (xcb_xkb_state_notify_event_t *)event;
+        if (state->xkbType == XCB_XKB_MAP_NOTIFY) {
+            if (event_is_ignored(event->sequence, type)) {
+                DLOG("Ignoring map notify event for sequence %d.\n", state->sequence);
+            } else {
+                DLOG("xkb map notify, sequence %d, time %d\n", state->sequence, state->time);
+                add_ignore_event(event->sequence, type);
+                ungrab_all_keys(conn);
+                translate_keysyms();
+                grab_all_keys(conn, false);
+            }
+        } else if (state->xkbType == XCB_XKB_STATE_NOTIFY) {
+            DLOG("xkb state group = %d\n", state->group);
+
+            /* See The XKB Extension: Library Specification, section 14.1 */
+            /* We check if the current group (each group contains
+             * two levels) has been changed. Mode_switch activates
+             * group XkbGroup2Index */
+            if (xkb_current_group == state->group)
+                return;
+            xkb_current_group = state->group;
+            if (state->group == XCB_XKB_GROUP_1) {
+                DLOG("Mode_switch disabled\n");
+                ungrab_all_keys(conn);
+                grab_all_keys(conn, false);
+            } else {
+                DLOG("Mode_switch enabled\n");
+                grab_all_keys(conn, false);
+            }
+        }
+
+        return;
+    }
+
     switch (type) {
         case XCB_KEY_PRESS:
         case XCB_KEY_RELEASE: