]> git.sur5r.net Git - i3/i3/commitdiff
Re-implement support for the urgency hint, extend t/13-urgent.t
authorMichael Stapelberg <michael@stapelberg.de>
Wed, 2 Jun 2010 15:51:58 +0000 (17:51 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Wed, 2 Jun 2010 15:55:10 +0000 (17:55 +0200)
The actual rendering will follow

include/data.h
include/handlers.h
include/workspace.h
src/con.c
src/handlers.c
src/ipc.c
src/nc.c
src/workspace.c
testcases/t/13-urgent.t

index def5d4b776394df5c593597a7ae68b7f34862c8d..f74f0d52d1faba271fc7d8c2b35dad3f78683997 100644 (file)
@@ -272,6 +272,10 @@ struct Con {
 
     struct Window *window;
 
+    /* Should this container be marked urgent? This gets set when the window
+     * inside this container (if any) sets the urgency hint, for example. */
+    bool urgent;
+
     /* ids/gc for the frame window */
     xcb_window_t frame;
     xcb_gcontext_t gc;
index 12d64c48edc958f75c99ea7280f657666e540f4f..73cafe4b42a44b4fd15eb0f1586ad08599ab9251 100644 (file)
@@ -171,12 +171,14 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state,
                         xcb_window_t window, xcb_atom_t name,
                         xcb_get_property_reply_t *reply);
 
+#endif
 /**
  * Handles the WM_HINTS property for extracting the urgency state of the window.
  *
  */
 int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
                   xcb_atom_t name, xcb_get_property_reply_t *reply);
+#if 0
 
 /**
  * Handles the transient for hints set by a window, signalizing that this
index 7a61daa83b10cdc51e25dca76e50527f0c9f9c79..28b7e571395fa8322496040121523e143dec2b60 100644 (file)
@@ -90,14 +90,16 @@ void workspace_unmap_clients(xcb_connection_t *conn, Workspace *u_ws);
  *
  */
 void workspace_map_clients(xcb_connection_t *conn, Workspace *ws);
+#endif
 
 /**
  * Goes through all clients on the given workspace and updates the workspace’s
  * urgent flag accordingly.
  *
  */
-void workspace_update_urgent_flag(Workspace *ws);
+void workspace_update_urgent_flag(Con *ws);
 
+#if 0
 /*
  * Returns the width of the workspace.
  *
index 411c8df6ae72cee9bdb2abc92bcc17df31e37aef..1922770819ab06652b4a825cf985e8ee643208b5 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -91,6 +91,10 @@ void con_focus(Con *con) {
         con_focus(con->parent);
 
     focused = con;
+    if (con->urgent) {
+        con->urgent = false;
+        workspace_update_urgent_flag(con_get_workspace(con));
+    }
 }
 
 /*
index 7613110c7b3fba8c6e2547efe3cd57b4a8c19752..990f7dd2b4b621b8a42506a34c9cd9c3975b1b93 100644 (file)
@@ -810,6 +810,7 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_w
 
         return 1;
 }
+#endif
 
 /*
  * Handles the WM_HINTS property for extracting the urgency state of the window.
@@ -817,46 +818,49 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_w
  */
 int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
                   xcb_atom_t name, xcb_get_property_reply_t *reply) {
-        Client *client = table_get(&by_child, window);
-        if (client == NULL) {
-                DLOG("Received WM_HINTS for unknown client\n");
-                return 1;
-        }
-        xcb_wm_hints_t hints;
+    Con *con = con_by_window_id(window);
+    if (con == NULL) {
+        DLOG("Received WM_HINTS for unknown client\n");
+        return 1;
+    }
 
-        if (reply != NULL) {
-                if (!xcb_get_wm_hints_from_reply(&hints, reply))
-                        return 1;
-        } else {
-                if (!xcb_get_wm_hints_reply(conn, xcb_get_wm_hints_unchecked(conn, client->child), &hints, NULL))
-                        return 1;
-        }
+    xcb_wm_hints_t hints;
 
-        Client *last_focused = SLIST_FIRST(&(c_ws->focus_stack));
-        if (!client->urgent && client == last_focused) {
-                DLOG("Ignoring urgency flag for current client\n");
-                return 1;
-        }
+    if (reply != NULL) {
+        if (!xcb_get_wm_hints_from_reply(&hints, reply))
+            return 1;
+    } else {
+        if (!xcb_get_wm_hints_reply(conn, xcb_get_wm_hints_unchecked(conn, con->window->id), &hints, NULL))
+            return 1;
+    }
 
-        /* Update the flag on the client directly */
-        client->urgent = (xcb_wm_hints_get_urgency(&hints) != 0);
-        CLIENT_LOG(client);
-        LOG("Urgency flag changed to %d\n", client->urgent);
+    if (!con->urgent && focused == con) {
+        DLOG("Ignoring urgency flag for current client\n");
+        return 1;
+    }
 
-        workspace_update_urgent_flag(client->workspace);
-        redecorate_window(conn, client);
+    /* Update the flag on the client directly */
+    con->urgent = (xcb_wm_hints_get_urgency(&hints) != 0);
+    //CLIENT_LOG(con);
+    LOG("Urgency flag changed to %d\n", con->urgent);
 
-        /* If the workspace this client is on is not visible, we need to redraw
-         * the workspace bar */
-        if (!workspace_is_visible(client->workspace)) {
-                Output *output = client->workspace->output;
-                render_workspace(conn, output, output->current_workspace);
-                xcb_flush(conn);
-        }
+    workspace_update_urgent_flag(con_get_workspace(con));
 
-        return 1;
+#if 0
+    /* If the workspace this client is on is not visible, we need to redraw
+     * the workspace bar */
+    if (!workspace_is_visible(client->workspace)) {
+            Output *output = client->workspace->output;
+            render_workspace(conn, output, output->current_workspace);
+            xcb_flush(conn);
+    }
+#endif
+
+    return 1;
 }
 
