]> git.sur5r.net Git - i3/i3/blob - src/window.c
use I3__FILE__ for DLOG, leave __FILE__ as is
[i3/i3] / src / window.c
1 #undef I3__FILE__
2 #define I3__FILE__ "window.c"
3 /*
4  * vim:ts=4:sw=4:expandtab
5  *
6  * i3 - an improved dynamic tiling window manager
7  * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
8  *
9  * window.c: Updates window attributes (X11 hints/properties).
10  *
11  */
12 #include "all.h"
13
14 /*
15  * Updates the WM_CLASS (consisting of the class and instance) for the
16  * given window.
17  *
18  */
19 void window_update_class(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt) {
20     if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
21         DLOG("WM_CLASS not set.\n");
22         FREE(prop);
23         return;
24     }
25
26     /* We cannot use asprintf here since this property contains two
27      * null-terminated strings (for compatibility reasons). Instead, we
28      * use strdup() on both strings */
29     char *new_class = xcb_get_property_value(prop);
30
31     FREE(win->class_instance);
32     FREE(win->class_class);
33
34     win->class_instance = sstrdup(new_class);
35     if ((strlen(new_class) + 1) < xcb_get_property_value_length(prop))
36         win->class_class = sstrdup(new_class + strlen(new_class) + 1);
37     else win->class_class = NULL;
38     LOG("WM_CLASS changed to %s (instance), %s (class)\n",
39         win->class_instance, win->class_class);
40
41     if (before_mgmt) {
42         free(prop);
43         return;
44     }
45
46     run_assignments(win);
47
48     free(prop);
49 }
50
51 /*
52  * Updates the name by using _NET_WM_NAME (encoded in UTF-8) for the given
53  * window. Further updates using window_update_name_legacy will be ignored.
54  *
55  */
56 void window_update_name(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt) {
57     if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
58         DLOG("_NET_WM_NAME not specified, not changing\n");
59         FREE(prop);
60         return;
61     }
62
63     /* Save the old pointer to make the update atomic */
64     char *new_name;
65     if (asprintf(&new_name, "%.*s", xcb_get_property_value_length(prop),
66                  (char*)xcb_get_property_value(prop)) == -1) {
67         perror("asprintf()");
68         DLOG("Could not get window name\n");
69         free(prop);
70         return;
71     }
72     /* Convert it to UCS-2 here for not having to convert it later every time we want to pass it to X */
73     size_t len;
74     xcb_char2b_t *ucs2_name = convert_utf8_to_ucs2(new_name, &len);
75     if (ucs2_name == NULL) {
76         LOG("Could not convert _NET_WM_NAME to UCS-2, ignoring new hint\n");
77         FREE(new_name);
78         free(prop);
79         return;
80     }
81     FREE(win->name_x);
82     FREE(win->name_json);
83     win->name_json = new_name;
84     win->name_x = (char*)ucs2_name;
85     win->name_len = len;
86     win->name_x_changed = true;
87     LOG("_NET_WM_NAME changed to \"%s\"\n", win->name_json);
88
89     win->uses_net_wm_name = true;
90
91     if (before_mgmt) {
92         free(prop);
93         return;
94     }
95
96     run_assignments(win);
97
98     free(prop);
99 }
100
101 /*
102  * Updates the name by using WM_NAME (encoded in COMPOUND_TEXT). We do not
103  * touch what the client sends us but pass it to xcb_image_text_8. To get
104  * proper unicode rendering, the application has to use _NET_WM_NAME (see
105  * window_update_name()).
106  *
107  */
108 void window_update_name_legacy(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt) {
109     if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
110         DLOG("WM_NAME not set (_NET_WM_NAME is what you want anyways).\n");
111         FREE(prop);
112         return;
113     }
114
115     /* ignore update when the window is known to already have a UTF-8 name */
116     if (win->uses_net_wm_name) {
117         free(prop);
118         return;
119     }
120
121     char *new_name;
122     if (asprintf(&new_name, "%.*s", xcb_get_property_value_length(prop),
123                  (char*)xcb_get_property_value(prop)) == -1) {
124         perror("asprintf()");
125         DLOG("Could not get legacy window name\n");
126         free(prop);
127         return;
128     }
129
130     LOG("WM_NAME changed to \"%s\"\n", new_name);
131     LOG("Using legacy window title. Note that in order to get Unicode window "
132         "titles in i3, the application has to set _NET_WM_NAME (UTF-8)\n");
133
134     FREE(win->name_x);
135     FREE(win->name_json);
136     win->name_x = new_name;
137     win->name_json = sstrdup(new_name);
138     win->name_len = strlen(new_name);
139     win->name_x_changed = true;
140
141     if (before_mgmt) {
142         free(prop);
143         return;
144     }
145
146     run_assignments(win);
147
148     free(prop);
149 }
150
151 /*
152  * Updates the CLIENT_LEADER (logical parent window).
153  *
154  */
155 void window_update_leader(i3Window *win, xcb_get_property_reply_t *prop) {
156     if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
157         DLOG("CLIENT_LEADER not set.\n");
158         FREE(prop);
159         return;
160     }
161
162     xcb_window_t *leader = xcb_get_property_value(prop);
163     if (leader == NULL) {
164         free(prop);
165         return;
166     }
167
168     DLOG("Client leader changed to %08x\n", *leader);
169
170     win->leader = *leader;
171
172     free(prop);
173 }
174
175 /*
176  * Updates the TRANSIENT_FOR (logical parent window).
177  *
178  */
179 void window_update_transient_for(i3Window *win, xcb_get_property_reply_t *prop) {
180     if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
181         DLOG("TRANSIENT_FOR not set.\n");
182         FREE(prop);
183         return;
184     }
185
186     xcb_window_t transient_for;
187     if (!xcb_icccm_get_wm_transient_for_from_reply(&transient_for, prop)) {
188         free(prop);
189         return;
190     }
191
192     DLOG("Transient for changed to %08x\n", transient_for);
193
194     win->transient_for = transient_for;
195
196     free(prop);
197 }
198
199 /*
200  * Updates the _NET_WM_STRUT_PARTIAL (reserved pixels at the screen edges)
201  *
202  */
203 void window_update_strut_partial(i3Window *win, xcb_get_property_reply_t *prop) {
204     if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
205         DLOG("_NET_WM_STRUT_PARTIAL not set.\n");
206         FREE(prop);
207         return;
208     }
209
210     uint32_t *strut;
211     if (!(strut = xcb_get_property_value(prop))) {
212         free(prop);
213         return;
214     }
215
216     DLOG("Reserved pixels changed to: left = %d, right = %d, top = %d, bottom = %d\n",
217          strut[0], strut[1], strut[2], strut[3]);
218
219     win->reserved = (struct reservedpx){ strut[0], strut[1], strut[2], strut[3] };
220
221     free(prop);
222 }
223
224 /*
225  * Updates the WM_WINDOW_ROLE
226  *
227  */
228 void window_update_role(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt) {
229     if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
230         DLOG("WM_WINDOW_ROLE not set.\n");
231         FREE(prop);
232         return;
233     }
234
235     char *new_role;
236     if (asprintf(&new_role, "%.*s", xcb_get_property_value_length(prop),
237                  (char*)xcb_get_property_value(prop)) == -1) {
238         perror("asprintf()");
239         DLOG("Could not get WM_WINDOW_ROLE\n");
240         free(prop);
241         return;
242     }
243     FREE(win->role);
244     win->role = new_role;
245     LOG("WM_WINDOW_ROLE changed to \"%s\"\n", win->role);
246
247     if (before_mgmt) {
248         free(prop);
249         return;
250     }
251
252     run_assignments(win);
253
254     free(prop);
255 }
256
257 /*
258  * Updates the WM_HINTS (we only care about the input focus handling part).
259  *
260  */
261 void window_update_hints(i3Window *win, xcb_get_property_reply_t *prop) {
262     if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
263         DLOG("WM_HINTS not set.\n");
264         FREE(prop);
265         return;
266     }
267
268     xcb_icccm_wm_hints_t hints;
269
270     if (!xcb_icccm_get_wm_hints_from_reply(&hints, prop)) {
271         DLOG("Could not get WM_HINTS\n");
272         free(prop);
273         return;
274     }
275
276     win->doesnt_accept_focus = !hints.input;
277     LOG("WM_HINTS.input changed to \"%d\"\n", hints.input);
278
279     free(prop);
280 }