]> git.lizzy.rs Git - bspwm.git/blob - src/ewmh.c
Port BSPWM to gcc10
[bspwm.git] / src / ewmh.c
1 /* Copyright (c) 2012, Bastien Dejean
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this
8  *    list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include "bspwm.h"
30 #include "settings.h"
31 #include "tree.h"
32 #include "ewmh.h"
33
34 xcb_ewmh_connection_t *ewmh;
35
36 void ewmh_init(void)
37 {
38         ewmh = calloc(1, sizeof(xcb_ewmh_connection_t));
39         if (xcb_ewmh_init_atoms_replies(ewmh, xcb_ewmh_init_atoms(dpy, ewmh), NULL) == 0) {
40                 err("Can't initialize EWMH atoms.\n");
41         }
42 }
43
44 void ewmh_update_active_window(void)
45 {
46         xcb_window_t win = ((mon->desk->focus == NULL || mon->desk->focus->client == NULL) ? XCB_NONE : mon->desk->focus->id);
47         xcb_ewmh_set_active_window(ewmh, default_screen, win);
48 }
49
50 void ewmh_update_number_of_desktops(void)
51 {
52         uint32_t desktops_count = 0;
53
54         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
55                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
56                         desktops_count++;
57                 }
58         }
59
60         xcb_ewmh_set_number_of_desktops(ewmh, default_screen, desktops_count);
61 }
62
63 uint32_t ewmh_get_desktop_index(desktop_t *d)
64 {
65         uint32_t i = 0;
66         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
67                 for (desktop_t *cd = m->desk_head; cd != NULL; cd = cd->next, i++) {
68                         if (d == cd) {
69                                 return i;
70                         }
71                 }
72         }
73         return 0;
74 }
75
76 bool ewmh_locate_desktop(uint32_t i, coordinates_t *loc)
77 {
78         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
79                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next, i--) {
80                         if (i == 0) {
81                                 loc->monitor = m;
82                                 loc->desktop = d;
83                                 loc->node = NULL;
84                                 return true;
85                         }
86                 }
87         }
88         return false;
89 }
90
91 void ewmh_update_current_desktop(void)
92 {
93         if (mon == NULL) {
94                 return;
95         }
96         uint32_t i = ewmh_get_desktop_index(mon->desk);
97         xcb_ewmh_set_current_desktop(ewmh, default_screen, i);
98 }
99
100 void ewmh_set_wm_desktop(node_t *n, desktop_t *d)
101 {
102         uint32_t i = ewmh_get_desktop_index(d);
103         for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
104                 if (f->client == NULL) {
105                         continue;
106                 }
107                 xcb_ewmh_set_wm_desktop(ewmh, f->id, i);
108         }
109 }
110
111 void ewmh_update_wm_desktops(void)
112 {
113         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
114                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
115                         uint32_t i = ewmh_get_desktop_index(d);
116                         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
117                                 if (n->client == NULL) {
118                                         continue;
119                                 }
120                                 xcb_ewmh_set_wm_desktop(ewmh, n->id, i);
121                         }
122                 }
123         }
124 }
125
126 void ewmh_update_desktop_names(void)
127 {
128         char names[MAXLEN];
129         unsigned int i, j;
130         uint32_t names_len;
131         i = 0;
132
133         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
134                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
135                         for (j = 0; d->name[j] != '\0' && (i + j) < sizeof(names); j++) {
136                                 names[i + j] = d->name[j];
137                         }
138                         i += j;
139                         if (i < sizeof(names)) {
140                                 names[i++] = '\0';
141                         }
142                 }
143         }
144
145         if (i < 1) {
146                 xcb_ewmh_set_desktop_names(ewmh, default_screen, 0, NULL);
147                 return;
148         }
149
150         names_len = i - 1;
151         xcb_ewmh_set_desktop_names(ewmh, default_screen, names_len, names);
152 }
153
154 void ewmh_update_desktop_viewport(void)
155 {
156         uint32_t desktops_count = 0;
157         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
158                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
159                         desktops_count++;
160                 }
161         }
162         if (desktops_count == 0) {
163                 xcb_ewmh_set_desktop_viewport(ewmh, default_screen, 0, NULL);
164                 return;
165         }
166         xcb_ewmh_coordinates_t coords[desktops_count];
167         uint16_t desktop = 0;
168         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
169                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
170                         coords[desktop++] = (xcb_ewmh_coordinates_t){m->rectangle.x, m->rectangle.y};
171                 }
172         }
173         xcb_ewmh_set_desktop_viewport(ewmh, default_screen, desktop, coords);
174 }
175
176 bool ewmh_handle_struts(xcb_window_t win)
177 {
178         xcb_ewmh_wm_strut_partial_t struts;
179         bool changed = false;
180         if (xcb_ewmh_get_wm_strut_partial_reply(ewmh, xcb_ewmh_get_wm_strut_partial(ewmh, win), &struts, NULL) == 1) {
181                 for (monitor_t *m = mon_head; m != NULL; m = m->next) {
182                         xcb_rectangle_t rect = m->rectangle;
183                         if (rect.x < (int16_t) struts.left &&
184                             (int16_t) struts.left < (rect.x + rect.width - 1) &&
185                             (int16_t) struts.left_end_y >= rect.y &&
186                             (int16_t) struts.left_start_y < (rect.y + rect.height)) {
187                                 int dx = struts.left - rect.x;
188                                 if (m->padding.left < 0) {
189                                         m->padding.left += dx;
190                                 } else {
191                                         m->padding.left = MAX(dx, m->padding.left);
192                                 }
193                                 changed = true;
194                         }
195                         if ((rect.x + rect.width) > (int16_t) (screen_width - struts.right) &&
196                             (int16_t) (screen_width - struts.right) > rect.x &&
197                             (int16_t) struts.right_end_y >= rect.y &&
198                             (int16_t) struts.right_start_y < (rect.y + rect.height)) {
199                                 int dx = (rect.x + rect.width) - screen_width + struts.right;
200                                 if (m->padding.right < 0) {
201                                         m->padding.right += dx;
202                                 } else {
203                                         m->padding.right = MAX(dx, m->padding.right);
204                                 }
205                                 changed = true;
206                         }
207                         if (rect.y < (int16_t) struts.top &&
208                             (int16_t) struts.top < (rect.y + rect.height - 1) &&
209                             (int16_t) struts.top_end_x >= rect.x &&
210                             (int16_t) struts.top_start_x < (rect.x + rect.width)) {
211                                 int dy = struts.top - rect.y;
212                                 if (m->padding.top < 0) {
213                                         m->padding.top += dy;
214                                 } else {
215                                         m->padding.top = MAX(dy, m->padding.top);
216                                 }
217                                 changed = true;
218                         }
219                         if ((rect.y + rect.height) > (int16_t) (screen_height - struts.bottom) &&
220                             (int16_t) (screen_height - struts.bottom) > rect.y &&
221                             (int16_t) struts.bottom_end_x >= rect.x &&
222                             (int16_t) struts.bottom_start_x < (rect.x + rect.width)) {
223                                 int dy = (rect.y + rect.height) - screen_height + struts.bottom;
224                                 if (m->padding.bottom < 0) {
225                                         m->padding.bottom += dy;
226                                 } else {
227                                         m->padding.bottom = MAX(dy, m->padding.bottom);
228                                 }
229                                 changed = true;
230                         }
231                 }
232         }
233         return changed;
234 }
235
236 void ewmh_update_client_list(bool stacking)
237 {
238         if (clients_count == 0) {
239                 xcb_ewmh_set_client_list(ewmh, default_screen, 0, NULL);
240                 xcb_ewmh_set_client_list_stacking(ewmh, default_screen, 0, NULL);
241                 return;
242         }
243
244         xcb_window_t wins[clients_count];
245         unsigned int i = 0;
246
247         if (stacking) {
248                 for (stacking_list_t *s = stack_head; s != NULL; s = s->next) {
249                         wins[i++] = s->node->id;
250                 }
251                 xcb_ewmh_set_client_list_stacking(ewmh, default_screen, clients_count, wins);
252         } else {
253                 for (monitor_t *m = mon_head; m != NULL; m = m->next) {
254                         for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
255                                 for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
256                                         if (n->client == NULL) {
257                                                 continue;
258                                         }
259                                         wins[i++] = n->id;
260                                 }
261                         }
262                 }
263                 xcb_ewmh_set_client_list(ewmh, default_screen, clients_count, wins);
264         }
265 }
266
267 void ewmh_wm_state_update(node_t *n)
268 {
269         client_t *c = n->client;
270         size_t count = 0;
271         uint32_t values[12];
272 #define HANDLE_WM_STATE(s)  \
273         if (WM_FLAG_##s & c->wm_flags) { \
274                 values[count++] = ewmh->_NET_WM_STATE_##s; \
275         }
276         HANDLE_WM_STATE(MODAL)
277         HANDLE_WM_STATE(STICKY)
278         HANDLE_WM_STATE(MAXIMIZED_VERT)
279         HANDLE_WM_STATE(MAXIMIZED_HORZ)
280         HANDLE_WM_STATE(SHADED)
281         HANDLE_WM_STATE(SKIP_TASKBAR)
282         HANDLE_WM_STATE(SKIP_PAGER)
283         HANDLE_WM_STATE(HIDDEN)
284         HANDLE_WM_STATE(FULLSCREEN)
285         HANDLE_WM_STATE(ABOVE)
286         HANDLE_WM_STATE(BELOW)
287         HANDLE_WM_STATE(DEMANDS_ATTENTION)
288 #undef HANDLE_WM_STATE
289         xcb_ewmh_set_wm_state(ewmh, n->id, count, values);
290 }
291
292 void ewmh_set_supporting(xcb_window_t win)
293 {
294         pid_t wm_pid = getpid();
295         xcb_ewmh_set_supporting_wm_check(ewmh, root, win);
296         xcb_ewmh_set_supporting_wm_check(ewmh, win, win);
297         xcb_ewmh_set_wm_name(ewmh, win, strlen(WM_NAME), WM_NAME);
298         xcb_ewmh_set_wm_pid(ewmh, win, wm_pid);
299 }