+#if 0
+
 /*
  * Handles the transient for hints set by a window, signalizing that this window is a popup window
  * for some other window.
index 1ca0778bf1b366db8025f03ae6adec207d5c1fcd..bde2485216da8d152dbcfac35aa7a197ef8ba92c 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -137,6 +137,9 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
         ystr("orientation");
         y(integer, con->orientation);
 
+        ystr("urgent");
+        y(integer, con->urgent);
+
         ystr("layout");
         y(integer, con->layout);
 
index ac8590afa3068111e08df151d7b2979827904616..a5769d170812b6f045ab2a3858fecc19567945fa 100644 (file)
--- a/src/nc.c
+++ b/src/nc.c
@@ -2,6 +2,7 @@
  * vim:ts=4:sw=4:expandtab
  */
 #include <ev.h>
+#include <limits.h>
 #include "all.h"
 
 static int xkb_event_base;
@@ -254,6 +255,9 @@ int main(int argc, char *argv[]) {
     /* Watch _NET_WM_NAME (title of the window encoded in UTF-8) */
     xcb_property_set_handler(&prophs, atoms[_NET_WM_NAME], 128, handle_windowname_change, NULL);
 
+    /* Watch WM_HINTS (contains the urgent property) */
+    xcb_property_set_handler(&prophs, WM_HINTS, UINT_MAX, handle_hints, NULL);
+
     /* Watch WM_NAME (title of the window encoded in COMPOUND_TEXT) */
     xcb_watch_wm_name(&prophs, 128, handle_windowname_change_legacy, NULL);
 
index 17986bafd87f15bbd611ac8bb69dda866c45cf32..6a81f30e95f85495161514285ea91bdeac9ad7dc 100644 (file)
@@ -429,31 +429,37 @@ void workspace_unmap_clients(xcb_connection_t *conn, Workspace *u_ws) {
 
         ignore_enter_notify_forall(conn, u_ws, false);
 }
+#endif
+
+static bool get_urgency_flag(Con *con) {
+    Con *child;
+    TAILQ_FOREACH(child, &(con->nodes_head), nodes)
+        if (child->urgent || get_urgency_flag(child))
+            return true;
+
+    TAILQ_FOREACH(child, &(con->floating_head), floating_windows)
+        if (child->urgent || get_urgency_flag(child))
+            return true;
+
+    return false;
+}
 
 /*
  * Goes through all clients on the given workspace and updates the workspace’s
  * urgent flag accordingly.
  *
  */
-void workspace_update_urgent_flag(Workspace *ws) {
-        Client *current;
-        bool old_flag = ws->urgent;
-        bool urgent = false;
-
-        SLIST_FOREACH(current, &(ws->focus_stack), focus_clients) {
-                if (!current->urgent)
-                        continue;
+void workspace_update_urgent_flag(Con *ws) {
+    bool old_flag = ws->urgent;
+    ws->urgent = get_urgency_flag(ws);
+    DLOG("Workspace urgency flag changed from %d to %d\n", old_flag, ws->urgent);
 
-                urgent = true;
-                break;
-        }
-
-        ws->urgent = urgent;
-
-        if (old_flag != urgent)
-                ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"urgent\"}");
+    if (old_flag != ws->urgent)
+        ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"urgent\"}");
 }
 
