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