]> git.sur5r.net Git - i3/i3/blobdiff - src/handlers.c
Merge branch 'fix-active'
[i3/i3] / src / handlers.c
index 7fa29e126f0944cfdf0d821c7975bc05c0a4c2fe..fce6627659487199dfe66f1286c4e3da406d6686 100644 (file)
@@ -13,6 +13,7 @@
 #include "all.h"
 
 #include <time.h>
+#include <float.h>
 #include <sys/time.h>
 #include <xcb/randr.h>
 #include <X11/XKBlib.h>
@@ -158,7 +159,7 @@ static void handle_enter_notify(xcb_enter_notify_event_t *event) {
     }
 
     /* see if the user entered the window on a certain window decoration */
-    int layout = (enter_child ? con->parent->layout : con->layout);
+    layout_t layout = (enter_child ? con->parent->layout : con->layout);
     if (layout == L_DEFAULT) {
         Con *child;
         TAILQ_FOREACH(child, &(con->nodes_head), nodes)
@@ -339,7 +340,7 @@ static void handle_configure_request(xcb_configure_request_event_t *event) {
 
     if (fullscreen != con && con_is_floating(con) && con_is_leaf(con)) {
         /* find the height for the decorations */
-        int deco_height = config.font.height + 5;
+        int deco_height = con->deco_rect.height;
         /* we actually need to apply the size/position changes to the *parent*
          * container */
         Rect bsr = con_border_style_rect(con);
@@ -349,6 +350,11 @@ static void handle_configure_request(xcb_configure_request_event_t *event) {
         }
         Con *floatingcon = con->parent;
 
+        if (strcmp(con_get_workspace(floatingcon)->name, "__i3_scratch") == 0) {
+            DLOG("This is a scratchpad container, ignoring ConfigureRequest\n");
+            return;
+        }
+
         Rect newrect = floatingcon->rect;
 
         if (event->value_mask & XCB_CONFIG_WINDOW_X) {
@@ -417,6 +423,19 @@ int handle_configure_event(void *prophs, xcb_connection_t *conn, xcb_configure_n
 static void handle_screen_change(xcb_generic_event_t *e) {
     DLOG("RandR screen change\n");
 
+    /* The geometry of the root window is used for “fullscreen global” and
+     * changes when new outputs are added. */
+    xcb_get_geometry_cookie_t cookie = xcb_get_geometry(conn, root);
+    xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(conn, cookie, NULL);
+    if (reply == NULL) {
+        ELOG("Could not get geometry of the root window, exiting\n");
+        exit(1);
+    }
+    DLOG("root geometry reply: (%d, %d) %d x %d\n", reply->x, reply->y, reply->width, reply->height);
+
+    croot->rect.width = reply->width;
+    croot->rect.height = reply->height;
+
     randr_query_outputs();
 
     scratchpad_fix_resolution();
@@ -614,10 +633,10 @@ static void handle_client_message(xcb_client_message_event_t *event) {
 
     LOG("ClientMessage for window 0x%08x\n", event->window);
     if (event->type == A__NET_WM_STATE) {
-        if (event->format != 32 || event->data.data32[1] != A__NET_WM_STATE_FULLSCREEN) {
-            DLOG("atom in clientmessage is %d, fullscreen is %d\n",
-                    event->data.data32[1], A__NET_WM_STATE_FULLSCREEN);
-            DLOG("not about fullscreen atom\n");
+        if (event->format != 32 ||
+            (event->data.data32[1] != A__NET_WM_STATE_FULLSCREEN &&
+             event->data.data32[1] != A__NET_WM_STATE_DEMANDS_ATTENTION)) {
+            DLOG("Unknown atom in clientmessage of type %d\n", event->data.data32[1]);
             return;
         }
 
@@ -627,15 +646,25 @@ static void handle_client_message(xcb_client_message_event_t *event) {
             return;
         }
 
-        /* Check if the fullscreen state should be toggled */
-        if ((con->fullscreen_mode != CF_NONE &&
-             (event->data.data32[0] == _NET_WM_STATE_REMOVE ||
-              event->data.data32[0] == _NET_WM_STATE_TOGGLE)) ||
-            (con->fullscreen_mode == CF_NONE &&
-             (event->data.data32[0] == _NET_WM_STATE_ADD ||
-              event->data.data32[0] == _NET_WM_STATE_TOGGLE))) {
-            DLOG("toggling fullscreen\n");
-            con_toggle_fullscreen(con, CF_OUTPUT);
+        if (event->data.data32[1] == A__NET_WM_STATE_FULLSCREEN) {
+            /* Check if the fullscreen state should be toggled */
+            if ((con->fullscreen_mode != CF_NONE &&
+                 (event->data.data32[0] == _NET_WM_STATE_REMOVE ||
+                  event->data.data32[0] == _NET_WM_STATE_TOGGLE)) ||
+                (con->fullscreen_mode == CF_NONE &&
+                 (event->data.data32[0] == _NET_WM_STATE_ADD ||
+                  event->data.data32[0] == _NET_WM_STATE_TOGGLE))) {
+                DLOG("toggling fullscreen\n");
+                con_toggle_fullscreen(con, CF_OUTPUT);
+            }
+        } else if (event->data.data32[1] == A__NET_WM_STATE_DEMANDS_ATTENTION) {
+            /* Check if the urgent flag must be set or not */
+            if (event->data.data32[0] == _NET_WM_STATE_ADD)
+                con_set_urgency(con, true);
+            else if (event->data.data32[0] == _NET_WM_STATE_REMOVE)
+                con_set_urgency(con, false);
+            else if (event->data.data32[0] == _NET_WM_STATE_TOGGLE)
+                con_set_urgency(con, !con->urgent);
         }
 
         tree_render();
@@ -653,6 +682,11 @@ static void handle_client_message(xcb_client_message_event_t *event) {
             return;
         }
 
+        if (con_is_internal(ws)) {
+            DLOG("Workspace is internal, ignoring _NET_ACTIVE_WINDOW\n");
+            return;
+        }
+
         if (ws != con_get_workspace(focused))
             workspace_show(ws);
 
@@ -676,6 +710,36 @@ static void handle_client_message(xcb_client_message_event_t *event) {
         xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char*)ev);
         xcb_flush(conn);
         free(reply);
+    } else if (event->type == A__NET_REQUEST_FRAME_EXTENTS) {
+        /*
+         * A client can request an estimate for the frame size which the window
+         * manager will put around it before actually mapping its window. Java
+         * does this (as of openjdk-7).
+         *
+         * Note that the calculation below is not entirely accurate — once you
+         * set a different border type, it’s off. We _could_ request all the
+         * window properties (which have to be set up at this point according
+         * to EWMH), but that seems rather elaborate. The standard explicitly
+         * says the application must cope with an estimate that is not entirely
+         * accurate.
+         */
+        DLOG("_NET_REQUEST_FRAME_EXTENTS for window 0x%08x\n", event->window);
+
+        /* The reply data: approximate frame size */
+        Rect r = {
+            config.default_border_width, /* left */
+            config.default_border_width, /* right */
+            config.font.height + 5, /* top */
+            config.default_border_width /* bottom */
+        };
+        xcb_change_property(
+                conn,
+                XCB_PROP_MODE_REPLACE,
+                event->window,
+                A__NET_FRAME_EXTENTS,
+                XCB_ATOM_CARDINAL, 32, 4,
+                &r);
+        xcb_flush(conn);
     } else {
         DLOG("unhandled clientmessage\n");
         return;
@@ -784,22 +848,18 @@ static bool handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t stat
         goto render_and_return;
 
     /* Check if we need to set proportional_* variables using the correct ratio */
+    double aspect_ratio = 0.0;
     if ((width / height) < min_aspect) {
-        if (con->proportional_width != width ||
-            con->proportional_height != (width / min_aspect)) {
-            con->proportional_width = width;
-            con->proportional_height = width / min_aspect;
-            changed = true;
-        }
+        aspect_ratio = min_aspect;
     } else if ((width / height) > max_aspect) {
-        if (con->proportional_width != width ||
-            con->proportional_height != (width / max_aspect)) {
-            con->proportional_width = width;
-            con->proportional_height = width / max_aspect;
-            changed = true;
-        }
+        aspect_ratio = max_aspect;
     } else goto render_and_return;
 
+    if (fabs(con->aspect_ratio - aspect_ratio) > DBL_EPSILON) {
+        con->aspect_ratio = aspect_ratio;
+        changed = true;
+    }
+
 render_and_return:
     if (changed)
         tree_render();
@@ -819,56 +879,13 @@ static bool handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_
         return false;
     }
 
-    xcb_icccm_wm_hints_t hints;
-
+    bool urgency_hint;
     if (reply == NULL)
-        if (!(reply = xcb_get_property_reply(conn, xcb_icccm_get_wm_hints(conn, window), NULL)))
-            return false;
-
-    if (!xcb_icccm_get_wm_hints_from_reply(&hints, reply))
-        return false;
-
-    if (!con->urgent && focused == con) {
-        DLOG("Ignoring urgency flag for current client\n");
-        con->window->urgent.tv_sec = 0;
-        con->window->urgent.tv_usec = 0;
-        goto end;
-    }
-
-    /* Update the flag on the client directly */
-    bool hint_urgent = (xcb_icccm_wm_hints_get_urgency(&hints) != 0);
-
-    if (con->urgency_timer == NULL) {
-        con->urgent = hint_urgent;
-    } else
-        DLOG("Discarding urgency WM_HINT because timer is running\n");
-
-    //CLIENT_LOG(con);
-    if (con->window) {
-        if (con->urgent) {
-            gettimeofday(&con->window->urgent, NULL);
-        } else {
-            con->window->urgent.tv_sec = 0;
-            con->window->urgent.tv_usec = 0;
-        }
-    }
-
-    con_update_parents_urgency(con);
-
-    LOG("Urgency flag changed to %d\n", con->urgent);
-
-    Con *ws;
-    /* Set the urgency flag on the workspace, if a workspace could be found
-     * (for dock clients, that is not the case). */
-    if ((ws = con_get_workspace(con)) != NULL)
-        workspace_update_urgent_flag(ws);
-
+        reply = xcb_get_property_reply(conn, xcb_icccm_get_wm_hints(conn, window), NULL);
+    window_update_hints(con->window, reply, &urgency_hint);
+    con_set_urgency(con, urgency_hint);
     tree_render();
 
-end:
-    if (con->window)
-        window_update_hints(con->window, reply);
-    else free(reply);
     return true;
 }
 
@@ -1089,7 +1106,7 @@ void handle_event(int type, xcb_generic_event_t *event) {
 
         /* Client message are sent to the root window. The only interesting
          * client message for us is _NET_WM_STATE, we honour
-         * _NET_WM_STATE_FULLSCREEN */
+         * _NET_WM_STATE_FULLSCREEN and _NET_WM_STATE_DEMANDS_ATTENTION */
         case XCB_CLIENT_MESSAGE:
             handle_client_message((xcb_client_message_event_t*)event);
             break;