+#if 0
+
 /*
  * Returns the width of the workspace.
  *
index cf847456f82a36582ce98856d622720a012a0a26..710d189242bd4add7dc0e275f6a17ca95e38f76a 100644 (file)
@@ -1,12 +1,10 @@
 #!perl
 # vim:ts=4:sw=4:expandtab
-# Beware that this test uses workspace 9 to perform some tests (it expects
-# the workspace to be empty).
-# TODO: skip it by default?
 
-use i3test tests => 7;
+use i3test tests => 10;
 use X11::XCB qw(:all);
 use Time::HiRes qw(sleep);
+use List::Util qw(first);
 
 BEGIN {
     use_ok('X11::XCB::Connection') or BAIL_OUT('Cannot load X11::XCB::Connection');
@@ -14,33 +12,68 @@ BEGIN {
 
 my $x = X11::XCB::Connection->new;
 
-my $i3 = i3;
-
-# Switch to the nineth workspace
-$i3->command('9')->recv;
+my $i3 = i3("/tmp/nestedcons");
+my $tmp = get_unused_workspace();
+$i3->command("workspace $tmp")->recv;
 
 #####################################################################
 # Create two windows and put them in stacking mode
 #####################################################################
 
+$i3->command('split v')->recv;
+
 my $top = i3test::open_standard_window($x);
-sleep 0.25;
 my $bottom = i3test::open_standard_window($x);
-sleep 0.25;
 
-$i3->command('s')->recv;
+my @urgent = grep { $_->{urgent} == 1 } @{get_ws_content($tmp)};
+is(@urgent, 0, 'no window got the urgent flag');
+
+#$i3->command('layout stacking')->recv;
 
 #####################################################################
 # Add the urgency hint, switch to a different workspace and back again
 #####################################################################
 $top->add_hint('urgency');
-sleep 1;
+sleep 0.5;
+
+@content = @{get_ws_content($tmp)};
+@urgent = grep { $_->{urgent} == 1 } @content;
+$top_info = first { $_->{window} == $top->id } @content;
+$bottom_info = first { $_->{window} == $bottom->id } @content;
+
+is($top_info->{urgent}, 1, 'top window is marked urgent');
+is($bottom_info->{urgent}, 0, 'bottom window is not marked urgent');
+is(@urgent, 1, 'exactly one window got the urgent flag');
+
+$i3->command('[id="' . $top->id . '"] focus')->recv;
+
+@urgent = grep { $_->{urgent} == 1 } @{get_ws_content($tmp)};
+is(@urgent, 0, 'no window got the urgent flag after focusing');
+
+$top->add_hint('urgency');
+sleep 0.5;
+
+@urgent = grep { $_->{urgent} == 1 } @{get_ws_content($tmp)};
+is(@urgent, 0, 'no window got the urgent flag after re-setting urgency hint');
+
+#####################################################################
+# Check if the workspace urgency hint gets set/cleared correctly
+#####################################################################
+my $ws = get_ws($tmp);
+is($ws->{urgent}, 0, 'urgent flag not set on workspace');
+
+my $otmp = get_unused_workspace();
+$i3->command("workspace $otmp")->recv;
+
+$top->add_hint('urgency');
+sleep 0.5;
+
+$ws = get_ws($tmp);
+is($ws->{urgent}, 1, 'urgent flag set on workspace');
+
+$i3->command("workspace $tmp")->recv;
 
-$i3->command('1')->recv;
-$i3->command('9')->recv;
-$i3->command('1')->recv;
+$ws = get_ws($tmp);
+is($ws->{urgent}, 0, 'urgent flag not set on workspace after switching');
 
-my $std = i3test::open_standard_window($x);
-sleep 0.25;
-$std->add_hint('urgency');
-sleep 1;
+diag( "Testing i3, Perl $], $^X" );