i3 - improved tiling WM


Implement EWMH desktop names

Patch status: needinfo

Patch by Tony Crisci

Long description:

Maintain the _NET_DESKTOP_NAMES property on the root window.

http://standards.freedesktop.org/wm-spec/latest/ar01s03.html#idm140251368131760

> _NET_DESKTOP_NAMES
>
> _NET_DESKTOP_NAMES, UTF8_STRING[]
>
> The names of all virtual desktops. This is a list of NULL-terminated
> strings in UTF-8 encoding [UTF8]. This property MAY be changed by a
> Pager or the Window Manager at any time.

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

b/include/atoms.xmacro

29
@@ -17,6 +17,7 @@ xmacro(_NET_CLIENT_LIST)
30
 xmacro(_NET_CLIENT_LIST_STACKING)
31
 xmacro(_NET_CURRENT_DESKTOP)
32
 xmacro(_NET_NUMBER_OF_DESKTOPS)
33
+xmacro(_NET_DESKTOP_NAMES)
34
 xmacro(_NET_ACTIVE_WINDOW)
35
 xmacro(_NET_STARTUP_ID)
36
 xmacro(_NET_WORKAREA)

b/include/ewmh.h

41
@@ -25,6 +25,12 @@ void ewmh_update_current_desktop(void);
42
 void ewmh_update_number_of_desktops(void);
43
 
44
 /**
45
+ * Updates _NET_DESKTOP_NAMES: "The names of all virtual desktops. This is a
46
+ * list of NULL-terminated strings in UTF-8 encoding"
47
+ */
48
+void ewmh_update_desktop_names(void);
49
+
50
+/**
51
  * Updates _NET_ACTIVE_WINDOW with the currently focused window.
52
  *
53
  * EWMH: The window ID of the currently active window or None if no window has

b/src/commands.c

58
@@ -1948,6 +1948,8 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) {
59
     ysuccess(true);
60
 
61
     ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"rename\"}");
62
+    ewmh_update_desktop_names();
63
+    ewmh_update_current_desktop();
64
 }
65
 
66
 /*

b/src/ewmh.c

71
@@ -62,6 +62,45 @@ void ewmh_update_number_of_desktops(void) {
72
 }
73
 
74
 /*
75
+ * Updates _NET_DESKTOP_NAMES: "The names of all virtual desktops. This is a
76
+ * list of NULL-terminated strings in UTF-8 encoding"
77
+ */
78
+void ewmh_update_desktop_names(void) {
79
+    Con *output;
80
+    int msg_length = 0;
81
+
82
+    /* count the size of the property message to set */
83
+    TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
84
+        Con *ws;
85
+        TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) {
86
+            if (STARTS_WITH(ws->name, "__"))
87
+                continue;
88
+            msg_length += strlen(ws->name) + 1;
89
+        }
90
+    }
91
+
92
+    char desktop_names[msg_length];
93
+    int current_position = 0;
94
+
95
+    /* fill the buffer with the names of the i3 workspaces */
96
+    TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
97
+        Con *ws;
98
+        TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) {
99
+            if (STARTS_WITH(ws->name, "__"))
100
+                continue;
101
+
102
+            for (int i = 0; i < strlen(ws->name) + 1; i++) {
103
+                desktop_names[current_position] = ws->name[i];
104
+                current_position += 1;
105
+            }
106
+        }
107
+    }
108
+
109
+    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root,
110
+                        A__NET_DESKTOP_NAMES, A_UTF8_STRING, 8, msg_length, desktop_names);
111
+}
112
+
113
+/*
114
  * Updates _NET_ACTIVE_WINDOW with the currently focused window.
115
  *
116
  * EWMH: The window ID of the currently active window or None if no window has
117
@@ -159,5 +198,5 @@ void ewmh_setup_hints(void) {
118
     /* I’m not entirely sure if we need to keep _NET_WM_NAME on root. */
119
     xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3");
120
 
121
-    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 19, supported_atoms);
122
+    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 20, supported_atoms);
123
 }

b/src/main.c

128
@@ -768,6 +768,7 @@ int main(int argc, char *argv[]) {
129
     /* Set the ewmh desktop properties. */
130
     ewmh_update_current_desktop();
131
     ewmh_update_number_of_desktops();
132
+    ewmh_update_desktop_names();
133
 
134
     struct ev_io *xcb_watcher = scalloc(sizeof(struct ev_io));
135
     struct ev_io *xkb = scalloc(sizeof(struct ev_io));

b/src/workspace.c

140
@@ -93,6 +93,7 @@ Con *workspace_get(const char *num, bool *created) {
141
 
142
         ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}");
143
         ewmh_update_number_of_desktops();
144
+        ewmh_update_desktop_names();
145
         if (created != NULL)
146
             *created = true;
147
     } else if (created != NULL) {
148
@@ -426,6 +427,7 @@ static void _workspace_show(Con *workspace) {
149
             tree_close(old, DONT_KILL_WINDOW, false, false);
150
             ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"empty\"}");
151
             ewmh_update_number_of_desktops();
152
+            ewmh_update_desktop_names();
153
         }
154
     }
155