i3 - improved tiling WM


Add support for _NET_WM_STATE_DEMANDS_ATTENTION.

Patch status: needinfo

Patch by oblique

Long description:

_NET_WM_STATE_DEMANDS_ATTENTION indicates that some action in or with
the window happened. It's a weaker hint than urgency flag of WM_HINTS,
but some applications and almost all Qt applications use it instead of
WM_HINTS' urgency flag (one example is Skype).

To apply this patch, use:
curl http://cr.i3wm.org/patch/60/raw.patch | git am

b/docs/hacking-howto

19
@@ -28,7 +28,8 @@ In the case of i3, the tasks (and order of them) are the following:
20
   the first client of X) and manage them (reparent them, create window
21
   decorations, etc.)
22
 . When new windows are created, manage them
23
-. Handle the client’s `_WM_STATE` property, but only the `_WM_STATE_FULLSCREEN`
24
+. Handle the client’s `_WM_STATE` property, but only `_WM_STATE_FULLSCREEN` and
25
+  `_NET_WM_STATE_DEMANDS_ATTENTION`
26
 . Handle the client’s `WM_NAME` property
27
 . Handle the client’s size hints to display them proportionally
28
 . Handle the client’s urgency hint

b/include/atoms.xmacro

33
@@ -2,6 +2,7 @@ xmacro(_NET_SUPPORTED)
34
 xmacro(_NET_SUPPORTING_WM_CHECK)
35
 xmacro(_NET_WM_NAME)
36
 xmacro(_NET_WM_STATE_FULLSCREEN)
37
+xmacro(_NET_WM_STATE_DEMANDS_ATTENTION)
38
 xmacro(_NET_WM_STATE)
39
 xmacro(_NET_WM_WINDOW_TYPE)
40
 xmacro(_NET_WM_WINDOW_TYPE_DOCK)

b/src/handlers.c

45
@@ -619,10 +619,10 @@ static void handle_client_message(xcb_client_message_event_t *event) {
46
 
47
     LOG("ClientMessage for window 0x%08x\n", event->window);
48
     if (event->type == A__NET_WM_STATE) {
49
-        if (event->format != 32 || event->data.data32[1] != A__NET_WM_STATE_FULLSCREEN) {
50
-            DLOG("atom in clientmessage is %d, fullscreen is %d\n",
51
-                    event->data.data32[1], A__NET_WM_STATE_FULLSCREEN);
52
-            DLOG("not about fullscreen atom\n");
53
+        if (event->format != 32 ||
54
+            (event->data.data32[1] != A__NET_WM_STATE_FULLSCREEN &&
55
+             event->data.data32[1] != A__NET_WM_STATE_DEMANDS_ATTENTION)) {
56
+            DLOG("Unknown atom in clientmessage of type %d\n", event->data.data32[1]);
57
             return;
58
         }
59
 
60
@@ -632,15 +632,52 @@ static void handle_client_message(xcb_client_message_event_t *event) {
61
             return;
62
         }
63
 
64
-        /* Check if the fullscreen state should be toggled */
65
-        if ((con->fullscreen_mode != CF_NONE &&
66
-             (event->data.data32[0] == _NET_WM_STATE_REMOVE ||
67
-              event->data.data32[0] == _NET_WM_STATE_TOGGLE)) ||
68
-            (con->fullscreen_mode == CF_NONE &&
69
-             (event->data.data32[0] == _NET_WM_STATE_ADD ||
70
-              event->data.data32[0] == _NET_WM_STATE_TOGGLE))) {
71
-            DLOG("toggling fullscreen\n");
72
-            con_toggle_fullscreen(con, CF_OUTPUT);
73
+        if (event->data.data32[1] == A__NET_WM_STATE_FULLSCREEN) {
74
+            /* Check if the fullscreen state should be toggled */
75
+            if ((con->fullscreen_mode != CF_NONE &&
76
+                 (event->data.data32[0] == _NET_WM_STATE_REMOVE ||
77
+                  event->data.data32[0] == _NET_WM_STATE_TOGGLE)) ||
78
+                (con->fullscreen_mode == CF_NONE &&
79
+                 (event->data.data32[0] == _NET_WM_STATE_ADD ||
80
+                  event->data.data32[0] == _NET_WM_STATE_TOGGLE))) {
81
+                DLOG("toggling fullscreen\n");
82
+                con_toggle_fullscreen(con, CF_OUTPUT);
83
+            }
84
+        } else if (event->data.data32[1] == A__NET_WM_STATE_DEMANDS_ATTENTION) {
85
+            bool urgent;
86
+
87
+            /* Check if the urgent flag must be set */
88
+            if (event->data.data32[0] == _NET_WM_STATE_ADD)
89
+                urgent = true;
90
+            else if (event->data.data32[0] == _NET_WM_STATE_REMOVE)
91
+                urgent = false;
92
+            else if (event->data.data32[0] == _NET_WM_STATE_TOGGLE)
93
+                urgent = !con->urgent;
94
+
95
+            if (con->urgency_timer == NULL) {
96
+                con->urgent = urgent;
97
+            } else
98
+                DLOG("Discarding urgency WM_HINT because timer is running\n");
99
+
100
+            //CLIENT_LOG(con);
101
+            if (con->window) {
102
+                if (con->urgent) {
103
+                    gettimeofday(&con->window->urgent, NULL);
104
+                } else {
105
+                    con->window->urgent.tv_sec = 0;
106
+                    con->window->urgent.tv_usec = 0;
107
+                }
108
+            }
109
+
110
+            con_update_parents_urgency(con);
111
+
112
+            LOG("Urgency flag changed to %d\n", con->urgent);
113
+
114
+            Con *ws;
115
+            /* Set the urgency flag on the workspace, if a workspace could be found
116
+             * (for dock clients, that is not the case). */
117
+            if ((ws = con_get_workspace(con)) != NULL)
118
+                workspace_update_urgent_flag(ws);
119
         }
120
 
121
         tree_render();
122
@@ -1094,7 +1131,7 @@ void handle_event(int type, xcb_generic_event_t *event) {
123
 
124
         /* Client message are sent to the root window. The only interesting
125
          * client message for us is _NET_WM_STATE, we honour
126
-         * _NET_WM_STATE_FULLSCREEN */
127
+         * _NET_WM_STATE_FULLSCREEN and _NET_WM_STATE_DEMANDS_ATTENTION */
128
         case XCB_CLIENT_MESSAGE:
129
             handle_client_message((xcb_client_message_event_t*)event);
130
             break;