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