A tiling window manager
1/*
2 * Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca>
3 * Copyright (C) 2016 Mathieu OTHACEHE <m.othacehe@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA.
18 */
19
20#include <string.h>
21#include <err.h>
22#include <X11/cursorfont.h>
23
24#include "sdorfehs.h"
25
26static void init_screen(rp_screen *s);
27
28int
29screen_width(rp_screen *s)
30{
31 return s->width - defaults.padding_right - defaults.padding_left;
32}
33
34int
35screen_height(rp_screen *s)
36{
37 int ret = s->height - defaults.padding_bottom - defaults.padding_top;
38
39 if (defaults.bar_sticky && screen_primary() == s) {
40 ret -= sticky_bar_height(s);
41
42 if (!defaults.bar_in_padding)
43 switch (defaults.bar_location) {
44 case NorthEastGravity:
45 case NorthGravity:
46 case NorthWestGravity:
47 ret -= defaults.padding_top;
48 break;
49 }
50 }
51
52 return ret;
53}
54
55int
56screen_left(rp_screen *s)
57{
58 return s->left + defaults.padding_left;
59}
60
61int
62screen_right(rp_screen *s)
63{
64 return s->left + s->width - defaults.padding_right;
65}
66
67int
68screen_top(rp_screen *s)
69{
70 int ret = s->top + defaults.padding_top;
71
72 if (defaults.bar_sticky && screen_primary() == s) {
73 switch (defaults.bar_location) {
74 case NorthEastGravity:
75 case NorthGravity:
76 case NorthWestGravity:
77 ret += sticky_bar_height(s);
78 if (!defaults.bar_in_padding)
79 ret += defaults.padding_top;
80 break;
81 }
82 }
83
84 return ret;
85}
86
87int
88screen_bottom(rp_screen *s)
89{
90 int ret = s->top + s->height - defaults.padding_bottom;
91
92 if (defaults.bar_sticky && screen_primary() == s) {
93 switch (defaults.bar_location) {
94 case SouthEastGravity:
95 case SouthGravity:
96 case SouthWestGravity:
97 ret -= sticky_bar_height(s);
98 break;
99 }
100 }
101
102 return ret;
103}
104
105/* Given a root window, return the rp_screen struct */
106rp_screen *
107find_screen(Window w)
108{
109 rp_screen *cur;
110
111 list_for_each_entry(cur, &rp_screens, node) {
112 if (cur->root == w)
113 return cur;
114 }
115
116 return NULL;
117}
118
119/* Given a window attr, return the rp_screen struct */
120rp_screen *
121find_screen_by_attr(XWindowAttributes attr)
122{
123 rp_screen *cur;
124
125 list_for_each_entry(cur, &rp_screens, node) {
126 if (attr.x >= cur->left &&
127 attr.x <= cur->left + cur->width &&
128 attr.y >= cur->top &&
129 attr.y <= cur->top + cur->height)
130 return cur;
131 }
132
133 return NULL;
134}
135
136/* Return 1 if w is a root window of any of the screens. */
137int
138is_a_root_window(unsigned int w)
139{
140 rp_screen *cur;
141
142 list_for_each_entry(cur, &rp_screens, node) {
143 if (cur->root == w)
144 return 1;
145 }
146
147 return 0;
148}
149
150rp_screen *
151screen_number(int number)
152{
153 rp_screen *cur;
154
155 list_for_each_entry(cur, &rp_screens, node) {
156 if (cur->number == number)
157 return cur;
158 }
159
160 return NULL;
161}
162
163static int
164screen_cmp(void *priv, struct list_head *a, struct list_head *b)
165{
166 rp_screen *sc_a = container_of(a, typeof(*sc_a), node);
167 rp_screen *sc_b = container_of(b, typeof(*sc_b), node);
168
169 if (sc_a->left < sc_b->left)
170 return -1;
171 if (sc_a->left > sc_b->left)
172 return 1;
173
174 if (sc_a->top > sc_b->top)
175 return -1;
176 if (sc_a->top < sc_b->top)
177 return 1;
178
179 return 0;
180}
181
182void
183screen_sort(void)
184{
185 return list_sort(NULL, &rp_screens, screen_cmp);
186}
187
188static void
189screen_set_numbers(void)
190{
191 rp_screen *cur;
192
193 list_for_each_entry(cur, &rp_screens, node) {
194 cur->number = numset_request(rp_glob_screen.numset);
195 }
196}
197
198rp_screen *
199screen_primary(void)
200{
201 rp_screen *first, *cur;
202
203 /* By default, take the first screen as current screen */
204 list_first(first, &rp_screens, node);
205
206 if (!rp_have_xrandr)
207 return first;
208
209 list_for_each_entry(cur, &rp_screens, node)
210 if (xrandr_is_primary(cur))
211 return cur;
212
213 /* nothing is primary? */
214 return first;
215}
216
217static void
218screen_select_primary(void)
219{
220 rp_screen *cur = screen_primary();
221
222 if (!rp_current_screen)
223 rp_current_screen = cur;
224
225 rp_current_screen = cur;
226 PRINT_DEBUG(("Xrandr primary screen %d detected\n",
227 rp_current_screen->number));
228}
229
230static void
231init_global_screen(rp_global_screen *s)
232{
233 XColor color, junk;
234 int screen_num;
235
236 screen_num = DefaultScreen(dpy);
237 s->root = RootWindow(dpy, screen_num);
238
239 s->numset = numset_new();
240 s->fgcolor = WhitePixel(dpy, screen_num);
241
242 if (XAllocNamedColor(dpy, DefaultColormap(dpy, screen_num),
243 defaults.fgcolor_string, &color, &junk))
244 rp_glob_screen.fgcolor = color.pixel | (0xff << 24);
245 else {
246 warnx("failed allocating fgcolor %s", defaults.fgcolor_string);
247 s->fgcolor = WhitePixel(dpy, screen_num);
248 }
249
250 if (XAllocNamedColor(dpy, DefaultColormap(dpy, screen_num),
251 defaults.bgcolor_string, &color, &junk))
252 rp_glob_screen.bgcolor = color.pixel | (0xff << 24);
253 else {
254 warnx("failed allocating bgcolor %s", defaults.bgcolor_string);
255 s->bgcolor = BlackPixel(dpy, screen_num);
256 }
257
258 if (XAllocNamedColor(dpy, DefaultColormap(dpy, screen_num),
259 defaults.fwcolor_string, &color, &junk))
260 rp_glob_screen.fwcolor = color.pixel | (0xff << 24);
261 else {
262 warnx("failed allocating fwcolor %s", defaults.fwcolor_string);
263 s->fwcolor = BlackPixel(dpy, screen_num);
264 }
265
266 if (XAllocNamedColor(dpy, DefaultColormap(dpy, screen_num),
267 defaults.bwcolor_string, &color, &junk))
268 rp_glob_screen.bwcolor = color.pixel | (0xff << 24);
269 else {
270 warnx("failed allocating bwcolor %s", defaults.bwcolor_string);
271 s->bwcolor = BlackPixel(dpy, screen_num);
272 }
273
274 if (XAllocNamedColor(dpy, DefaultColormap(dpy, screen_num),
275 defaults.barbordercolor_string, &color, &junk))
276 rp_glob_screen.bar_bordercolor = color.pixel | (0xff << 24);
277 else {
278 warnx("failed allocating barbordercolor %s",
279 defaults.barbordercolor_string);
280 s->bar_bordercolor = BlackPixel(dpy, screen_num);
281 }
282
283 s->wm_check = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1,
284 0, 0, rp_glob_screen.bgcolor);
285 set_atom(s->wm_check, _net_supporting_wm_check, XA_WINDOW,
286 &s->wm_check, 1);
287 set_atom(s->root, _net_supporting_wm_check, XA_WINDOW,
288 &s->wm_check, 1);
289 XChangeProperty(dpy, s->root, _net_wm_name,
290 xa_utf8_string, 8, PropModeReplace,
291 (unsigned char *)PROGNAME, strlen(PROGNAME));
292 XChangeProperty(dpy, s->wm_check, _net_wm_name,
293 xa_utf8_string, 8, PropModeReplace,
294 (unsigned char *)PROGNAME, strlen(PROGNAME));
295}
296
297void
298init_screens(void)
299{
300 int i;
301 int screen_count = 0;
302 int *rr_outputs = NULL;
303 rp_screen *screen;
304
305 /* Get the number of screens */
306 if (rp_have_xrandr) {
307 screen_count = xrandr_query_screen(&rr_outputs);
308 if (!screen_count) {
309 rp_have_xrandr = 0;
310 warnx("XRandR reported no screens, not using it\n");
311 }
312 }
313
314 if (!screen_count)
315 screen_count = ScreenCount(dpy);
316
317 /* Create our global frame numset */
318 rp_frame_numset = numset_new();
319
320 init_global_screen(&rp_glob_screen);
321
322 for (i = 0; i < screen_count; i++) {
323 screen = xmalloc(sizeof(*screen));
324 memset(screen, 0, sizeof(*screen));
325 list_add(&screen->node, &rp_screens);
326
327 if (rp_have_xrandr && rr_outputs != NULL)
328 xrandr_fill_screen(rr_outputs[i], screen);
329 else
330 xrandr_fill_screen(i, screen);
331
332 init_screen(screen);
333 }
334
335 screen_sort();
336 screen_set_numbers();
337 screen_select_primary();
338
339 set_atom(rp_glob_screen.root, _net_number_of_desktops, XA_CARDINAL,
340 (unsigned long *)&defaults.vscreens, 1);
341
342 free(rr_outputs);
343}
344
345static void
346init_rat_cursor(rp_screen *s)
347{
348 s->rat = XCreateFontCursor(dpy, XC_icon);
349}
350
351static void
352init_screen(rp_screen *s)
353{
354 XGCValues gcv;
355 struct sbuf *buf;
356 rp_vscreen *vscreen;
357 char *colon;
358 int screen_num, x;
359
360 screen_num = DefaultScreen(dpy);
361
362 if (!rp_have_xrandr) {
363 s->left = 0;
364 s->top = 0;
365 s->width = DisplayWidth(dpy, screen_num);
366 s->height = DisplayHeight(dpy, screen_num);
367 }
368 /*
369 * Select on some events on the root window, if this fails, then there
370 * is already a WM running and the X Error handler will catch it,
371 * terminating us.
372 */
373 XSelectInput(dpy, RootWindow(dpy, screen_num),
374 PropertyChangeMask | ColormapChangeMask
375 | SubstructureRedirectMask | SubstructureNotifyMask
376 | StructureNotifyMask);
377 XSync(dpy, False);
378
379 s->scratch_buffer = NULL;
380
381 /* Build the display string for each screen */
382 buf = sbuf_new(0);
383 sbuf_printf(buf, "DISPLAY=%s", DisplayString(dpy));
384 colon = strrchr(sbuf_get(buf), ':');
385 if (colon) {
386 char *dot;
387
388 dot = strrchr(sbuf_get(buf), '.');
389 if (!dot || dot < colon) {
390 /*
391 * no dot was found or it belongs to fqdn - append
392 * screen_num to the end
393 */
394 sbuf_printf_concat(buf, ".%d", screen_num);
395 }
396 }
397 s->display_string = sbuf_free_struct(buf);
398
399 PRINT_DEBUG(("display string: %s\n", s->display_string));
400
401 s->root = RootWindow(dpy, screen_num);
402 s->screen_num = screen_num;
403 s->def_cmap = DefaultColormap(dpy, screen_num);
404 s->full_screen_win = NULL;
405
406 init_rat_cursor(s);
407
408 /* Setup the GC for drawing the font. */
409 gcv.foreground = rp_glob_screen.fgcolor;
410 gcv.background = rp_glob_screen.bgcolor;
411 gcv.function = GXcopy;
412 gcv.line_width = 1;
413 gcv.subwindow_mode = IncludeInferiors;
414 s->normal_gc = XCreateGC(dpy, s->root,
415 GCForeground | GCBackground | GCFunction
416 | GCLineWidth | GCSubwindowMode,
417 &gcv);
418 gcv.foreground = rp_glob_screen.bgcolor;
419 gcv.background = rp_glob_screen.fgcolor;
420 s->inverse_gc = XCreateGC(dpy, s->root,
421 GCForeground | GCBackground | GCFunction
422 | GCLineWidth | GCSubwindowMode,
423 &gcv);
424
425 s->xft_font = XftFontOpenName(dpy, screen_num, DEFAULT_XFT_FONT);
426 if (!s->xft_font)
427 errx(1, "failed to open default font \"%s\"", DEFAULT_XFT_FONT);
428
429 memset(s->xft_font_cache, 0, sizeof(s->xft_font_cache));
430
431 if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen_num),
432 DefaultColormap(dpy, screen_num),
433 defaults.fgcolor_string, &s->xft_fgcolor))
434 errx(1, "failed to allocate font fg color %s",
435 defaults.fgcolor_string);
436
437 if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen_num),
438 DefaultColormap(dpy, screen_num),
439 defaults.bgcolor_string, &s->xft_bgcolor))
440 errx(1, "failed to allocate font bg color %s",
441 defaults.bgcolor_string);
442
443 /* Create the program bar window. */
444 s->bar_is_raised = 0;
445 s->bar_window = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1,
446 defaults.bar_border_width, rp_glob_screen.bar_bordercolor,
447 rp_glob_screen.bgcolor);
448 set_atom(s->bar_window, _net_wm_window_type, XA_ATOM,
449 &_net_wm_window_type_dock, 1);
450 XSelectInput(dpy, s->bar_window, ButtonPressMask);
451
452 /*
453 * Setup the window that will receive all keystrokes once the prefix
454 * key has been pressed.
455 */
456 s->key_window = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1, 0,
457 WhitePixel(dpy, screen_num),
458 BlackPixel(dpy, screen_num));
459 set_atom(s->key_window, _net_wm_window_type, XA_ATOM,
460 &_net_wm_window_type_dock, 1);
461 XSelectInput(dpy, s->key_window, KeyPressMask | KeyReleaseMask);
462
463 /* Create the input window. */
464 s->input_window = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1,
465 defaults.bar_border_width, rp_glob_screen.bar_bordercolor,
466 rp_glob_screen.bgcolor);
467 set_atom(s->input_window, _net_wm_window_type, XA_ATOM,
468 &_net_wm_window_type_dock, 1);
469 XSelectInput(dpy, s->input_window, KeyPressMask | KeyReleaseMask);
470
471 /* Create the frame indicator window */
472 s->frame_window = XCreateSimpleWindow(dpy, s->root, 1, 1, 1, 1,
473 defaults.bar_border_width, rp_glob_screen.bar_bordercolor,
474 rp_glob_screen.bgcolor);
475 set_atom(s->frame_window, _net_wm_window_type, XA_ATOM,
476 &_net_wm_window_type_tooltip, 1);
477
478 /* Create the help window */
479 s->help_window = XCreateSimpleWindow(dpy, s->root, s->left, s->top,
480 s->width, s->height, 0, rp_glob_screen.bar_bordercolor,
481 rp_glob_screen.bgcolor);
482 set_atom(s->help_window, _net_wm_window_type, XA_ATOM,
483 &_net_wm_window_type_splash, 1);
484 XSelectInput(dpy, s->help_window, KeyPressMask);
485
486 activate_screen(s);
487
488 XSync(dpy, 0);
489
490 INIT_LIST_HEAD(&s->vscreens);
491 s->vscreens_numset = numset_new();
492
493 for (x = 0; x < defaults.vscreens; x++) {
494 vscreen = xmalloc(sizeof(rp_vscreen));
495 init_vscreen(vscreen, s);
496 list_add_tail(&vscreen->node, &s->vscreens);
497
498 if (x == 0) {
499 s->current_vscreen = vscreen;
500 vscreen_announce_current(vscreen);
501 }
502 }
503
504 screen_update_workarea(s);
505}
506
507void
508activate_screen(rp_screen *s)
509{
510 XMapWindow(dpy, s->key_window);
511}
512
513void
514deactivate_screen(rp_screen *s)
515{
516 /* Unmap its key window */
517 XUnmapWindow(dpy, s->key_window);
518}
519
520static int
521is_rp_window_for_given_screen(Window w, rp_screen *s)
522{
523 if (w != s->key_window &&
524 w != s->bar_window &&
525 w != s->input_window &&
526 w != s->frame_window &&
527 w != s->help_window)
528 return 0;
529 return 1;
530}
531
532int
533is_rp_window(Window w)
534{
535 rp_screen *cur;
536
537 list_for_each_entry(cur, &rp_screens, node) {
538 if (is_rp_window_for_given_screen(w, cur))
539 return 1;
540 }
541
542 return 0;
543}
544
545char *
546screen_dump(rp_screen *screen)
547{
548 char *tmp;
549 struct sbuf *s;
550
551 s = sbuf_new(0);
552 if (rp_have_xrandr)
553 sbuf_printf(s, "%s ", screen->xrandr.name);
554
555 sbuf_printf_concat(s, "%d %d %d %d %d %d",
556 screen->number,
557 screen->left,
558 screen->top,
559 screen->width,
560 screen->height,
561 (rp_current_screen == screen) ? 1 : 0 /* is current? */
562 );
563
564 /* Extract the string and return it, and don't forget to free s. */
565 tmp = sbuf_get(s);
566 free(s);
567 return tmp;
568}
569
570int
571screen_count(void)
572{
573 return list_size(&rp_screens);
574}
575
576rp_screen *
577screen_next(void)
578{
579 return list_next_entry(rp_current_screen, &rp_screens, node);
580}
581
582rp_screen *
583screen_prev(void)
584{
585 return list_prev_entry(rp_current_screen, &rp_screens, node);
586}
587
588static void
589screen_remove_current(void)
590{
591 rp_screen *new_screen;
592 rp_frame *new_frame;
593 rp_window *cur_win;
594 int cur_frame;
595
596 cur_win = current_window();
597 new_screen = screen_next();
598
599 cur_frame = new_screen->current_vscreen->current_frame;
600 new_frame = vscreen_get_frame(new_screen->current_vscreen, cur_frame);
601
602 set_active_frame(new_frame, 1);
603
604 hide_window(cur_win);
605}
606
607void
608screen_update(rp_screen *s, int left, int top, int width, int height)
609{
610 rp_frame *f;
611 rp_vscreen *v;
612 int oldwidth, oldheight;
613
614 PRINT_DEBUG(("screen_update (left=%d, top=%d, width=%d, height=%d)\n",
615 left, top, width, height));
616
617 oldwidth = s->width;
618 oldheight = s->height;
619
620 s->left = left;
621 s->top = top;
622 s->width = width;
623 s->height = height;
624
625 if (defaults.bar_sticky && screen_primary() == s)
626 hide_bar(s, 0);
627
628 XMoveResizeWindow(dpy, s->help_window, s->left, s->top, s->width,
629 s->height);
630
631 list_for_each_entry(v, &s->vscreens, node) {
632 list_for_each_entry(f, &v->frames, node) {
633 f->x = (f->x * width) / oldwidth;
634 f->width = (f->width * width) / oldwidth;
635 f->y = (f->y * height) / oldheight;
636 f->height = (f->height * height) / oldheight;
637 maximize_all_windows_in_frame(f);
638 }
639 }
640
641 screen_update_workarea(s);
642}
643
644void
645screen_update_frames(rp_screen *s)
646{
647 rp_vscreen *v;
648 rp_frame *f;
649 int diff;
650
651 list_for_each_entry(v, &s->vscreens, node) {
652 list_for_each_entry(f, &v->frames, node) {
653 if (frame_left_screen_edge(f) ||
654 (f->edges & EDGE_LEFT)) {
655 diff = screen_left(v->screen) - f->x;
656 f->x = screen_left(v->screen);
657 f->width -= diff;
658 }
659
660 if (frame_top_screen_edge(f) ||
661 (f->edges & EDGE_TOP)) {
662 diff = screen_top(v->screen) - f->y;
663 f->y = screen_top(v->screen);
664 f->height -= diff;
665 }
666
667 if (frame_right_screen_edge(f) ||
668 (f->edges & EDGE_RIGHT))
669 f->width = screen_right(v->screen) - f->x;
670
671 if (frame_bottom_screen_edge(f) ||
672 (f->edges & EDGE_BOTTOM))
673 f->height = screen_bottom(v->screen) - f->y;
674
675 maximize_all_windows_in_frame(f);
676 }
677 }
678
679 redraw_sticky_bar_text(1);
680}
681
682void
683screen_update_workarea(rp_screen *s)
684{
685 unsigned long workarea[4];
686
687 workarea[0] = screen_left(s) - s->left;
688 workarea[1] = screen_top(s) - s->top;
689 workarea[2] = screen_width(s);
690 workarea[3] = screen_height(s);
691
692 set_atom(s->root, _net_workarea, XA_CARDINAL, workarea, 4);
693}
694
695rp_screen *
696screen_add(int rr_output)
697{
698 rp_screen *screen;
699
700 screen = xmalloc(sizeof(*screen));
701 memset(screen, 0, sizeof(*screen));
702 list_add(&screen->node, &rp_screens);
703
704 screen->number = numset_request(rp_glob_screen.numset);
705
706 xrandr_fill_screen(rr_output, screen);
707 init_screen(screen);
708
709 if (screen_count() == 1) {
710 rp_current_screen = screen;
711 change_windows_vscreen(NULL, rp_current_vscreen);
712 set_window_focus(rp_current_screen->key_window);
713 }
714 return screen;
715}
716
717void
718screen_del(rp_screen *s)
719{
720 rp_vscreen *v;
721 struct list_head *iter, *tmp;
722
723 if (s == rp_current_screen) {
724 if (screen_count() == 1) {
725 list_for_each_safe_entry(v, iter, tmp, &s->vscreens,
726 node)
727 hide_vscreen_windows(v);
728
729 rp_current_screen = NULL;
730 } else {
731 /*
732 * The deleted screen cannot be the current screen
733 * anymore, focus the next one.
734 */
735 screen_remove_current();
736 }
737 } else {
738 list_for_each_safe_entry(v, iter, tmp, &s->vscreens, node)
739 hide_vscreen_windows(v);
740 }
741
742 numset_release(rp_glob_screen.numset, s->number);
743
744 list_for_each_safe_entry(v, iter, tmp, &s->vscreens, node)
745 vscreen_del(v);
746
747 screen_free(s);
748
749 list_del(&s->node);
750 free(s);
751}
752
753void
754screen_free(rp_screen *s)
755{
756 deactivate_screen(s);
757
758 XDestroyWindow(dpy, s->bar_window);
759 XDestroyWindow(dpy, s->key_window);
760 XDestroyWindow(dpy, s->input_window);
761 XDestroyWindow(dpy, s->frame_window);
762 XDestroyWindow(dpy, s->help_window);
763
764 if (s->xft_font) {
765 XftColorFree(dpy, DefaultVisual(dpy, s->screen_num),
766 DefaultColormap(dpy, s->screen_num), &s->xft_fgcolor);
767 XftColorFree(dpy, DefaultVisual(dpy, s->screen_num),
768 DefaultColormap(dpy, s->screen_num), &s->xft_bgcolor);
769 XftFontClose(dpy, s->xft_font);
770 }
771 rp_clear_cached_fonts(s);
772
773 XFreeCursor(dpy, s->rat);
774 XFreeColormap(dpy, s->def_cmap);
775 XFreeGC(dpy, s->normal_gc);
776 XFreeGC(dpy, s->inverse_gc);
777
778 free(s->display_string);
779 free(s->xrandr.name);
780}
781
782void
783screen_free_final(void)
784{
785 /* Relinquish our hold on the root window. */
786 XSelectInput(dpy, RootWindow(dpy, DefaultScreen(dpy)), 0);
787
788 numset_free(rp_glob_screen.numset);
789
790 XDeleteProperty(dpy, rp_glob_screen.root, _net_wm_name);
791 XDeleteProperty(dpy, rp_glob_screen.root, _net_supporting_wm_check);
792 XDeleteProperty(dpy, rp_glob_screen.root, _net_supported);
793 XDestroyWindow(dpy, rp_glob_screen.wm_check);
794}