A tiling window manager
1/*
2 * Manage windows, such as Mapping them and making sure the proper key Grabs
3 * have been put in place.
4 *
5 * Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA.
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <err.h>
26
27#include <X11/X.h>
28#include <X11/Xlib.h>
29#include <X11/Xutil.h>
30#include <X11/Xatom.h>
31#include <X11/keysymdef.h>
32
33#include "sdorfehs.h"
34
35static char **unmanaged_window_list = NULL;
36static int num_unmanaged_windows = 0;
37
38void
39clear_unmanaged_list(void)
40{
41 if (unmanaged_window_list) {
42 int i;
43
44 for (i = 0; i < num_unmanaged_windows; i++)
45 free(unmanaged_window_list[i]);
46
47 free(unmanaged_window_list);
48
49 unmanaged_window_list = NULL;
50 }
51 num_unmanaged_windows = 0;
52}
53
54char *
55list_unmanaged_windows(void)
56{
57 char *tmp = NULL;
58
59 if (unmanaged_window_list) {
60 struct sbuf *buf;
61 int i;
62
63 buf = sbuf_new(0);
64
65 for (i = 0; i < num_unmanaged_windows; i++) {
66 sbuf_concat(buf, unmanaged_window_list[i]);
67 sbuf_concat(buf, "\n");
68 }
69 sbuf_chop(buf);
70 tmp = sbuf_free_struct(buf);
71 }
72 return tmp;
73}
74
75void
76add_unmanaged_window(char *name)
77{
78 char **tmp;
79
80 if (!name)
81 return;
82
83 tmp = xmalloc((num_unmanaged_windows + 1) * sizeof(char *));
84
85 if (unmanaged_window_list) {
86 memcpy(tmp, unmanaged_window_list,
87 num_unmanaged_windows * sizeof(char *));
88 free(unmanaged_window_list);
89 }
90 tmp[num_unmanaged_windows] = xstrdup(name);
91 num_unmanaged_windows++;
92
93 unmanaged_window_list = tmp;
94}
95
96void
97grab_top_level_keys(Window w)
98{
99 rp_keymap *map = find_keymap(defaults.top_kmap);
100 int i;
101
102 if (map == NULL) {
103 warnx("unable to find %s level keymap", defaults.top_kmap);
104 return;
105 }
106 PRINT_INPUT_DEBUG(("grabbing top level key\n"));
107 for (i = 0; i < map->actions_last; i++) {
108 PRINT_INPUT_DEBUG(("%d\n", i));
109 grab_key(map->actions[i].key, map->actions[i].state, w);
110 }
111}
112
113void
114ungrab_top_level_keys(Window w)
115{
116 XUngrabKey(dpy, AnyKey, AnyModifier, w);
117}
118
119void
120ungrab_keys_all_wins(void)
121{
122 rp_window *cur;
123
124 /* Remove the grab on the current prefix key */
125 list_for_each_entry(cur, &rp_mapped_window, node) {
126 ungrab_top_level_keys(cur->w);
127 }
128}
129
130void
131grab_keys_all_wins(void)
132{
133 rp_window *cur;
134
135 /* Remove the grab on the current prefix key */
136 list_for_each_entry(cur, &rp_mapped_window, node) {
137 grab_top_level_keys(cur->w);
138 }
139}
140
141void
142update_normal_hints(rp_window *win)
143{
144 long supplied;
145
146 XGetWMNormalHints(dpy, win->w, win->hints, &supplied);
147
148 /* Discard bogus hints */
149 if ((win->hints->flags & PAspect) && (win->hints->min_aspect.x < 1 ||
150 win->hints->min_aspect.y < 1 || win->hints->max_aspect.x < 1 ||
151 win->hints->max_aspect.y < 1))
152 win->hints->flags &= ~PAspect;
153 if ((win->hints->flags & PMaxSize) && win->hints->max_width < 1)
154 win->hints->flags &= ~PMaxSize;
155 if ((win->hints->flags & PMinSize) && win->hints->min_width < 1)
156 win->hints->flags &= ~PMinSize;
157 if ((win->hints->flags & PResizeInc) && (win->hints->width_inc < 1 ||
158 win->hints->height_inc < 1))
159 win->hints->flags &= ~PResizeInc;
160
161 /* Print debugging output for window hints. */
162#ifdef DEBUG
163 if (win->hints->flags & PMinSize)
164 PRINT_DEBUG(("minx: %d miny: %d\n", win->hints->min_width,
165 win->hints->min_height));
166
167 if (win->hints->flags & PMaxSize)
168 PRINT_DEBUG(("maxx: %d maxy: %d\n", win->hints->max_width,
169 win->hints->max_height));
170
171 if (win->hints->flags & PResizeInc)
172 PRINT_DEBUG(("incx: %d incy: %d\n", win->hints->width_inc,
173 win->hints->height_inc));
174#endif
175}
176
177
178static char *
179get_wmname(Window w)
180{
181 char *name = NULL;
182 XTextProperty text_prop;
183 Atom type = None;
184 int ret = None, n;
185 unsigned long nitems, bytes_after;
186 int format;
187 char **cl;
188 unsigned char *val = NULL;
189
190 /*
191 * Try to use the window's _NET_WM_NAME ewmh property
192 */
193 ret = XGetWindowProperty(dpy, w, _net_wm_name, 0, 40, False,
194 xa_utf8_string, &type, &format, &nitems,
195 &bytes_after, &val);
196 /* We have a valid UTF-8 string */
197 if (ret == Success && type == xa_utf8_string && format == 8 &&
198 nitems > 0) {
199 name = xstrdup((char *) val);
200 XFree(val);
201 PRINT_DEBUG(("Fetching window name using "
202 "_NET_WM_NAME succeeded\n"));
203 PRINT_DEBUG(("WM_NAME: %s\n", name));
204 return name;
205 }
206 /* Something went wrong for whatever reason */
207 if (ret == Success && val)
208 XFree(val);
209 PRINT_DEBUG(("Could not fetch window name using _NET_WM_NAME\n"));
210
211 if (XGetWMName(dpy, w, &text_prop) == 0) {
212 PRINT_DEBUG(("XGetWMName failed\n"));
213 return NULL;
214 }
215 PRINT_DEBUG(("WM_NAME encoding: "));
216 if (text_prop.encoding == xa_string)
217 PRINT_DEBUG(("STRING\n"));
218 else if (text_prop.encoding == xa_compound_text)
219 PRINT_DEBUG(("COMPOUND_TEXT\n"));
220 else if (text_prop.encoding == xa_utf8_string)
221 PRINT_DEBUG(("UTF8_STRING\n"));
222 else
223 PRINT_DEBUG(("unknown (%d)\n", (int) text_prop.encoding));
224
225 /*
226 * It seems that most applications supporting UTF8_STRING and
227 * _NET_WM_NAME don't bother making their WM_NAME available as
228 * UTF8_STRING (but only as either STRING or COMPOUND_TEXT). Let's try
229 * anyway.
230 */
231 if (text_prop.encoding == xa_utf8_string) {
232 ret = Xutf8TextPropertyToTextList(dpy, &text_prop, &cl, &n);
233 PRINT_DEBUG(("Xutf8TextPropertyToTextList: %s\n",
234 ret == Success ? "success" : "error"));
235 } else {
236 /*
237 * XmbTextPropertyToTextList should be fine for all cases, even
238 * UTF8_STRING encoded WM_NAME
239 */
240 ret = XmbTextPropertyToTextList(dpy, &text_prop, &cl, &n);
241 PRINT_DEBUG(("XmbTextPropertyToTextList: %s\n",
242 ret == Success ? "success" : "error"));
243 }
244
245 if (ret == Success && cl && n > 0) {
246 name = xstrdup(cl[0]);
247 XFreeStringList(cl);
248 } else if (text_prop.value) {
249 /* Convertion failed, try to get the raw string */
250 name = xstrdup((char *) text_prop.value);
251 XFree(text_prop.value);
252 }
253 if (name == NULL) {
254 PRINT_DEBUG(("I can't get the WMName.\n"));
255 } else {
256 PRINT_DEBUG(("WM_NAME: '%s'\n", name));
257 }
258
259 return name;
260}
261
262static XClassHint *
263get_class_hints(Window w)
264{
265 XClassHint *class;
266
267 class = XAllocClassHint();
268
269 if (class == NULL)
270 errx(1, "not enough memory for WM_CLASS structure");
271
272 XGetClassHint(dpy, w, class);
273
274 return class;
275}
276
277/*
278 * Reget the WM_NAME property for the window and update its name. Return 1 if
279 * the name changed.
280 */
281int
282update_window_name(rp_window *win)
283{
284 char *newstr;
285 int changed = 0;
286 XClassHint *class;
287
288 newstr = get_wmname(win->w);
289 if (newstr != NULL) {
290 changed = changed || win->wm_name == NULL ||
291 strcmp(newstr, win->wm_name);
292 free(win->wm_name);
293 win->wm_name = newstr;
294 }
295 class = get_class_hints(win->w);
296
297 if (class->res_class != NULL
298 && (win->res_class == NULL || strcmp(class->res_class, win->res_class))) {
299 changed = 1;
300 free(win->res_class);
301 win->res_class = xstrdup(class->res_class);
302 }
303 if (class->res_name != NULL
304 && (win->res_name == NULL || strcmp(class->res_name, win->res_name))) {
305 changed = 1;
306 free(win->res_name);
307 win->res_name = xstrdup(class->res_name);
308 }
309 XFree(class->res_name);
310 XFree(class->res_class);
311 XFree(class);
312 return changed;
313}
314
315/*
316 * This function is used to determine if the window should be treated as a
317 * transient.
318 */
319int
320window_is_transient(rp_window *win)
321{
322 return win->transient
323#ifdef ASPECT_WINDOWS_ARE_TRANSIENTS
324 || win->hints->flags & PAspect
325#endif
326#ifdef MAXSIZE_WINDOWS_ARE_TRANSIENTS
327 || (win->hints->flags & PMaxSize
328 && (win->hints->max_width < win->vscreen->screen->width
329 || win->hints->max_height < win->vscreen->screen->height))
330#endif
331 ;
332}
333
334Atom
335get_net_wm_window_type(rp_window *win)
336{
337 Atom type, window_type = None;
338 int format;
339 unsigned long nitems;
340 unsigned long bytes_left;
341 unsigned char *data;
342
343 if (win == NULL)
344 return None;
345
346 if (XGetWindowProperty(dpy, win->w, _net_wm_window_type, 0, 1L,
347 False, XA_ATOM, &type, &format, &nitems, &bytes_left,
348 &data) == Success && nitems > 0) {
349 window_type = *(Atom *)data;
350 XFree(data);
351 }
352 return window_type;
353}
354
355int
356is_unmanaged_window_type(Window win)
357{
358 Atom win_type;
359 rp_window tmp;
360
361 tmp.w = win;
362 win_type = get_net_wm_window_type(&tmp);
363 if (win_type == _net_wm_window_type_dock ||
364 win_type == _net_wm_window_type_splash ||
365 win_type == _net_wm_window_type_tooltip ||
366 win_type == _net_wm_window_type_utility)
367 return 1;
368
369 return 0;
370}
371
372void
373update_window_information(rp_window *win)
374{
375 XWindowAttributes attr;
376
377 update_window_name(win);
378
379 /* Get the WM Hints */
380 update_normal_hints(win);
381
382 /* Get the colormap */
383 XGetWindowAttributes(dpy, win->w, &attr);
384 win->colormap = attr.colormap;
385 win->x = attr.x;
386 win->y = attr.y;
387 win->width = attr.width;
388 win->height = attr.height;
389 win->border = attr.border_width;
390
391 /* Transient status */
392 win->transient = XGetTransientForHint(dpy, win->w, &win->transient_for);
393
394 if (get_net_wm_window_type(win) == _net_wm_window_type_dialog)
395 win->transient = 1;
396
397 PRINT_DEBUG(("update_window_information: x:%d y:%d width:%d height:%d "
398 "transient:%d\n", win->x, win->y, win->width, win->height,
399 win->transient));
400
401 update_window_gravity(win);
402}
403
404void
405unmanage(rp_window *w)
406{
407 list_del(&w->node);
408 vscreen_del_window(w->vscreen, w);
409
410 remove_atom(rp_glob_screen.root, _net_client_list, XA_WINDOW, w->w);
411 remove_atom(rp_glob_screen.root, _net_client_list_stacking, XA_WINDOW,
412 w->w);
413
414 free_window(w);
415}
416
417/* When starting up scan existing windows and start managing them. */
418void
419scanwins(void)
420{
421 rp_window *win;
422 XWindowAttributes attr;
423 unsigned int i, nwins;
424 Window dw1, dw2, *wins;
425
426 XQueryTree(dpy, rp_glob_screen.root, &dw1, &dw2, &wins, &nwins);
427 PRINT_DEBUG(("windows: %d\n", nwins));
428
429 for (i = 0; i < nwins; i++) {
430 rp_screen *screen;
431
432 XGetWindowAttributes(dpy, wins[i], &attr);
433 if (is_rp_window(wins[i])
434 || attr.override_redirect == True
435 || unmanaged_window(wins[i]))
436 continue;
437
438 screen = find_screen_by_attr(attr);
439 if (!screen)
440 list_first(screen, &rp_screens, node);
441
442 win = add_to_window_list(screen, wins[i]);
443
444 PRINT_DEBUG(("map_state: %s\n",
445 attr.map_state == IsViewable ? "IsViewable" :
446 attr.map_state == IsUnviewable ? "IsUnviewable" :
447 "IsUnmapped"));
448 PRINT_DEBUG(("state: %s\n",
449 get_state(win) == IconicState ? "Iconic" :
450 get_state(win) == NormalState ? "Normal" : "Other"));
451
452 /* Collect mapped and iconized windows. */
453 if (attr.map_state == IsViewable
454 || (attr.map_state == IsUnmapped
455 && get_state(win) == IconicState))
456 map_window(win);
457 }
458
459 XFree(wins);
460}
461
462int
463unmanaged_window(Window w)
464{
465 char *wname;
466 int i;
467
468 if (!unmanaged_window_list)
469 return 0;
470
471 wname = get_wmname(w);
472 if (!wname)
473 return 0;
474
475 for (i = 0; i < num_unmanaged_windows; i++) {
476 if (!strcmp(unmanaged_window_list[i], wname)) {
477 free(wname);
478 return 1;
479 }
480 }
481
482 free(wname);
483
484 if (is_unmanaged_window_type(w))
485 return 1;
486
487 return 0;
488}
489
490/* Set the state of the window. */
491void
492set_state(rp_window *win, int state)
493{
494 unsigned long data[2];
495
496 win->state = state;
497
498 data[0] = (long) win->state;
499 data[1] = (long) None;
500
501 set_atom(win->w, wm_state, wm_state, data, 2);
502}
503
504/* Get the WM state of the window. */
505long
506get_state(rp_window *win)
507{
508 long state = WithdrawnState;
509 Atom type;
510 int format;
511 unsigned long nitems;
512 unsigned long bytes_left;
513 unsigned char *data;
514
515 if (win == NULL)
516 return state;
517
518 if (XGetWindowProperty(dpy, win->w, wm_state, 0L, 2L, False, wm_state,
519 &type, &format, &nitems, &bytes_left, &data) == Success &&
520 nitems > 0) {
521 state = *(long *)data;
522 XFree(data);
523 }
524 return state;
525}
526
527void
528check_state(rp_window *win)
529{
530 Atom state;
531 unsigned long read, left;
532 int i, fs = 0;
533
534 for (i = 0, left = 1; left; i += read) {
535 read = get_atom(win->w, _net_wm_state, XA_ATOM, i, &state, 1,
536 &left);
537 if (!read)
538 break;
539
540 if (state == _net_wm_state_fullscreen) {
541 fs = 1;
542 window_full_screen(win);
543 } else {
544 PRINT_DEBUG(("unhandled window state %ld (%s)\n",
545 state, XGetAtomName(dpy, state)));
546 }
547 }
548
549 if (win->full_screen && !fs)
550 window_full_screen(NULL);
551}
552
553static void
554move_window(rp_window *win)
555{
556 rp_frame *frame;
557 int t, t2, gap;
558
559 if (win->frame_number == EMPTY) {
560 PRINT_DEBUG(("%s: window has no frame\n", __func__));
561 return;
562 }
563
564 frame = win_get_frame(win);
565
566 if (win->full_screen) {
567 win->x = win->vscreen->screen->left;
568 win->y = win->vscreen->screen->top;
569 return;
570 }
571
572 if (defaults.only_border == 0 && num_frames(win->vscreen) <= 1)
573 gap = 0;
574 else
575 gap = defaults.gap;
576
577 /* X coord. */
578 switch (win->gravity) {
579 case NorthWestGravity:
580 case WestGravity:
581 case SouthWestGravity:
582 win->x = frame->x +
583 (frame_left_screen_edge(frame) ? 0 : gap);
584 break;
585 case NorthGravity:
586 case CenterGravity:
587 case SouthGravity:
588 t = (frame_left_screen_edge(frame) ? 0 : gap);
589 t2 = (frame_right_screen_edge(frame) ? 0 : gap);
590 win->x = frame->x + t +
591 ((frame->width - t - t2 -
592 (win->width + win->border * 2)) / 2);
593 break;
594 case NorthEastGravity:
595 case EastGravity:
596 case SouthEastGravity:
597 win->x = frame->x + frame->width -
598 (win->width + win->border * 2) -
599 (frame_right_screen_edge(frame) ? 0 : gap);
600 break;
601 }
602
603 /* Y coord. */
604 switch (win->gravity) {
605 case NorthEastGravity:
606 case NorthGravity:
607 case NorthWestGravity:
608 win->y = frame->y +
609 (frame_top_screen_edge(frame) ? 0 : gap);
610 break;
611 case EastGravity:
612 case CenterGravity:
613 case WestGravity:
614 t = (frame_top_screen_edge(frame) ? 0 : gap);
615 t2 = (frame_bottom_screen_edge(frame) ? 0 : gap);
616 win->y = frame->y + t +
617 ((frame->height - t - t2 -
618 (win->height + win->border * 2)) / 2);
619 break;
620 case SouthEastGravity:
621 case SouthGravity:
622 case SouthWestGravity:
623 win->y = frame->y + frame->height -
624 (win->height + win->border * 2) -
625 (frame_bottom_screen_edge(frame) ? 0 : gap);
626 break;
627 }
628
629 if (win->x < frame->x)
630 win->x = frame->x;
631 if (win->y < frame->y)
632 win->y = frame->y;
633}
634
635/*
636 * set a good standard window's x,y,width,height fields to maximize the window.
637 */
638static void
639maximize_window(rp_window *win, int transient)
640{
641 rp_frame *frame;
642 int maxw, maxh;
643 float gap;
644
645 frame = win_get_frame(win);
646
647 /* We can't maximize a window if it has no frame. */
648 if (frame == NULL) {
649 PRINT_DEBUG(("%s: no frame\n", __func__));
650 return;
651 }
652
653 /* Set the window's border */
654 if ((defaults.only_border == 0 && num_frames(win->vscreen) <= 1) ||
655 win->full_screen)
656 win->border = 0;
657 else
658 win->border = defaults.window_border_width;
659
660 if (win->full_screen) {
661 maxw = win->vscreen->screen->width;
662 maxh = win->vscreen->screen->height;
663 } else {
664 if (transient) {
665 maxw = win->width;
666 maxh = win->height;
667 } else {
668 maxw = frame->width;
669 maxh = frame->height;
670 }
671
672 if (win->hints->flags & PMaxSize) {
673 if (maxw > win->hints->max_width)
674 maxw = win->hints->max_width;
675
676 if (maxh > win->hints->max_height)
677 maxh = win->hints->max_height;
678 }
679
680 if (maxw > frame->width)
681 maxw = frame->width;
682 if (maxh > frame->height)
683 maxh = frame->height;
684
685 PRINT_DEBUG(("adjusted to frame, maxsize %d %d\n", maxw, maxh));
686
687 if (!transient && !(defaults.only_border == 0 &&
688 num_frames(win->vscreen) <= 1)) {
689 int fw, fh;
690
691 gap = (frame_right_screen_edge(frame) ? 0 : 1);
692 gap += (frame_left_screen_edge(frame) ? 0 : 1);
693 fw = frame->width - (gap * defaults.gap) -
694 (win->border * 2);
695 if (maxw > fw)
696 maxw = fw;
697
698 gap = (frame_top_screen_edge(frame) ? 0 : 1);
699 gap += (frame_bottom_screen_edge(frame) ? 0 : 1);
700 fh = frame->height - (gap * defaults.gap) -
701 (win->border * 2);
702 if (maxh > fh)
703 maxh = fh;
704 }
705 }
706
707 /* Honour the window's aspect ratio. */
708 PRINT_DEBUG(("aspect: %ld\n", win->hints->flags & PAspect));
709 if (!win->full_screen && (win->hints->flags & PAspect)) {
710 float ratio = (float) maxw / maxh;
711 float min_ratio = (float) win->hints->min_aspect.x /
712 win->hints->min_aspect.y;
713 float max_ratio = (float) win->hints->max_aspect.x /
714 win->hints->max_aspect.y;
715 PRINT_DEBUG(("ratio=%f min_ratio=%f max_ratio=%f\n",
716 ratio, min_ratio, max_ratio));
717 if (ratio < min_ratio) {
718 maxh = (int) (maxw / min_ratio);
719 } else if (ratio > max_ratio) {
720 maxw = (int) (maxh * max_ratio);
721 }
722
723 PRINT_DEBUG(("honored ratio, maxsize %d %d\n", maxw, maxh));
724 }
725 /*
726 * Make sure we maximize to the nearest Resize Increment specified by
727 * the window
728 */
729 if (!defaults.ignore_resize_hints && !win->full_screen &&
730 (win->hints->flags & PResizeInc)) {
731 int amount;
732 int delta;
733
734 if (win->hints->width_inc) {
735 amount = maxw - win->width;
736 delta = amount % win->hints->width_inc;
737 if (amount < 0 && delta)
738 amount -= win->hints->width_inc;
739 amount -= delta;
740 maxw = amount + win->width;
741 }
742 if (win->hints->height_inc) {
743 amount = maxh - win->height;
744 delta = amount % win->hints->height_inc;
745 if (amount < 0 && delta)
746 amount -= win->hints->height_inc;
747 amount -= delta;
748 maxh = amount + win->height;
749 }
750
751 PRINT_DEBUG(("applied width_inc/height_inc, maxsize %d %d\n",
752 maxw, maxh));
753 }
754 PRINT_DEBUG(("final maxsize: %d %d\n", maxw, maxh));
755
756 win->width = maxw;
757 win->height = maxh;
758}
759
760/*
761 * Maximize the current window if data = 0, otherwise assume it is a pointer to
762 * a window that should be maximized
763 */
764void
765maximize(rp_window *win)
766{
767 if (!win)
768 win = current_window();
769 if (!win)
770 return;
771
772 /* Handle maximizing transient windows differently. */
773 maximize_window(win, win->transient);
774
775 /* Reposition the window. */
776 move_window(win);
777
778 PRINT_DEBUG(("Resizing %s window '%s' to x:%d y:%d w:%d h:%d\n",
779 win->transient ? "transient" : "normal",
780 window_name(win), win->x, win->y, win->width, win->height));
781
782 /* Actually do the maximizing. */
783 XMoveResizeWindow(dpy, win->w, win->x, win->y, win->width, win->height);
784 XSetWindowBorderWidth(dpy, win->w, win->border);
785
786 XSync(dpy, False);
787}
788
789/*
790 * Maximize the current window but don't treat transient windows differently.
791 */
792void
793force_maximize(rp_window *win)
794{
795 if (!win)
796 win = current_window();
797 if (!win)
798 return;
799
800 maximize_window(win, 0);
801
802 /* Reposition the window. */
803 move_window(win);
804
805 /*
806 * This little dance is to force a maximize event. If the window is
807 * already "maximized" X11 will optimize away the event since to
808 * geometry changes were made. This initial resize solves the problem.
809 */
810 if (!defaults.ignore_resize_hints && (win->hints->flags & PResizeInc)) {
811 XMoveResizeWindow(dpy, win->w,
812 win->vscreen->screen->left + win->x,
813 win->vscreen->screen->top + win->y,
814 win->width + win->hints->width_inc,
815 win->height + win->hints->height_inc);
816 } else {
817 XResizeWindow(dpy, win->w, win->width + 1, win->height + 1);
818 }
819
820 XSync(dpy, False);
821
822 /* Resize the window to its proper maximum size. */
823 XMoveResizeWindow(dpy, win->w, win->vscreen->screen->left + win->x,
824 win->vscreen->screen->top + win->y, win->width, win->height);
825 XSetWindowBorderWidth(dpy, win->w, win->border);
826
827 XSync(dpy, False);
828}
829
830/* map the unmapped window win */
831void
832map_window(rp_window *win)
833{
834 rp_window *transfor;
835
836 PRINT_DEBUG(("Mapping the unmapped window %s\n", window_name(win)));
837
838 /* Fill in the necessary data about the window */
839 update_window_information(win);
840
841 if (win->transient_for &&
842 (transfor = find_window(win->transient_for))) {
843 PRINT_DEBUG(("map_window: transient_for %lu\n",
844 win->transient_for));
845 win->vscreen = transfor->vscreen;
846 win->intended_frame_number = transfor->frame_number;
847 }
848
849 win->number = numset_request(rp_window_numset);
850 grab_top_level_keys(win->w);
851
852 /* Put win in the mapped window list */
853 list_del(&win->node);
854 insert_into_list(win, &rp_mapped_window);
855
856 vscreen_map_window(win->vscreen, win);
857
858 /*
859 * The window has never been accessed since it was brought back from the
860 * Withdrawn state.
861 */
862 win->last_access = 0;
863
864 /* It is now considered iconic and set_active_window can handle the
865 * rest. */
866 set_state(win, IconicState);
867
868 /* Depending on the rudeness level, actually map the window. */
869 if ((rp_honour_transient_map && win->transient)
870 || (rp_honour_normal_map && !win->transient))
871 set_active_window(win);
872 else
873 show_rudeness_msg(win, 0);
874
875 append_atom(rp_glob_screen.root, _net_client_list, XA_WINDOW, &win->w,
876 1);
877 append_atom(rp_glob_screen.root, _net_client_list_stacking, XA_WINDOW,
878 &win->w, 1);
879
880 hook_run(&rp_new_window_hook);
881}
882
883void
884hide_window(rp_window *win)
885{
886 if (win == NULL)
887 return;
888
889 /* An unmapped window is not inside a frame. */
890 win->frame_number = EMPTY;
891
892 /* Ignore the unmap_notify event. */
893 XSelectInput(dpy, win->w, WIN_EVENTS & ~(StructureNotifyMask));
894 XUnmapWindow(dpy, win->w);
895 XSelectInput(dpy, win->w, WIN_EVENTS);
896 /*
897 * Ensure that the window doesn't have the focused border color. This
898 * is needed by remove_frame and possibly others.
899 */
900 XSetWindowBorder(dpy, win->w, rp_glob_screen.bwcolor);
901 set_state(win, IconicState);
902}
903
904void
905unhide_window(rp_window * win)
906{
907 if (win == NULL)
908 return;
909
910 /* Always raise the window. */
911 XRaiseWindow(dpy, win->w);
912
913 if (win->state != IconicState)
914 return;
915
916 XMapWindow(dpy, win->w);
917 set_state(win, NormalState);
918}
919
920void
921unhide_all_windows(void)
922{
923 struct list_head *tmp, *iter;
924 rp_window *win;
925
926 list_for_each_safe_entry(win, iter, tmp, &rp_mapped_window, node)
927 unhide_window(win);
928}
929
930void
931withdraw_window(rp_window *win)
932{
933 if (win == NULL)
934 return;
935
936 PRINT_DEBUG(("withdraw_window on '%s'\n", window_name(win)));
937
938 if (win->full_screen)
939 window_full_screen(NULL);
940
941 /*
942 * Give back the window number. the window will get another one, if it is
943 * remapped.
944 */
945 if (win->number == -1)
946 warnx("attempting to withdraw '%s' with number -1!",
947 window_name(win));
948
949 numset_release(rp_window_numset, win->number);
950 win->number = -1;
951
952 list_move_tail(&win->node, &rp_unmapped_window);
953
954 /* Update the vscreens. */
955 vscreen_unmap_window(win->vscreen, win);
956
957 ignore_badwindow++;
958
959 XRemoveFromSaveSet(dpy, win->w);
960 set_state(win, WithdrawnState);
961 XSync(dpy, False);
962
963 ignore_badwindow--;
964
965 /* Call our hook */
966 hook_run(&rp_delete_window_hook);
967}
968
969/* Hide all other mapped windows except for win in win's frame. */
970void
971hide_others(rp_window *win)
972{
973 rp_frame *frame;
974 rp_window *cur;
975
976 if (win == NULL)
977 return;
978 frame = find_windows_frame(win);
979 if (frame == NULL)
980 return;
981
982 list_for_each_entry(cur, &rp_mapped_window, node) {
983 if (find_windows_frame(cur)
984 || cur->state != NormalState
985 || cur->frame_number != frame->number)
986 continue;
987
988 hide_window(cur);
989 }
990}
991
992/* Hide any window displayed on the given screen */
993void
994hide_vscreen_windows(rp_vscreen *v)
995{
996 rp_window *cur;
997
998 list_for_each_entry(cur, &rp_mapped_window, node)
999 if (cur->vscreen == v)
1000 hide_window(cur);
1001}
1002
1003void
1004raise_utility_windows(void)
1005{
1006 unsigned int i, nwins;
1007 Window dw1, dw2, *wins;
1008
1009 XQueryTree(dpy, rp_glob_screen.root, &dw1, &dw2, &wins, &nwins);
1010
1011 for (i = 0; i < nwins; i++) {
1012 if (!is_rp_window(wins[i]) &&
1013 is_unmanaged_window_type(wins[i]))
1014 XRaiseWindow(dpy, wins[i]);
1015 }
1016
1017 XFree(wins);
1018}