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
36 static char **unmanaged_window_list = NULL;
37 static int num_unmanaged_windows = 0;
38
39 void
clear_unmanaged_list(void)40 clear_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
56 char *
list_unmanaged_windows(void)57 list_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
79 void
add_unmanaged_window(char * name)80 add_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
100 void
grab_top_level_keys(Window w)101 grab_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
125 void
ungrab_top_level_keys(Window w)126 ungrab_top_level_keys (Window w)
127 {
128 XUngrabKey(dpy, AnyKey, AnyModifier, w);
129 }
130
131 void
ungrab_keys_all_wins(void)132 ungrab_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
143 void
grab_keys_all_wins(void)144 grab_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
155 void
update_normal_hints(rp_window * win)156 update_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
177 static char *
get_wmname(Window w)178 get_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 (defaults.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 (defaults.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
271 static XClassHint *
get_class_hints(Window w)272 get_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. */
291 int
update_window_name(rp_window * win)292 update_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 /* Send an artificial configure event to the window. */
331 void
send_configure(Window w,int x,int y,int width,int height,int border)332 send_configure (Window w, int x, int y, int width, int height, int border)
333 {
334 XConfigureEvent ce;
335
336 ce.type = ConfigureNotify;
337 ce.event = w;
338 ce.window = w;
339 ce.x = x;
340 ce.y = y;
341 ce.width = width;
342 ce.height = height;
343 ce.border_width = border;
344 ce.above = None;
345 ce.override_redirect = 0;
346
347 XSendEvent (dpy, w, False, StructureNotifyMask, (XEvent*)&ce);
348 }
349
350 /* This function is used to determine if the window should be treated
351 as a transient. */
352 int
window_is_transient(rp_window * win)353 window_is_transient (rp_window *win)
354 {
355 return win->transient
356 #ifdef ASPECT_WINDOWS_ARE_TRANSIENTS
357 || win->hints->flags & PAspect
358 #endif
359 #ifdef MAXSIZE_WINDOWS_ARE_TRANSIENTS
360 || (win->hints->flags & PMaxSize
361 && (win->hints->max_width < win->scr->width
362 || win->hints->max_height < win->scr->height))
363 #endif
364 ;
365 }
366
367 static Atom
get_net_wm_window_type(rp_window * win)368 get_net_wm_window_type (rp_window *win)
369 {
370 Atom type, window_type = None;
371 int format;
372 unsigned long nitems;
373 unsigned long bytes_left;
374 unsigned char *data;
375
376 if (win == NULL)
377 return None;
378
379 if (XGetWindowProperty (dpy, win->w, _net_wm_window_type, 0, 1L,
380 False, XA_ATOM, &type, &format,
381 &nitems, &bytes_left,
382 &data) == Success && nitems > 0)
383 {
384 window_type = *(Atom *)data;
385 XFree (data);
386 PRINT_DEBUG(("hey ya %ld %ld\n", window_type, _net_wm_window_type_dialog));
387 }
388
389 return window_type;
390 }
391
392
393 void
update_window_information(rp_window * win)394 update_window_information (rp_window *win)
395 {
396 XWindowAttributes attr;
397
398 update_window_name (win);
399
400 /* Get the WM Hints */
401 update_normal_hints (win);
402
403 /* Get the colormap */
404 XGetWindowAttributes (dpy, win->w, &attr);
405 win->colormap = attr.colormap;
406 win->x = attr.x;
407 win->y = attr.y;
408 win->width = attr.width;
409 win->height = attr.height;
410 win->border = attr.border_width;
411
412 /* Transient status */
413 win->transient = XGetTransientForHint (dpy, win->w, &win->transient_for);
414
415 if (get_net_wm_window_type(win) == _net_wm_window_type_dialog)
416 win->transient = 1;
417
418 update_window_gravity (win);
419 }
420
421 void
unmanage(rp_window * w)422 unmanage (rp_window *w)
423 {
424 list_del (&w->node);
425 groups_del_window (w);
426
427 free_window (w);
428
429 #ifdef AUTO_CLOSE
430 if (rp_mapped_window.next == &rp_mapped_window
431 && rp_mapped_window.prev == &rp_mapped_window)
432 {
433 /* If the mapped window list is empty then we have run out of
434 managed windows, so kill ratpoison. */
435
436 /* FIXME: The unmapped window list may also have to be checked
437 in the case that the only mapped window in unmapped and
438 shortly after another window is mapped most likely by the
439 same app. */
440
441 kill_signalled = 1;
442 }
443 #endif
444 }
445
446 /* When starting up scan existing windows and start managing them. */
447 void
scanwins(void)448 scanwins (void)
449 {
450 rp_window *win;
451 XWindowAttributes attr;
452 unsigned int i, nwins;
453 Window dw1, dw2, *wins;
454
455 XQueryTree(dpy, rp_glob_screen.root, &dw1, &dw2, &wins, &nwins);
456 PRINT_DEBUG (("windows: %d\n", nwins));
457
458 for (i = 0; i < nwins; i++)
459 {
460 rp_screen *screen;
461
462 XGetWindowAttributes(dpy, wins[i], &attr);
463 if (is_rp_window (wins[i])
464 || attr.override_redirect == True
465 || unmanaged_window (wins[i])) continue;
466
467
468 screen = find_screen_by_attr (attr);
469 if (!screen)
470 list_first (screen, &rp_screens, node);
471
472 win = add_to_window_list (screen, wins[i]);
473
474 PRINT_DEBUG (("map_state: %s\n",
475 attr.map_state == IsViewable ? "IsViewable":
476 attr.map_state == IsUnviewable ? "IsUnviewable" : "IsUnmapped"));
477 PRINT_DEBUG (("state: %s\n",
478 get_state(win) == IconicState ? "Iconic":
479 get_state(win) == NormalState ? "Normal" : "Other"));
480
481 /* Collect mapped and iconized windows. */
482 if (attr.map_state == IsViewable
483 || (attr.map_state == IsUnmapped
484 && get_state (win) == IconicState))
485 map_window (win);
486 }
487
488 XFree(wins);
489 }
490
491 int
unmanaged_window(Window w)492 unmanaged_window (Window w)
493 {
494 char *wname;
495 int i;
496
497 if (!unmanaged_window_list)
498 return 0;
499
500 wname = get_wmname (w);
501 if (!wname)
502 return 0;
503
504 for (i = 0; i < num_unmanaged_windows; i++)
505 {
506 if (!strcmp (unmanaged_window_list[i], wname))
507 {
508 free (wname);
509 return 1;
510 }
511 }
512
513 free (wname);
514 return 0;
515 }
516
517 /* Set the state of the window. */
518 void
set_state(rp_window * win,int state)519 set_state (rp_window *win, int state)
520 {
521 long data[2];
522
523 win->state = state;
524
525 data[0] = (long)win->state;
526 data[1] = (long)None;
527
528 XChangeProperty (dpy, win->w, wm_state, wm_state, 32,
529 PropModeReplace, (unsigned char *)data, 2);
530 }
531
532 /* Get the WM state of the window. */
533 long
get_state(rp_window * win)534 get_state (rp_window *win)
535 {
536 long state = WithdrawnState;
537 Atom type;
538 int format;
539 unsigned long nitems;
540 unsigned long bytes_left;
541 unsigned char *data;
542
543 if (win == NULL)
544 return state;
545
546 if (XGetWindowProperty (dpy, win->w, wm_state, 0L, 2L,
547 False, wm_state, &type, &format,
548 &nitems, &bytes_left,
549 &data) == Success && nitems > 0)
550 {
551 state = *(long *)data;
552 XFree (data);
553 }
554
555 return state;
556 }
557
558 static void
move_window(rp_window * win)559 move_window (rp_window *win)
560 {
561 rp_frame *frame;
562
563 if (win->frame_number == EMPTY)
564 return;
565
566 frame = win_get_frame (win);
567
568 /* X coord. */
569 switch (win->gravity)
570 {
571 case NorthWestGravity:
572 case WestGravity:
573 case SouthWestGravity:
574 win->x = frame->x;
575 break;
576 case NorthGravity:
577 case CenterGravity:
578 case SouthGravity:
579 win->x = frame->x + (frame->width - win->border * 2) / 2 - win->width / 2;
580 break;
581 case NorthEastGravity:
582 case EastGravity:
583 case SouthEastGravity:
584 win->x = frame->x + frame->width - win->width - win->border;
585 break;
586 }
587
588 /* Y coord. */
589 switch (win->gravity)
590 {
591 case NorthEastGravity:
592 case NorthGravity:
593 case NorthWestGravity:
594 win->y = frame->y;
595 break;
596 case EastGravity:
597 case CenterGravity:
598 case WestGravity:
599 win->y = frame->y + (frame->height - win->border * 2) / 2 - win->height / 2;
600 break;
601 case SouthEastGravity:
602 case SouthGravity:
603 case SouthWestGravity:
604 win->y = frame->y + frame->height - win->height - win->border;
605 break;
606 }
607 }
608
609 /* Set a transient window's x,y,width,height fields to maximize the
610 window. */
611 static void
maximize_transient(rp_window * win)612 maximize_transient (rp_window *win)
613 {
614 rp_frame *frame;
615 int maxx, maxy;
616
617 frame = win_get_frame (win);
618
619 /* We can't maximize a window if it has no frame. */
620 if (frame == NULL)
621 return;
622
623 /* Set the window's border */
624 win->border = defaults.window_border_width;
625
626 /* Always use the window's current width and height for
627 transients. */
628 maxx = win->width;
629 maxy = win->height;
630
631 /* Fit the window inside its frame (if it has one) */
632 if (frame)
633 {
634 PRINT_DEBUG (("frame width=%d height=%d\n",
635 frame->width, frame->height));
636
637 if (maxx + win->border * 2 > frame->width) maxx = frame->width - win->border * 2;
638 if (maxy + win->border * 2 > frame->height) maxy = frame->height - win->border * 2;
639 }
640
641 /* Make sure we maximize to the nearest Resize Increment specified
642 by the window */
643 if (win->hints->flags & PResizeInc)
644 {
645 int amount;
646 int delta;
647
648 /* Avoid a divide by zero if width/height_inc is 0. */
649 if (win->hints->width_inc)
650 {
651 amount = maxx - win->width;
652 delta = amount % win->hints->width_inc;
653 amount -= delta;
654 if (amount < 0 && delta) amount -= win->hints->width_inc;
655 maxx = amount + win->width;
656 }
657
658 if (win->hints->height_inc)
659 {
660 amount = maxy - win->height;
661 delta = amount % win->hints->height_inc;
662 amount -= delta;
663 if (amount < 0 && delta) amount -= win->hints->height_inc;
664 maxy = amount + win->height;
665 }
666 }
667
668 PRINT_DEBUG (("maxsize: %d %d\n", maxx, maxy));
669
670 win->width = maxx;
671 win->height = maxy;
672 }
673
674 /* set a good standard window's x,y,width,height fields to maximize
675 the window. */
676 static void
maximize_normal(rp_window * win)677 maximize_normal (rp_window *win)
678 {
679 rp_frame *frame;
680 int maxx, maxy;
681
682 frame = win_get_frame (win);
683
684 /* We can't maximize a window if it has no frame. */
685 if (frame == NULL)
686 return;
687
688 /* Set the window's border */
689 win->border = defaults.window_border_width;
690
691 /* Honour the window's maximum size */
692 if (win->hints->flags & PMaxSize)
693 {
694 maxx = win->hints->max_width;
695 maxy = win->hints->max_height;
696 }
697 else
698 {
699 maxx = frame->width - win->border * 2;
700 maxy = frame->height - win->border * 2;
701 }
702
703 /* Honour the window's aspect ratio. */
704 PRINT_DEBUG (("aspect: %ld\n", win->hints->flags & PAspect));
705 if (win->hints->flags & PAspect)
706 {
707 float ratio = (float)maxx / maxy;
708 float min_ratio = (float)win->hints->min_aspect.x / win->hints->min_aspect.y;
709 float max_ratio = (float)win->hints->max_aspect.x / win->hints->max_aspect.y;
710 PRINT_DEBUG (("ratio=%f min_ratio=%f max_ratio=%f\n",
711 ratio,min_ratio,max_ratio));
712 if (ratio < min_ratio)
713 {
714 maxy = (int) (maxx / min_ratio);
715 }
716 else if (ratio > max_ratio)
717 {
718 maxx = (int) (maxy * max_ratio);
719 }
720 }
721
722 /* Fit the window inside its frame (if it has one) */
723 if (frame)
724 {
725 PRINT_DEBUG (("frame width=%d height=%d\n",
726 frame->width, frame->height));
727
728 if (maxx > frame->width) maxx = frame->width - win->border * 2;
729 if (maxy > frame->height) maxy = frame->height - win->border * 2;
730 }
731
732 /* Make sure we maximize to the nearest Resize Increment specified
733 by the window */
734 if (win->hints->flags & PResizeInc)
735 {
736 int amount;
737 int delta;
738
739 if (win->hints->width_inc)
740 {
741 amount = maxx - win->width;
742 delta = amount % win->hints->width_inc;
743 if (amount < 0 && delta) amount -= win->hints->width_inc;
744 amount -= delta;
745 maxx = amount + win->width;
746 }
747
748 if (win->hints->height_inc)
749 {
750 amount = maxy - win->height;
751 delta = amount % win->hints->height_inc;
752 if (amount < 0 && delta) amount -= win->hints->height_inc;
753 amount -= delta;
754 maxy = amount + win->height;
755 }
756 }
757
758 PRINT_DEBUG (("maxsize: %d %d\n", maxx, maxy));
759
760 win->width = maxx;
761 win->height = maxy;
762 }
763
764 /* Maximize the current window if data = 0, otherwise assume it is a
765 pointer to a window that should be maximized */
766 void
maximize(rp_window * win)767 maximize (rp_window *win)
768 {
769 if (!win) win = current_window();
770 if (!win) return;
771
772 /* Handle maximizing transient windows differently. */
773 if (win->transient)
774 maximize_transient (win);
775 else
776 maximize_normal (win);
777
778 /* Reposition the window. */
779 move_window (win);
780
781 PRINT_DEBUG (("Resizing window '%s' to x:%d y:%d w:%d h:%d\n", window_name (win),
782 win->x, win->y, win->width, win->height));
783
784
785 /* Actually do the maximizing. */
786 XMoveResizeWindow (dpy, win->w, win->scr->left + win->x, win->scr->top + win->y, win->width, win->height);
787 XSetWindowBorderWidth (dpy, win->w, win->border);
788
789 XSync (dpy, False);
790 }
791
792 /* Maximize the current window but don't treat transient windows
793 differently. */
794 void
force_maximize(rp_window * win)795 force_maximize (rp_window *win)
796 {
797 if (!win) win = current_window();
798 if (!win) return;
799
800 maximize_normal(win);
801
802 /* Reposition the window. */
803 move_window (win);
804
805 /* This little dance is to force a maximize event. If the window is
806 already "maximized" X11 will optimize away the event since to
807 geometry changes were made. This initial resize solves the
808 problem. */
809 if (win->hints->flags & PResizeInc)
810 {
811 XMoveResizeWindow (dpy, win->w, win->scr->left + win->x, win->scr->top + win->y,
812 win->width + win->hints->width_inc,
813 win->height + win->hints->height_inc);
814 }
815 else
816 {
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->scr->left + win->x, win->scr->top + win->y, win->width, win->height);
824 XSetWindowBorderWidth (dpy, win->w, win->border);
825
826 XSync (dpy, False);
827 }
828
829 /* map the unmapped window win */
830 void
map_window(rp_window * win)831 map_window (rp_window *win)
832 {
833 PRINT_DEBUG (("Mapping the unmapped window %s\n", window_name (win)));
834
835 /* Fill in the necessary data about the window */
836 update_window_information (win);
837 win->number = numset_request (rp_window_numset);
838 grab_top_level_keys (win->w);
839
840 /* Put win in the mapped window list */
841 list_del (&win->node);
842 insert_into_list (win, &rp_mapped_window);
843
844 /* Update all groups. */
845 groups_map_window (win);
846
847 /* The window has never been accessed since it was brought back from
848 the Withdrawn state. */
849 win->last_access = 0;
850
851 /* It is now considered iconic and set_active_window can handle the rest. */
852 set_state (win, IconicState);
853
854 /* Depending on the rudeness level, actually map the window. */
855 if ((rp_honour_transient_map && win->transient)
856 || (rp_honour_normal_map && !win->transient))
857 set_active_window (win);
858 else
859 show_rudeness_msg (win, 0);
860
861 hook_run (&rp_new_window_hook);
862 }
863
864 void
hide_window(rp_window * win)865 hide_window (rp_window *win)
866 {
867 if (win == NULL) return;
868
869 /* An unmapped window is not inside a frame. */
870 win->frame_number = EMPTY;
871
872 /* Ignore the unmap_notify event. */
873 XSelectInput(dpy, win->w, WIN_EVENTS&~(StructureNotifyMask));
874 XUnmapWindow (dpy, win->w);
875 XSelectInput (dpy, win->w, WIN_EVENTS);
876 /* Ensure that the window doesn't have the focused border
877 color. This is needed by remove_frame and possibly others. */
878 XSetWindowBorder (dpy, win->w, rp_glob_screen.bw_color);
879 set_state (win, IconicState);
880 }
881
882 void
unhide_window(rp_window * win)883 unhide_window (rp_window *win)
884 {
885 if (win == NULL) return;
886
887 /* Always raise the window. */
888 XRaiseWindow (dpy, win->w);
889
890 if (win->state != IconicState) return;
891
892 XMapWindow (dpy, win->w);
893 set_state (win, NormalState);
894 }
895
896 void
unhide_all_windows(void)897 unhide_all_windows (void)
898 {
899 struct list_head *tmp, *iter;
900 rp_window *win;
901
902 list_for_each_safe_entry (win, iter, tmp, &rp_mapped_window, node)
903 unhide_window (win);
904 }
905
906 /* same as unhide_window except that it makes sure the window is mapped
907 on the bottom of the window stack. */
908 void
unhide_window_below(rp_window * win)909 unhide_window_below (rp_window *win)
910 {
911 if (win == NULL) return;
912
913 /* Always lower the window, but if its not iconic we don't need to
914 map it since it already is mapped. */
915 XLowerWindow (dpy, win->w);
916
917 if (win->state != IconicState) return;
918
919 XMapWindow (dpy, win->w);
920 set_state (win, NormalState);
921 }
922
923 void
withdraw_window(rp_window * win)924 withdraw_window (rp_window *win)
925 {
926 if (win == NULL) return;
927
928 PRINT_DEBUG (("withdraw_window on '%s'\n", window_name (win)));
929
930 /* Give back the window number. the window will get another one,
931 if it is remapped. */
932 if (win->number == -1)
933 PRINT_ERROR(("Attempting to withdraw '%s' with number -1!\n", window_name(win)));
934
935 numset_release (rp_window_numset, win->number);
936 win->number = -1;
937
938 list_move_tail(&win->node, &rp_unmapped_window);
939
940 /* Update the groups. */
941 groups_unmap_window (win);
942
943 ignore_badwindow++;
944
945 XRemoveFromSaveSet (dpy, win->w);
946 set_state (win, WithdrawnState);
947 XSync (dpy, False);
948
949 ignore_badwindow--;
950
951 /* Call our hook */
952 hook_run (&rp_delete_window_hook);
953 }
954
955 /* Hide all other mapped windows except for win in win's frame. */
956 void
hide_others(rp_window * win)957 hide_others (rp_window *win)
958 {
959 rp_frame *frame;
960 rp_window *cur;
961
962 if (win == NULL) return;
963 frame = find_windows_frame (win);
964 if (frame == NULL) return;
965
966 list_for_each_entry (cur, &rp_mapped_window, node)
967 {
968 if (find_windows_frame (cur)
969 || cur->state != NormalState
970 || cur->frame_number != frame->number)
971 continue;
972
973 hide_window (cur);
974 }
975 }
976
977 /* Hide any window displayed on the given screen */
978 void
hide_screen_windows(rp_screen * s)979 hide_screen_windows (rp_screen *s)
980 {
981 rp_frame *cur_frame;
982 rp_window *cur_win;
983
984 list_for_each_entry (cur_frame, &s->frames, node)
985 {
986 cur_win = find_window_number (cur_frame->win_number);
987 hide_window (cur_win);
988 }
989 }
990