i3 - improved tiling WM


Add IPC event for window title changes

Patch status: superseded

Patch by Marco Hunsicker

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

b/include/i3/ipc.h

17
@@ -100,3 +100,6 @@ typedef struct i3_ipc_header {
18
 
19
 /** Bar config update will be triggered to update the bar config */
20
 #define I3_IPC_EVENT_BARCONFIG_UPDATE           (I3_IPC_EVENT_MASK | 4)
21
+
22
+/* The window title event will be triggered upon window title changes */
23
+#define I3_IPC_EVENT_WINDOW_TITLE               (I3_IPC_EVENT_MASK | 5)

b/include/ipc.h

28
@@ -87,3 +87,9 @@ void dump_node(yajl_gen gen, Con *con, bool inplace_restart);
29
  * respectively.
30
  */
31
 void ipc_send_workspace_focus_event(Con *current, Con *old);
32
+
33
+/*
34
+ * For the window "window_title" event we send, along the usual "change" field,
35
+ * also the changed title, in "title".
36
+ */
37
+void ipc_send_window_title_event(Con *current);

b/src/con.c

42
@@ -213,6 +213,8 @@ void con_focus(Con *con) {
43
     assert(con != NULL);
44
     DLOG("con_focus = %p\n", con);
45
 
46
+    bool already_focused = (con == focused);
47
+
48
     /* 1: set focused-pointer to the new con */
49
     /* 2: exchange the position of the container in focus stack of the parent all the way up */
50
     TAILQ_REMOVE(&(con->parent->focus_head), con, focused);
51
@@ -221,15 +223,22 @@ void con_focus(Con *con) {
52
         con_focus(con->parent);
53
 
54
     focused = con;
55
-    /* We can't blindly reset non-leaf containers since they might have
56
-     * other urgent children. Therefore we only reset leafs and propagate
57
-     * the changes upwards via con_update_parents_urgency() which does proper
58
-     * checks before resetting the urgency.
59
-     */
60
-    if (con->urgent && con_is_leaf(con)) {
61
-        con->urgent = false;
62
-        con_update_parents_urgency(con);
63
-        workspace_update_urgent_flag(con_get_workspace(con));
64
+
65
+    if (con_is_leaf(con))
66
+    {
67
+        if (!already_focused)
68
+            ipc_send_window_title_event(con);
69
+
70
+        /* We can't blindly reset non-leaf containers since they might have
71
+         * other urgent children. Therefore we only reset leafs and propagate
72
+         * the changes upwards via con_update_parents_urgency() which does proper
73
+         * checks before resetting the urgency.
74
+         */
75
+        if (con->urgent) {
76
+            con->urgent = false;
77
+            con_update_parents_urgency(con);
78
+            workspace_update_urgent_flag(con_get_workspace(con));
79
+        }
80
     }
81
 }
82
 

b/src/handlers.c

87
@@ -540,6 +540,8 @@ static bool handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t
88
 
89
     window_update_name(con->window, prop, false);
90
 
91
+    ipc_send_window_title_event(con);
92
+
93
     x_push_changes(croot);
94
 
95
     return true;
96
@@ -558,6 +560,8 @@ static bool handle_windowname_change_legacy(void *data, xcb_connection_t *conn,
97
 
98
     window_update_name_legacy(con->window, prop, false);
99
 
100
+    ipc_send_window_title_event(con);
101
+
102
     x_push_changes(croot);
103
 
104
     return true;

b/src/ipc.c

109
@@ -21,6 +21,7 @@
110
 #include <yajl/yajl_parse.h>
111
 
112
 char *current_socketpath = NULL;
113
+char *current_windowtitle = NULL;
114
 
115
 TAILQ_HEAD(ipc_client_head, ipc_client) all_clients = TAILQ_HEAD_INITIALIZER(all_clients);
116
 
117
@@ -1056,3 +1057,43 @@ void ipc_send_workspace_focus_event(Con *current, Con *old) {
118
     y(free);
119
     setlocale(LC_NUMERIC, "");
120
 }
121
+
122
+const char* get_window_title(Con *con) {
123
+    return (con != NULL && con->window != NULL && con->window->name != NULL) ? i3string_as_utf8(con->window->name) : "";
124
+}
125
+
126
+void ipc_send_window_title_event(Con *con) {
127
+    const char* title = get_window_title(con);
128
+
129
+    if (con != focused || (current_windowtitle != NULL && strcmp(current_windowtitle, title) == 0)) {
130
+        return;
131
+    }
132
+
133
+    FREE(current_windowtitle);
134
+
135
+    current_windowtitle = strdup(title);
136
+
137
+    setlocale(LC_NUMERIC, "C");
138
+    yajl_gen gen = ygenalloc();
139
+
140
+    y(map_open);
141
+
142
+    ystr("change");
143
+    ystr("window_title");
144
+
145
+    ystr("title");
146
+    ystr(title);
147
+
148
+    ystr("current");
149
+    dump_node(gen, con, false);
150
+
151
+    y(map_close);
152
+
153
+    const unsigned char *payload;
154
+    ylength length;
155
+    y(get_buf, &payload, &length);
156
+
157
+    ipc_send_event("window_title", I3_IPC_EVENT_WINDOW_TITLE, (const char *)payload);
158
+    y(free);
159
+    setlocale(LC_NUMERIC, "");
160
+}