Maximus: Tiled Maximization
[wmaker-crm.git] / src / actions.c
1 /* action.c- misc. window commands (miniaturize, hide etc.)
2  *
3  *  Window Maker window manager
4  *
5  *  Copyright (c) 1997-2003 Alfredo K. Kojima
6  *  Copyright (c) 1998-2003 Dan Pascu
7  *
8  *  This program 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 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program 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 program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21  *  USA.
22  */
23
24 #include "wconfig.h"
25
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <math.h>
32 #include <time.h>
33
34 #include "WindowMaker.h"
35 #include "wcore.h"
36 #include "framewin.h"
37 #include "window.h"
38 #include "client.h"
39 #include "icon.h"
40 #include "funcs.h"
41 #include "application.h"
42 #include "actions.h"
43 #include "stacking.h"
44 #include "appicon.h"
45 #include "dock.h"
46 #include "appmenu.h"
47 #include "winspector.h"
48 #include "workspace.h"
49 #include "wsound.h"
50 #include "xinerama.h"
51
52 /****** Global Variables ******/
53 extern Time LastTimestamp;
54 extern Time LastFocusChange;
55
56 extern Cursor wCursor[WCUR_LAST];
57
58 extern WPreferences wPreferences;
59
60 extern Atom _XA_WM_TAKE_FOCUS;
61
62 extern void ProcessPendingEvents();
63 extern int calcIntersectionLength(int p1, int l1, int p2, int l2);
64
65 static void find_Maximus_geometry(WWindow *wwin, WArea usableArea, int *new_x,
66                                   int *new_y, int *new_width, int *new_height);
67
68 /******* Local Variables *******/
69 static struct {
70         int steps;
71         int delay;
72 } shadePars[5] = {
73         {
74         SHADE_STEPS_UF, SHADE_DELAY_UF}, {
75         SHADE_STEPS_F, SHADE_DELAY_F}, {
76         SHADE_STEPS_M, SHADE_DELAY_M}, {
77         SHADE_STEPS_S, SHADE_DELAY_S}, {
78 SHADE_STEPS_US, SHADE_DELAY_US}};
79
80 #define UNSHADE         0
81 #define SHADE           1
82 #define SHADE_STEPS     shadePars[(int)wPreferences.shade_speed].steps
83 #define SHADE_DELAY     shadePars[(int)wPreferences.shade_speed].delay
84
85 static int compareTimes(Time t1, Time t2)
86 {
87         Time diff;
88         if (t1 == t2)
89                 return 0;
90         diff = t1 - t2;
91         return (diff < 60000) ? 1 : -1;
92 }
93
94 /*
95  *----------------------------------------------------------------------
96  * wSetFocusTo--
97  *      Changes the window focus to the one passed as argument.
98  * If the window to focus is not already focused, it will be brought
99  * to the head of the list of windows. Previously focused window is
100  * unfocused.
101  *
102  * Side effects:
103  *      Window list may be reordered and the window focus is changed.
104  *
105  *----------------------------------------------------------------------
106  */
107 void wSetFocusTo(WScreen * scr, WWindow * wwin)
108 {
109         static WScreen *old_scr = NULL;
110
111         WWindow *old_focused;
112         WWindow *focused = scr->focused_window;
113         Time timestamp = LastTimestamp;
114         WApplication *oapp = NULL, *napp = NULL;
115         int wasfocused;
116
117         if (scr->flags.ignore_focus_events || compareTimes(LastFocusChange, timestamp) > 0)
118                 return;
119
120         if (!old_scr)
121                 old_scr = scr;
122         old_focused = old_scr->focused_window;
123
124         LastFocusChange = timestamp;
125
126         if (old_focused)
127                 oapp = wApplicationOf(old_focused->main_window);
128
129         if (wwin == NULL) {
130                 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
131                 if (old_focused) {
132                         wWindowUnfocus(old_focused);
133                 }
134                 if (oapp) {
135                         wAppMenuUnmap(oapp->menu);
136 #ifdef NEWAPPICON
137                         wApplicationDeactivate(oapp);
138 #endif
139                 }
140
141                 WMPostNotificationName(WMNChangedFocus, NULL, (void *)True);
142                 return;
143         } else if (old_scr != scr && old_focused) {
144                 wWindowUnfocus(old_focused);
145         }
146
147         wasfocused = wwin->flags.focused;
148         napp = wApplicationOf(wwin->main_window);
149
150         /* remember last workspace where the app has been */
151         if (napp) {
152                 /*napp->last_workspace = wwin->screen_ptr->current_workspace; */
153                 napp->last_workspace = wwin->frame->workspace;
154         }
155
156         if (wwin->flags.mapped && !WFLAGP(wwin, no_focusable)) {
157                 /* install colormap if colormap mode is lock mode */
158                 if (wPreferences.colormap_mode == WCM_CLICK)
159                         wColormapInstallForWindow(scr, wwin);
160
161                 /* set input focus */
162                 switch (wwin->focus_mode) {
163                 case WFM_NO_INPUT:
164                         XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
165                         break;
166
167                 case WFM_PASSIVE:
168                 case WFM_LOCALLY_ACTIVE:
169                         XSetInputFocus(dpy, wwin->client_win, RevertToParent, CurrentTime);
170                         break;
171
172                 case WFM_GLOBALLY_ACTIVE:
173                         break;
174                 }
175                 XFlush(dpy);
176                 if (wwin->protocols.TAKE_FOCUS) {
177                         wClientSendProtocol(wwin, _XA_WM_TAKE_FOCUS, timestamp);
178                 }
179                 XSync(dpy, False);
180         } else {
181                 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
182         }
183         if (WFLAGP(wwin, no_focusable))
184                 return;
185
186         /* if this is not the focused window focus it */
187         if (focused != wwin) {
188                 /* change the focus window list order */
189                 if (wwin->prev)
190                         wwin->prev->next = wwin->next;
191
192                 if (wwin->next)
193                         wwin->next->prev = wwin->prev;
194
195                 wwin->prev = focused;
196                 focused->next = wwin;
197                 wwin->next = NULL;
198                 scr->focused_window = wwin;
199
200                 if (oapp && oapp != napp) {
201                         wAppMenuUnmap(oapp->menu);
202 #ifdef NEWAPPICON
203                         wApplicationDeactivate(oapp);
204 #endif
205                 }
206         }
207
208         wWindowFocus(wwin, focused);
209
210         if (napp && !wasfocused) {
211 #ifdef USER_MENU
212                 wUserMenuRefreshInstances(napp->menu, wwin);
213 #endif                          /* USER_MENU */
214
215                 if (wwin->flags.mapped)
216                         wAppMenuMap(napp->menu, wwin);
217 #ifdef NEWAPPICON
218                 wApplicationActivate(napp);
219 #endif
220         }
221
222         XFlush(dpy);
223         old_scr = scr;
224 }
225
226 void wShadeWindow(WWindow *wwin)
227 {
228
229         if (wwin->flags.shaded)
230                 return;
231
232         XLowerWindow(dpy, wwin->client_win);
233         wSoundPlay(WSOUND_SHADE);
234         shade_animate(wwin, SHADE);
235
236         wwin->flags.skip_next_animation = 0;
237         wwin->flags.shaded = 1;
238         wwin->flags.mapped = 0;
239         /* prevent window withdrawal when getting UnmapNotify */
240         XSelectInput(dpy, wwin->client_win, wwin->event_mask & ~StructureNotifyMask);
241         XUnmapWindow(dpy, wwin->client_win);
242         XSelectInput(dpy, wwin->client_win, wwin->event_mask);
243
244         /* for the client it's just like iconification */
245         wFrameWindowResize(wwin->frame, wwin->frame->core->width, wwin->frame->top_width - 1);
246
247         wwin->client.y = wwin->frame_y - wwin->client.height + wwin->frame->top_width;
248         wWindowSynthConfigureNotify(wwin);
249
250         /*
251            wClientSetState(wwin, IconicState, None);
252          */
253
254         WMPostNotificationName(WMNChangedState, wwin, "shade");
255
256 #ifdef ANIMATIONS
257         if (!wwin->screen_ptr->flags.startup) {
258                 /* Catch up with events not processed while animation was running */
259                 ProcessPendingEvents();
260         }
261 #endif
262 }
263
264 void wUnshadeWindow(WWindow *wwin)
265 {
266
267         if (!wwin->flags.shaded)
268                 return;
269
270         wwin->flags.shaded = 0;
271         wwin->flags.mapped = 1;
272         XMapWindow(dpy, wwin->client_win);
273
274         wSoundPlay(WSOUND_UNSHADE);
275         shade_animate(wwin, UNSHADE);
276
277         wwin->flags.skip_next_animation = 0;
278         wFrameWindowResize(wwin->frame, wwin->frame->core->width,
279                            wwin->frame->top_width + wwin->client.height + wwin->frame->bottom_width);
280
281         wwin->client.y = wwin->frame_y + wwin->frame->top_width;
282         wWindowSynthConfigureNotify(wwin);
283
284         /*
285            wClientSetState(wwin, NormalState, None);
286          */
287         /* if the window is focused, set the focus again as it was disabled during
288          * shading */
289         if (wwin->flags.focused)
290                 wSetFocusTo(wwin->screen_ptr, wwin);
291
292         WMPostNotificationName(WMNChangedState, wwin, "shade");
293 }
294
295 void wMaximizeWindow(WWindow * wwin, int directions)
296 {
297         int new_x, new_y;
298         unsigned int new_width, new_height, half_scr_width;
299         int changed_h, changed_v, shrink_h, shrink_v;
300         WArea usableArea, totalArea;
301
302         if (!IS_RESIZABLE(wwin))
303                 return;
304
305         totalArea.x1 = 0;
306         totalArea.y1 = 0;
307         totalArea.x2 = wwin->screen_ptr->scr_width;
308         totalArea.y2 = wwin->screen_ptr->scr_height;
309         usableArea = totalArea;
310
311         if (!(directions & MAX_IGNORE_XINERAMA)) {
312                 WScreen *scr = wwin->screen_ptr;
313                 int head;
314
315                 if (directions & MAX_KEYBOARD)
316                         head = wGetHeadForWindow(wwin);
317                 else
318                         head = wGetHeadForPointerLocation(scr);
319
320                 usableArea = wGetUsableAreaForHead(scr, head, &totalArea, True);
321         }
322
323         if (WFLAGP(wwin, full_maximize)) {
324                 usableArea = totalArea;
325         }
326         half_scr_width = (usableArea.x2 - usableArea.x1)/2;
327
328         if (wwin->flags.shaded) {
329                 wwin->flags.skip_next_animation = 1;
330                 wUnshadeWindow(wwin);
331         }
332         /* Only save directions, not kbd or xinerama hints */
333         directions &= (MAX_HORIZONTAL | MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS);
334
335         changed_h = ((wwin->flags.maximized ^ directions) & MAX_HORIZONTAL);
336         changed_v = ((wwin->flags.maximized ^ directions) & MAX_VERTICAL);
337         shrink_h = (changed_h && (directions & MAX_HORIZONTAL) == 0);
338         shrink_v = (changed_v && (directions & MAX_VERTICAL) == 0);
339
340         if (wwin->flags.maximized) {
341                 /* if already maximized in some direction, we only update the
342                  * appropriate old x, old y coordinates. This is necessary to
343                  * allow succesive maximizations in different directions without
344                  * the need to first do an un-maximize (to avoid flicker).
345                  */
346                 if (!(wwin->flags.maximized & (MAX_HORIZONTAL|MAX_LEFTHALF|MAX_RIGHTHALF))) {
347                         wwin->old_geometry.x = wwin->frame_x;
348                 }
349                 if (!(wwin->flags.maximized & MAX_VERTICAL)) {
350                         wwin->old_geometry.y = wwin->frame_y;
351                 }
352         } else {
353                 wwin->old_geometry.width = wwin->client.width;
354                 wwin->old_geometry.height = wwin->client.height;
355                 wwin->old_geometry.x = wwin->frame_x;
356                 wwin->old_geometry.y = wwin->frame_y;
357         }
358         wwin->flags.maximized = directions;
359
360         if (directions & MAX_HORIZONTAL) {
361                 new_width = usableArea.x2 - usableArea.x1;
362                 if (HAS_BORDER(wwin))
363                         new_width -= FRAME_BORDER_WIDTH * 2;
364                 new_x = usableArea.x1;
365         } else if (directions & MAX_LEFTHALF) {
366                 new_width = half_scr_width;
367                 if (HAS_BORDER(wwin))
368                         new_width -= FRAME_BORDER_WIDTH * 2;
369                 new_x = usableArea.x1;
370         } else if (directions & MAX_RIGHTHALF) {
371                 new_width = half_scr_width;
372                 if (HAS_BORDER(wwin))
373                         new_width -= FRAME_BORDER_WIDTH * 2;
374                 new_x = usableArea.x1 + half_scr_width;
375         } else if (shrink_h) {
376                 new_x = wwin->old_geometry.x;
377                 new_width = wwin->old_geometry.width;
378         } else {
379                 new_x = wwin->frame_x;
380                 new_width = wwin->frame->core->width;
381         }
382
383         if (directions & MAX_VERTICAL) {
384                 new_height = usableArea.y2 - usableArea.y1;
385                 if (HAS_BORDER(wwin))
386                         new_height -= FRAME_BORDER_WIDTH * 2;
387                 new_y = usableArea.y1;
388                 if (WFLAGP(wwin, full_maximize)) {
389                         new_y -= wwin->frame->top_width;
390                         new_height += wwin->frame->bottom_width - 1;
391                 }
392         } else if (shrink_v) {
393                 new_y = wwin->old_geometry.y;
394                 new_height = wwin->old_geometry.height;
395         } else {
396                 new_y = wwin->frame_y;
397                 new_height = wwin->frame->core->height;
398         }
399
400         if (!WFLAGP(wwin, full_maximize)) {
401                 new_height -= wwin->frame->top_width + wwin->frame->bottom_width;
402         }
403
404         if (directions & MAX_MAXIMUS)
405                 find_Maximus_geometry(wwin, usableArea, &new_x, &new_y, &new_width, &new_height);
406
407         wWindowConstrainSize(wwin, &new_width, &new_height);
408
409         wWindowCropSize(wwin, usableArea.x2 - usableArea.x1,
410                         usableArea.y2 - usableArea.y1, &new_width, &new_height);
411
412         wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
413
414         WMPostNotificationName(WMNChangedState, wwin, "maximize");
415
416         wSoundPlay(WSOUND_MAXIMIZE);
417 }
418
419 /*
420  * Maximus: tiled maximization (maximize without overlapping other windows)
421  *
422  * The window to be maximized will be denoted by w_0 (sub-index zero)
423  * while the windows which will stop the maximization of w_0 are denoted by w_j.
424  */
425 static void find_Maximus_geometry(WWindow *wwin, WArea usableArea, int *new_x, int *new_y,
426                                   int *new_width, int *new_height)
427 {
428         WWindow *tmp;
429         int x_0            = wwin->frame_x;
430         int y_0            = wwin->frame_y;
431         int width_0        = wwin->frame->core->width;
432         int height_0       = wwin->frame->core->height;
433         int botton_0       = y_0 + height_0;
434         int right_border_0 = x_0 + width_0;
435         int new_x_0, new_y_0, new_botton_0, new_right_border_0, new_height_0;
436         int x_j,  y_j, width_j, height_j, botton_j, top_j, right_border_j;
437         int x_intsect, y_intsect;
438         /* Assume that the window w_0 has titlebar etc */
439         int has_titlebar = 1, has_resizebar = 1, has_border = 1;
440         int adjust_height, adjust_width;
441
442         /* Try to fully maximize first, then readjust later */
443         new_x_0            = usableArea.x1;
444         new_y_0            = usableArea.y1;
445         new_botton_0       = usableArea.y2;
446         new_right_border_0 = usableArea.x2;
447
448         if (!HAS_TITLEBAR(wwin))
449                 has_titlebar = 0;
450         if (!HAS_RESIZEBAR(wwin))
451                 has_resizebar = 0;
452         if (!HAS_BORDER(wwin))
453                 has_border = 0;
454
455         /* the lengths to be subtracted if w_0 has titlebar, etc */
456         adjust_height = TITLEBAR_HEIGHT * has_titlebar
457                 + 2 * FRAME_BORDER_WIDTH * has_border + RESIZEBAR_HEIGHT * has_resizebar;
458         adjust_width = 2 * FRAME_BORDER_WIDTH * has_border;
459
460         tmp = wwin;
461         /* TODO: Is the focused window always the last in the list? */
462         while (tmp->prev) {
463                 /* ignore windows in other workspaces or minimized */
464                 if (tmp->prev->frame->workspace != wwin->screen_ptr->current_workspace
465                     || tmp->prev->flags.miniaturized) {
466                         tmp = tmp->prev;
467                         continue;
468                 }
469                 tmp = tmp->prev;
470
471                 /* set the w_j window coordinates */
472                 x_j = tmp->frame_x;
473                 y_j = tmp->frame_y;
474                 width_j = tmp->frame->core->width;
475                 height_j = tmp->frame->core->height;
476                 botton_j = y_j + height_j;
477                 top_j = y_j;
478                 right_border_j = x_j + width_j;
479
480                 /* Try to maximize in the y direction first */
481                 x_intsect = calcIntersectionLength(x_0, width_0, x_j, width_j);
482                 if (x_intsect != 0) {
483                         if (botton_j < y_0 && botton_j > new_y_0) {
484                                 /* w_0 is below the botton of w_j */
485                                 new_y_0 = botton_j;
486                         }
487                         if (botton_0 < top_j && top_j < new_botton_0) {
488                                 /* The botton of w_0 is above the top of w_j */
489                                 new_botton_0 = top_j;
490                         }
491                 }
492
493                 /*
494                  * Use the updated y coordinates from the above step to account
495                  * the possibility that the new value of y_0 will have different
496                  * intersections with w_j
497                  */
498                 new_height_0 = new_botton_0 - new_y_0 - adjust_height;
499                 y_intsect = calcIntersectionLength(new_y_0, new_height_0, y_j, height_j);
500                 if (y_intsect != 0) {
501                         if (right_border_j < x_0 && right_border_j > new_x_0) {
502                                 /* w_0 is completely to the right of w_j */
503                                 new_x_0 = right_border_j;
504                         }
505                         if (right_border_0 < x_j && x_j < new_right_border_0) {
506                                 /* w_0 is completely to the left of w_j */
507                                 new_right_border_0 = x_j;
508                         }
509                 }
510         }
511
512         new_height_0 = new_botton_0 - new_y_0 - adjust_height;
513         *new_x = new_x_0;
514         *new_y = new_y_0;
515         *new_height = new_height_0;
516         *new_width = new_right_border_0 - new_x_0 - adjust_width;
517 }
518
519 void wUnmaximizeWindow(WWindow * wwin)
520 {
521         int x, y, w, h;
522
523         if (!wwin->flags.maximized)
524                 return;
525
526         if (wwin->flags.shaded) {
527                 wwin->flags.skip_next_animation = 1;
528                 wUnshadeWindow(wwin);
529         }
530         x = ((wwin->flags.maximized & (MAX_HORIZONTAL|MAX_LEFTHALF|MAX_RIGHTHALF)) && wwin->old_geometry.x) ?
531             wwin->old_geometry.x : wwin->frame_x;
532         y = ((wwin->flags.maximized & MAX_VERTICAL) && wwin->old_geometry.y) ?
533             wwin->old_geometry.y : wwin->frame_y;
534         w = wwin->old_geometry.width ? wwin->old_geometry.width : wwin->client.width;
535         h = wwin->old_geometry.height ? wwin->old_geometry.height : wwin->client.height;
536
537         wwin->flags.maximized = 0;
538         wWindowConfigure(wwin, x, y, w, h);
539
540         WMPostNotificationName(WMNChangedState, wwin, "maximize");
541
542         wSoundPlay(WSOUND_UNMAXIMIZE);
543 }
544
545 void wFullscreenWindow(WWindow * wwin)
546 {
547         int head;
548         WMRect rect;
549
550         if (wwin->flags.fullscreen)
551                 return;
552
553         wwin->flags.fullscreen = True;
554
555         wWindowConfigureBorders(wwin);
556
557         ChangeStackingLevel(wwin->frame->core, WMFullscreenLevel);
558
559         wwin->bfs_geometry.x = wwin->frame_x;
560         wwin->bfs_geometry.y = wwin->frame_y;
561         wwin->bfs_geometry.width = wwin->frame->core->width;
562         wwin->bfs_geometry.height = wwin->frame->core->height;
563
564         head = wGetHeadForWindow(wwin);
565         rect = wGetRectForHead(wwin->screen_ptr, head);
566         wWindowConfigure(wwin, rect.pos.x, rect.pos.y, rect.size.width, rect.size.height);
567
568         WMPostNotificationName(WMNChangedState, wwin, "fullscreen");
569 }
570
571 void wUnfullscreenWindow(WWindow * wwin)
572 {
573         if (!wwin->flags.fullscreen)
574                 return;
575
576         wwin->flags.fullscreen = False;
577
578         if (wwin->frame->core->stacking->window_level == WMFullscreenLevel) {
579                 if (WFLAGP(wwin, sunken)) {
580                         ChangeStackingLevel(wwin->frame->core, WMSunkenLevel);
581                 } else if (WFLAGP(wwin, floating)) {
582                         ChangeStackingLevel(wwin->frame->core, WMFloatingLevel);
583                 } else {
584                         ChangeStackingLevel(wwin->frame->core, WMNormalLevel);
585                 }
586         }
587
588         wWindowConfigure(wwin, wwin->bfs_geometry.x, wwin->bfs_geometry.y,
589                          wwin->bfs_geometry.width, wwin->bfs_geometry.height);
590
591         wWindowConfigureBorders(wwin);
592         /*
593            // seems unnecessary, but also harmless (doesn't generate flicker) -Dan
594            wFrameWindowPaint(wwin->frame);
595          */
596
597         WMPostNotificationName(WMNChangedState, wwin, "fullscreen");
598 }
599
600 #ifdef ANIMATIONS
601 static void animateResizeFlip(WScreen * scr, int x, int y, int w, int h, int fx, int fy, int fw, int fh, int steps)
602 {
603 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
604         float cx, cy, cw, ch;
605         float xstep, ystep, wstep, hstep;
606         XPoint points[5];
607         float dx, dch, midy;
608         float angle, final_angle, delta;
609
610         xstep = (float)(fx - x) / steps;
611         ystep = (float)(fy - y) / steps;
612         wstep = (float)(fw - w) / steps;
613         hstep = (float)(fh - h) / steps;
614
615         cx = (float)x;
616         cy = (float)y;
617         cw = (float)w;
618         ch = (float)h;
619
620         final_angle = 2 * WM_PI * MINIATURIZE_ANIMATION_TWIST_F;
621         delta = (float)(final_angle / FRAMES);
622         for (angle = 0;; angle += delta) {
623                 if (angle > final_angle)
624                         angle = final_angle;
625
626                 dx = (cw / 10) - ((cw / 5) * sin(angle));
627                 dch = (ch / 2) * cos(angle);
628                 midy = cy + (ch / 2);
629
630                 points[0].x = cx + dx;
631                 points[0].y = midy - dch;
632                 points[1].x = cx + cw - dx;
633                 points[1].y = points[0].y;
634                 points[2].x = cx + cw + dx;
635                 points[2].y = midy + dch;
636                 points[3].x = cx - dx;
637                 points[3].y = points[2].y;
638                 points[4].x = points[0].x;
639                 points[4].y = points[0].y;
640
641                 XGrabServer(dpy);
642                 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
643                 XFlush(dpy);
644 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
645                 wusleep(MINIATURIZE_ANIMATION_DELAY_F);
646 #else
647                 wusleep(10);
648 #endif
649
650                 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
651                 XUngrabServer(dpy);
652                 cx += xstep;
653                 cy += ystep;
654                 cw += wstep;
655                 ch += hstep;
656                 if (angle >= final_angle)
657                         break;
658
659         }
660         XFlush(dpy);
661 }
662
663 #undef FRAMES
664
665 static void
666 animateResizeTwist(WScreen * scr, int x, int y, int w, int h, int fx, int fy, int fw, int fh, int steps)
667 {
668 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
669         float cx, cy, cw, ch;
670         float xstep, ystep, wstep, hstep;
671         XPoint points[5];
672         float angle, final_angle, a, d, delta;
673
674         x += w / 2;
675         y += h / 2;
676         fx += fw / 2;
677         fy += fh / 2;
678
679         xstep = (float)(fx - x) / steps;
680         ystep = (float)(fy - y) / steps;
681         wstep = (float)(fw - w) / steps;
682         hstep = (float)(fh - h) / steps;
683
684         cx = (float)x;
685         cy = (float)y;
686         cw = (float)w;
687         ch = (float)h;
688
689         final_angle = 2 * WM_PI * MINIATURIZE_ANIMATION_TWIST_T;
690         delta = (float)(final_angle / FRAMES);
691         for (angle = 0;; angle += delta) {
692                 if (angle > final_angle)
693                         angle = final_angle;
694
695                 a = atan(ch / cw);
696                 d = sqrt((cw / 2) * (cw / 2) + (ch / 2) * (ch / 2));
697
698                 points[0].x = cx + cos(angle - a) * d;
699                 points[0].y = cy + sin(angle - a) * d;
700                 points[1].x = cx + cos(angle + a) * d;
701                 points[1].y = cy + sin(angle + a) * d;
702                 points[2].x = cx + cos(angle - a + WM_PI) * d;
703                 points[2].y = cy + sin(angle - a + WM_PI) * d;
704                 points[3].x = cx + cos(angle + a + WM_PI) * d;
705                 points[3].y = cy + sin(angle + a + WM_PI) * d;
706                 points[4].x = cx + cos(angle - a) * d;
707                 points[4].y = cy + sin(angle - a) * d;
708                 XGrabServer(dpy);
709                 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
710                 XFlush(dpy);
711 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
712                 wusleep(MINIATURIZE_ANIMATION_DELAY_T);
713 #else
714                 wusleep(10);
715 #endif
716
717                 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
718                 XUngrabServer(dpy);
719                 cx += xstep;
720                 cy += ystep;
721                 cw += wstep;
722                 ch += hstep;
723                 if (angle >= final_angle)
724                         break;
725
726         }
727         XFlush(dpy);
728 }
729
730 #undef FRAMES
731
732 static void animateResizeZoom(WScreen * scr, int x, int y, int w, int h, int fx, int fy, int fw, int fh, int steps)
733 {
734 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
735         float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
736         float xstep, ystep, wstep, hstep;
737         int i, j;
738
739         xstep = (float)(fx - x) / steps;
740         ystep = (float)(fy - y) / steps;
741         wstep = (float)(fw - w) / steps;
742         hstep = (float)(fh - h) / steps;
743
744         for (j = 0; j < FRAMES; j++) {
745                 cx[j] = (float)x;
746                 cy[j] = (float)y;
747                 cw[j] = (float)w;
748                 ch[j] = (float)h;
749         }
750         XGrabServer(dpy);
751         for (i = 0; i < steps; i++) {
752                 for (j = 0; j < FRAMES; j++) {
753                         XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
754                                        (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
755                 }
756                 XFlush(dpy);
757 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
758                 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
759 #else
760                 wusleep(10);
761 #endif
762                 for (j = 0; j < FRAMES; j++) {
763                         XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
764                                        (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
765                         if (j < FRAMES - 1) {
766                                 cx[j] = cx[j + 1];
767                                 cy[j] = cy[j + 1];
768                                 cw[j] = cw[j + 1];
769                                 ch[j] = ch[j + 1];
770                         } else {
771                                 cx[j] += xstep;
772                                 cy[j] += ystep;
773                                 cw[j] += wstep;
774                                 ch[j] += hstep;
775                         }
776                 }
777         }
778
779         for (j = 0; j < FRAMES; j++) {
780                 XDrawRectangle(dpy, scr->root_win, scr->frame_gc, (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
781         }
782         XFlush(dpy);
783 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
784         wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
785 #else
786         wusleep(10);
787 #endif
788         for (j = 0; j < FRAMES; j++) {
789                 XDrawRectangle(dpy, scr->root_win, scr->frame_gc, (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
790         }
791
792         XUngrabServer(dpy);
793 }
794
795 #undef FRAMES
796
797 void animateResize(WScreen * scr, int x, int y, int w, int h, int fx, int fy, int fw, int fh, int hiding)
798 {
799         int style = wPreferences.iconification_style;   /* Catch the value */
800         int steps, k;
801
802         if (style == WIS_NONE)
803                 return;
804
805         if (style == WIS_RANDOM) {
806                 style = rand() % 3;
807         }
808
809         k = (hiding ? 2 : 3);
810
811         switch (style) {
812         case WIS_TWIST:
813                 steps = (MINIATURIZE_ANIMATION_STEPS_T * k) / 3;
814                 if (steps > 0)
815                         animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
816                 break;
817         case WIS_FLIP:
818                 steps = (MINIATURIZE_ANIMATION_STEPS_F * k) / 3;
819                 if (steps > 0)
820                         animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
821                 break;
822         case WIS_ZOOM:
823         default:
824                 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k) / 3;
825                 if (steps > 0)
826                         animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
827                 break;
828         }
829 }
830 #endif                          /* ANIMATIONS */
831
832 static void flushExpose()
833 {
834         XEvent tmpev;
835
836         while (XCheckTypedEvent(dpy, Expose, &tmpev))
837                 WMHandleEvent(&tmpev);
838         XSync(dpy, 0);
839 }
840
841 static void unmapTransientsFor(WWindow * wwin)
842 {
843         WWindow *tmp;
844
845         tmp = wwin->screen_ptr->focused_window;
846         while (tmp) {
847                 /* unmap the transients for this transient */
848                 if (tmp != wwin && tmp->transient_for == wwin->client_win
849                     && (tmp->flags.mapped || wwin->screen_ptr->flags.startup || tmp->flags.shaded)) {
850                         unmapTransientsFor(tmp);
851                         tmp->flags.miniaturized = 1;
852                         if (!tmp->flags.shaded) {
853                                 wWindowUnmap(tmp);
854                         } else {
855                                 XUnmapWindow(dpy, tmp->frame->core->window);
856                         }
857                         /*
858                            if (!tmp->flags.shaded)
859                          */
860                         wClientSetState(tmp, IconicState, None);
861
862                         WMPostNotificationName(WMNChangedState, tmp, "iconify-transient");
863                 }
864                 tmp = tmp->prev;
865         }
866 }
867
868 static void mapTransientsFor(WWindow * wwin)
869 {
870         WWindow *tmp;
871
872         tmp = wwin->screen_ptr->focused_window;
873         while (tmp) {
874                 /* recursively map the transients for this transient */
875                 if (tmp != wwin && tmp->transient_for == wwin->client_win && /*!tmp->flags.mapped */ tmp->flags.miniaturized
876                     && tmp->icon == NULL) {
877                         mapTransientsFor(tmp);
878                         tmp->flags.miniaturized = 0;
879                         if (!tmp->flags.shaded) {
880                                 wWindowMap(tmp);
881                         } else {
882                                 XMapWindow(dpy, tmp->frame->core->window);
883                         }
884                         tmp->flags.semi_focused = 0;
885                         /*
886                            if (!tmp->flags.shaded)
887                          */
888                         wClientSetState(tmp, NormalState, None);
889
890                         WMPostNotificationName(WMNChangedState, tmp, "iconify-transient");
891                 }
892                 tmp = tmp->prev;
893         }
894 }
895
896 #if 0
897 static void setupIconGrabs(WIcon * icon)
898 {
899         /* setup passive grabs on the icon */
900         XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
901                     ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
902         XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
903                     ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
904         XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
905                     ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
906         XSync(dpy, 0);
907 }
908 #endif
909
910 static WWindow *recursiveTransientFor(WWindow * wwin)
911 {
912         int i;
913
914         if (!wwin)
915                 return None;
916
917         /* hackish way to detect transient_for cycle */
918         i = wwin->screen_ptr->window_count + 1;
919
920         while (wwin && wwin->transient_for != None && i > 0) {
921                 wwin = wWindowFor(wwin->transient_for);
922                 i--;
923         }
924         if (i == 0 && wwin) {
925                 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.", wwin->frame->title);
926                 return NULL;
927         }
928
929         return wwin;
930 }
931
932 #if 0
933 static void removeIconGrabs(WIcon * icon)
934 {
935         /* remove passive grabs on the icon */
936         XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
937         XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
938         XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);
939         XSync(dpy, 0);
940 }
941 #endif
942
943 void wIconifyWindow(WWindow * wwin)
944 {
945         XWindowAttributes attribs;
946         int present;
947
948         if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
949                 /* the window doesn't exist anymore */
950                 return;
951         }
952
953         if (wwin->flags.miniaturized) {
954                 return;
955         }
956
957         if (wwin->transient_for != None && wwin->transient_for != wwin->screen_ptr->root_win) {
958                 WWindow *owner = wWindowFor(wwin->transient_for);
959
960                 if (owner && owner->flags.miniaturized)
961                         return;
962         }
963
964         present = wwin->frame->workspace == wwin->screen_ptr->current_workspace;
965
966         /* if the window is in another workspace, simplify process */
967         if (present) {
968                 /* icon creation may take a while */
969                 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
970                              ButtonMotionMask | ButtonReleaseMask, GrabModeAsync,
971                              GrabModeAsync, None, None, CurrentTime);
972         }
973
974         if (!wPreferences.disable_miniwindows
975 #ifdef NETWM_HINTS
976             && !wwin->flags.net_handle_icon
977 #endif
978             ) {
979                 if (!wwin->flags.icon_moved) {
980                         PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y, wGetHeadForWindow(wwin));
981                 }
982                 wwin->icon = wIconCreate(wwin);
983
984                 wwin->icon->mapped = 1;
985         }
986
987         wwin->flags.miniaturized = 1;
988         wwin->flags.mapped = 0;
989
990         /* unmap transients */
991
992         unmapTransientsFor(wwin);
993
994         if (present) {
995                 wSoundPlay(WSOUND_ICONIFY);
996
997                 XUngrabPointer(dpy, CurrentTime);
998                 wWindowUnmap(wwin);
999                 /* let all Expose events arrive so that we can repaint
1000                  * something before the animation starts (and the server is grabbed) */
1001                 XSync(dpy, 0);
1002
1003                 if (wPreferences.disable_miniwindows
1004 #ifdef NETWM_HINTS
1005                     || wwin->flags.net_handle_icon
1006 #endif
1007                     )
1008                         wClientSetState(wwin, IconicState, None);
1009                 else
1010                         wClientSetState(wwin, IconicState, wwin->icon->icon_win);
1011
1012                 flushExpose();
1013 #ifdef ANIMATIONS
1014                 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
1015                     && !wPreferences.no_animations) {
1016                         int ix, iy, iw, ih;
1017
1018                         if (!wPreferences.disable_miniwindows
1019 #ifdef NETWM_HINTS
1020                             && !wwin->flags.net_handle_icon
1021 #endif
1022                             ) {
1023                                 ix = wwin->icon_x;
1024                                 iy = wwin->icon_y;
1025                                 iw = wwin->icon->core->width;
1026                                 ih = wwin->icon->core->height;
1027                         } else {
1028 #ifdef NETWM_HINTS
1029                                 if (wwin->flags.net_handle_icon) {
1030                                         ix = wwin->icon_x;
1031                                         iy = wwin->icon_y;
1032                                         iw = wwin->icon_w;
1033                                         ih = wwin->icon_h;
1034                                 } else
1035 #endif
1036                                 {
1037                                         ix = 0;
1038                                         iy = 0;
1039                                         iw = wwin->screen_ptr->scr_width;
1040                                         ih = wwin->screen_ptr->scr_height;
1041                                 }
1042                         }
1043                         animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1044                                       wwin->frame->core->width, wwin->frame->core->height, ix, iy, iw, ih, False);
1045                 }
1046 #endif
1047         }
1048
1049         wwin->flags.skip_next_animation = 0;
1050
1051         if (!wPreferences.disable_miniwindows
1052 #ifdef NETWM_HINTS
1053             && !wwin->flags.net_handle_icon
1054 #endif
1055             ) {
1056
1057                 if (wwin->screen_ptr->current_workspace == wwin->frame->workspace ||
1058                     IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)
1059
1060                         XMapWindow(dpy, wwin->icon->core->window);
1061
1062                 AddToStackList(wwin->icon->core);
1063
1064                 wLowerFrame(wwin->icon->core);
1065         }
1066
1067         if (present) {
1068                 WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
1069
1070                 /*
1071                  * It doesn't seem to be working and causes button event hangup
1072                  * when deiconifying a transient window.
1073                  setupIconGrabs(wwin->icon);
1074                  */
1075                 if ((wwin->flags.focused || (owner && wwin->client_win == owner->client_win))
1076                     && wPreferences.focus_mode == WKF_CLICK) {
1077                         WWindow *tmp;
1078
1079                         tmp = wwin->prev;
1080                         while (tmp) {
1081                                 if (!WFLAGP(tmp, no_focusable)
1082                                     && !(tmp->flags.hidden || tmp->flags.miniaturized)
1083                                     && (wwin->frame->workspace == tmp->frame->workspace))
1084                                         break;
1085                                 tmp = tmp->prev;
1086                         }
1087                         wSetFocusTo(wwin->screen_ptr, tmp);
1088                 } else if (wPreferences.focus_mode != WKF_CLICK) {
1089                         wSetFocusTo(wwin->screen_ptr, NULL);
1090                 }
1091 #ifdef ANIMATIONS
1092                 if (!wwin->screen_ptr->flags.startup) {
1093                         /* Catch up with events not processed while animation was running */
1094                         Window clientwin = wwin->client_win;
1095
1096                         ProcessPendingEvents();
1097
1098                         /* the window can disappear while ProcessPendingEvents() runs */
1099                         if (!wWindowFor(clientwin)) {
1100                                 return;
1101                         }
1102                 }
1103 #endif
1104         }
1105
1106         /* maybe we want to do this regardless of net_handle_icon
1107          * it seems to me we might break behaviour this way.
1108          */
1109         if (wwin->flags.selected && !wPreferences.disable_miniwindows
1110 #ifdef NETWM_HINTS
1111             && !wwin->flags.net_handle_icon
1112 #endif
1113             )
1114                 wIconSelect(wwin->icon);
1115
1116         WMPostNotificationName(WMNChangedState, wwin, "iconify");
1117 }
1118
1119 void wDeiconifyWindow(WWindow * wwin)
1120 {
1121 #ifdef NETWM_HINTS
1122         /* we're hiding for show_desktop */
1123         int netwm_hidden = wwin->flags.net_show_desktop &&
1124             wwin->frame->workspace != wwin->screen_ptr->current_workspace;
1125 #else
1126         int netwm_hidden = False;
1127 #endif
1128
1129         if (!netwm_hidden)
1130                 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1131
1132         if (!wwin->flags.miniaturized)
1133                 return;
1134
1135         if (wwin->transient_for != None && wwin->transient_for != wwin->screen_ptr->root_win) {
1136                 WWindow *owner = recursiveTransientFor(wwin);
1137
1138                 if (owner && owner->flags.miniaturized) {
1139                         wDeiconifyWindow(owner);
1140                         wSetFocusTo(wwin->screen_ptr, wwin);
1141                         wRaiseFrame(wwin->frame->core);
1142                         return;
1143                 }
1144         }
1145
1146         wwin->flags.miniaturized = 0;
1147
1148         if (!netwm_hidden && !wwin->flags.shaded) {
1149                 wwin->flags.mapped = 1;
1150         }
1151
1152         if (!netwm_hidden || wPreferences.sticky_icons) {
1153                 /* maybe we want to do this regardless of net_handle_icon
1154                  * it seems to me we might break behaviour this way.
1155                  */
1156                 if (!wPreferences.disable_miniwindows
1157 #ifdef NETWM_HINTS
1158                     && !wwin->flags.net_handle_icon
1159 #endif
1160                     && wwin->icon != NULL) {
1161                         if (wwin->icon->selected)
1162                                 wIconSelect(wwin->icon);
1163
1164                         XUnmapWindow(dpy, wwin->icon->core->window);
1165                 }
1166         }
1167
1168         if (!netwm_hidden)
1169                 wSoundPlay(WSOUND_DEICONIFY);
1170
1171         /* if the window is in another workspace, do it silently */
1172         if (!netwm_hidden) {
1173 #ifdef ANIMATIONS
1174                 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1175                     && !wwin->flags.skip_next_animation && wwin->icon != NULL) {
1176                         int ix, iy, iw, ih;
1177
1178                         if (!wPreferences.disable_miniwindows
1179 #ifdef NETWM_HINTS
1180                             && !wwin->flags.net_handle_icon
1181 #endif
1182                             ) {
1183                                 ix = wwin->icon_x;
1184                                 iy = wwin->icon_y;
1185                                 iw = wwin->icon->core->width;
1186                                 ih = wwin->icon->core->height;
1187                         } else {
1188 #ifdef NETWM_HINTS
1189                                 if (wwin->flags.net_handle_icon) {
1190                                         ix = wwin->icon_x;
1191                                         iy = wwin->icon_y;
1192                                         iw = wwin->icon_w;
1193                                         ih = wwin->icon_h;
1194                                 } else
1195 #endif
1196                                 {
1197                                         ix = 0;
1198                                         iy = 0;
1199                                         iw = wwin->screen_ptr->scr_width;
1200                                         ih = wwin->screen_ptr->scr_height;
1201                                 }
1202                         }
1203                         animateResize(wwin->screen_ptr, ix, iy, iw, ih,
1204                                       wwin->frame_x, wwin->frame_y,
1205                                       wwin->frame->core->width, wwin->frame->core->height, False);
1206                 }
1207 #endif                          /* ANIMATIONS */
1208                 wwin->flags.skip_next_animation = 0;
1209                 XGrabServer(dpy);
1210                 if (!wwin->flags.shaded) {
1211                         XMapWindow(dpy, wwin->client_win);
1212                 }
1213                 XMapWindow(dpy, wwin->frame->core->window);
1214                 wRaiseFrame(wwin->frame->core);
1215                 if (!wwin->flags.shaded) {
1216                         wClientSetState(wwin, NormalState, None);
1217                 }
1218                 mapTransientsFor(wwin);
1219         }
1220
1221         if (!wPreferences.disable_miniwindows && wwin->icon != NULL
1222 #ifdef NETWM_HINTS
1223             && !wwin->flags.net_handle_icon
1224 #endif
1225             ) {
1226                 RemoveFromStackList(wwin->icon->core);
1227                 /*    removeIconGrabs(wwin->icon); */
1228                 wIconDestroy(wwin->icon);
1229                 wwin->icon = NULL;
1230         }
1231
1232         if (!netwm_hidden) {
1233                 XUngrabServer(dpy);
1234
1235                 wSetFocusTo(wwin->screen_ptr, wwin);
1236
1237 #ifdef ANIMATIONS
1238                 if (!wwin->screen_ptr->flags.startup) {
1239                         /* Catch up with events not processed while animation was running */
1240                         Window clientwin = wwin->client_win;
1241
1242                         ProcessPendingEvents();
1243
1244                         /* the window can disappear while ProcessPendingEvents() runs */
1245                         if (!wWindowFor(clientwin)) {
1246                                 return;
1247                         }
1248                 }
1249 #endif
1250         }
1251
1252         if (wPreferences.auto_arrange_icons) {
1253                 wArrangeIcons(wwin->screen_ptr, True);
1254         }
1255
1256         WMPostNotificationName(WMNChangedState, wwin, "iconify");
1257
1258         /* In case we were shaded and iconified, also unshade */
1259         if (!netwm_hidden)
1260                 wUnshadeWindow(wwin);
1261 }
1262
1263 static void hideWindow(WIcon * icon, int icon_x, int icon_y, WWindow * wwin, int animate)
1264 {
1265         if (wwin->flags.miniaturized) {
1266                 if (wwin->icon) {
1267                         XUnmapWindow(dpy, wwin->icon->core->window);
1268                         wwin->icon->mapped = 0;
1269                 }
1270                 wwin->flags.hidden = 1;
1271
1272                 WMPostNotificationName(WMNChangedState, wwin, "hide");
1273                 return;
1274         }
1275
1276         if (wwin->flags.inspector_open) {
1277                 wHideInspectorForWindow(wwin);
1278         }
1279
1280         wwin->flags.hidden = 1;
1281         wWindowUnmap(wwin);
1282
1283         wClientSetState(wwin, IconicState, icon->icon_win);
1284         flushExpose();
1285         wSoundPlay(WSOUND_HIDE);
1286 #ifdef ANIMATIONS
1287         if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1288             !wwin->flags.skip_next_animation && animate) {
1289                 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1290                               wwin->frame->core->width, wwin->frame->core->height,
1291                               icon_x, icon_y, icon->core->width, icon->core->height, True);
1292         }
1293 #endif
1294         wwin->flags.skip_next_animation = 0;
1295
1296         WMPostNotificationName(WMNChangedState, wwin, "hide");
1297 }
1298
1299 void wHideOtherApplications(WWindow * awin)
1300 {
1301         WWindow *wwin;
1302         WApplication *tapp;
1303
1304         if (!awin)
1305                 return;
1306         wwin = awin->screen_ptr->focused_window;
1307
1308         while (wwin) {
1309                 if (wwin != awin
1310                     && wwin->frame->workspace == awin->screen_ptr->current_workspace
1311                     && !(wwin->flags.miniaturized || wwin->flags.hidden)
1312                     && !wwin->flags.internal_window
1313                     && wGetWindowOfInspectorForWindow(wwin) != awin && !WFLAGP(wwin, no_hide_others)) {
1314
1315                         if (wwin->main_window == None || WFLAGP(wwin, no_appicon)) {
1316                                 if (!WFLAGP(wwin, no_miniaturizable)) {
1317                                         wwin->flags.skip_next_animation = 1;
1318                                         wIconifyWindow(wwin);
1319                                 }
1320                         } else if (wwin->main_window != None && awin->main_window != wwin->main_window) {
1321                                 tapp = wApplicationOf(wwin->main_window);
1322                                 if (tapp) {
1323                                         tapp->flags.skip_next_animation = 1;
1324                                         wHideApplication(tapp);
1325                                 } else {
1326                                         if (!WFLAGP(wwin, no_miniaturizable)) {
1327                                                 wwin->flags.skip_next_animation = 1;
1328                                                 wIconifyWindow(wwin);
1329                                         }
1330                                 }
1331                         }
1332                 }
1333                 wwin = wwin->prev;
1334         }
1335         /*
1336            wSetFocusTo(awin->screen_ptr, awin);
1337          */
1338 }
1339
1340 void wHideApplication(WApplication * wapp)
1341 {
1342         WScreen *scr;
1343         WWindow *wlist;
1344         int hadfocus;
1345         int animate;
1346
1347         if (!wapp) {
1348                 wwarning("trying to hide a non grouped window");
1349                 return;
1350         }
1351         if (!wapp->main_window_desc) {
1352                 wwarning("group leader not found for window group");
1353                 return;
1354         }
1355         scr = wapp->main_window_desc->screen_ptr;
1356         hadfocus = 0;
1357         wlist = scr->focused_window;
1358         if (!wlist)
1359                 return;
1360
1361         if (wlist->main_window == wapp->main_window)
1362                 wapp->last_focused = wlist;
1363         else
1364                 wapp->last_focused = NULL;
1365
1366         animate = !wapp->flags.skip_next_animation;
1367
1368         while (wlist) {
1369                 if (wlist->main_window == wapp->main_window) {
1370                         if (wlist->flags.focused) {
1371                                 hadfocus = 1;
1372                         }
1373                         if (wapp->app_icon) {
1374                                 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1375                                            wapp->app_icon->y_pos, wlist, animate);
1376                                 animate = False;
1377                         }
1378                 }
1379                 wlist = wlist->prev;
1380         }
1381
1382         wapp->flags.skip_next_animation = 0;
1383
1384         if (hadfocus) {
1385                 if (wPreferences.focus_mode == WKF_CLICK) {
1386                         wlist = scr->focused_window;
1387                         while (wlist) {
1388                                 if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden
1389                                     && (wlist->flags.mapped || wlist->flags.shaded))
1390                                         break;
1391                                 wlist = wlist->prev;
1392                         }
1393                         wSetFocusTo(scr, wlist);
1394                 } else {
1395                         wSetFocusTo(scr, NULL);
1396                 }
1397         }
1398
1399         wapp->flags.hidden = 1;
1400
1401         if (wPreferences.auto_arrange_icons) {
1402                 wArrangeIcons(scr, True);
1403         }
1404 #ifdef HIDDENDOT
1405         if (wapp->app_icon)
1406                 wAppIconPaint(wapp->app_icon);
1407 #endif
1408 }
1409
1410 static void unhideWindow(WIcon * icon, int icon_x, int icon_y, WWindow * wwin, int animate, int bringToCurrentWS)
1411 {
1412         if (bringToCurrentWS)
1413                 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1414
1415         wwin->flags.hidden = 0;
1416
1417         wSoundPlay(WSOUND_UNHIDE);
1418 #ifdef ANIMATIONS
1419         if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations && animate) {
1420                 animateResize(wwin->screen_ptr, icon_x, icon_y,
1421                               icon->core->width, icon->core->height,
1422                               wwin->frame_x, wwin->frame_y,
1423                               wwin->frame->core->width, wwin->frame->core->height, True);
1424         }
1425 #endif
1426         wwin->flags.skip_next_animation = 0;
1427         if (wwin->screen_ptr->current_workspace == wwin->frame->workspace) {
1428                 XMapWindow(dpy, wwin->client_win);
1429                 XMapWindow(dpy, wwin->frame->core->window);
1430                 wClientSetState(wwin, NormalState, None);
1431                 wwin->flags.mapped = 1;
1432                 wRaiseFrame(wwin->frame->core);
1433         }
1434         if (wwin->flags.inspector_open) {
1435                 wUnhideInspectorForWindow(wwin);
1436         }
1437
1438         WMPostNotificationName(WMNChangedState, wwin, "hide");
1439 }
1440
1441 void wUnhideApplication(WApplication * wapp, Bool miniwindows, Bool bringToCurrentWS)
1442 {
1443         WScreen *scr;
1444         WWindow *wlist, *next;
1445         WWindow *focused = NULL;
1446         int animate;
1447
1448         if (!wapp)
1449                 return;
1450
1451         scr = wapp->main_window_desc->screen_ptr;
1452         wlist = scr->focused_window;
1453         if (!wlist)
1454                 return;
1455
1456         /* goto beginning of list */
1457         while (wlist->prev)
1458                 wlist = wlist->prev;
1459
1460         animate = !wapp->flags.skip_next_animation;
1461
1462         while (wlist) {
1463                 next = wlist->next;
1464
1465                 if (wlist->main_window == wapp->main_window) {
1466                         if (wlist->flags.focused)
1467                                 focused = wlist;
1468                         else if (!focused || !focused->flags.focused)
1469                                 focused = wlist;
1470
1471                         if (wlist->flags.miniaturized) {
1472                                 if ((bringToCurrentWS || wPreferences.sticky_icons ||
1473                                      wlist->frame->workspace == scr->current_workspace) && wlist->icon) {
1474                                         if (!wlist->icon->mapped) {
1475                                                 int x, y;
1476
1477                                                 PlaceIcon(scr, &x, &y, wGetHeadForWindow(wlist));
1478                                                 if (wlist->icon_x != x || wlist->icon_y != y) {
1479                                                         XMoveWindow(dpy, wlist->icon->core->window, x, y);
1480                                                 }
1481                                                 wlist->icon_x = x;
1482                                                 wlist->icon_y = y;
1483                                                 XMapWindow(dpy, wlist->icon->core->window);
1484                                                 wlist->icon->mapped = 1;
1485                                         }
1486                                         wRaiseFrame(wlist->icon->core);
1487                                 }
1488                                 if (bringToCurrentWS)
1489                                         wWindowChangeWorkspace(wlist, scr->current_workspace);
1490                                 wlist->flags.hidden = 0;
1491                                 if (miniwindows && wlist->frame->workspace == scr->current_workspace) {
1492                                         wDeiconifyWindow(wlist);
1493                                 }
1494                                 WMPostNotificationName(WMNChangedState, wlist, "hide");
1495                         } else if (wlist->flags.shaded) {
1496                                 if (bringToCurrentWS)
1497                                         wWindowChangeWorkspace(wlist, scr->current_workspace);
1498                                 wlist->flags.hidden = 0;
1499                                 if (wlist->frame->workspace == scr->current_workspace) {
1500                                         XMapWindow(dpy, wlist->frame->core->window);
1501                                         if (miniwindows) {
1502                                                 wUnshadeWindow(wlist);
1503                                                 wRaiseFrame(wlist->frame->core);
1504                                         }
1505                                 }
1506                                 WMPostNotificationName(WMNChangedState, wlist, "hide");
1507                         } else if (wlist->flags.hidden) {
1508                                 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1509                                              wapp->app_icon->y_pos, wlist, animate, bringToCurrentWS);
1510                                 animate = False;
1511                         } else {
1512                                 if (bringToCurrentWS && wlist->frame->workspace != scr->current_workspace) {
1513                                         wWindowChangeWorkspace(wlist, scr->current_workspace);
1514                                 }
1515                                 wRaiseFrame(wlist->frame->core);
1516                         }
1517                 }
1518                 wlist = next;
1519         }
1520
1521         wapp->flags.skip_next_animation = 0;
1522         wapp->flags.hidden = 0;
1523
1524         if (wapp->last_focused && wapp->last_focused->flags.mapped) {
1525                 wRaiseFrame(wapp->last_focused->frame->core);
1526                 wSetFocusTo(scr, wapp->last_focused);
1527         } else if (focused) {
1528                 wSetFocusTo(scr, focused);
1529         }
1530         wapp->last_focused = NULL;
1531         if (wPreferences.auto_arrange_icons) {
1532                 wArrangeIcons(scr, True);
1533         }
1534 #ifdef HIDDENDOT
1535         wAppIconPaint(wapp->app_icon);
1536 #endif
1537 }
1538
1539 void wShowAllWindows(WScreen * scr)
1540 {
1541         WWindow *wwin, *old_foc;
1542         WApplication *wapp;
1543
1544         old_foc = wwin = scr->focused_window;
1545         while (wwin) {
1546                 if (!wwin->flags.internal_window &&
1547                     (scr->current_workspace == wwin->frame->workspace || IS_OMNIPRESENT(wwin))) {
1548                         if (wwin->flags.miniaturized) {
1549                                 wwin->flags.skip_next_animation = 1;
1550                                 wDeiconifyWindow(wwin);
1551                         } else if (wwin->flags.hidden) {
1552                                 wapp = wApplicationOf(wwin->main_window);
1553                                 if (wapp) {
1554                                         wUnhideApplication(wapp, False, False);
1555                                 } else {
1556                                         wwin->flags.skip_next_animation = 1;
1557                                         wDeiconifyWindow(wwin);
1558                                 }
1559                         }
1560                 }
1561                 wwin = wwin->prev;
1562         }
1563         wSetFocusTo(scr, old_foc);
1564         /*wRaiseFrame(old_foc->frame->core); */
1565 }
1566
1567 void wRefreshDesktop(WScreen * scr)
1568 {
1569         Window win;
1570         XSetWindowAttributes attr;
1571
1572         attr.backing_store = NotUseful;
1573         attr.save_under = False;
1574         win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1575                             scr->scr_height, 0, CopyFromParent, CopyFromParent,
1576                             (Visual *) CopyFromParent, CWBackingStore | CWSaveUnder, &attr);
1577         XMapRaised(dpy, win);
1578         XDestroyWindow(dpy, win);
1579         XFlush(dpy);
1580 }
1581
1582 void wArrangeIcons(WScreen * scr, Bool arrangeAll)
1583 {
1584         WWindow *wwin;
1585         WAppIcon *aicon;
1586
1587         int head;
1588         const int heads = wXineramaHeads(scr);
1589
1590         struct HeadVars {
1591                 int pf;         /* primary axis */
1592                 int sf;         /* secondary axis */
1593                 int fullW;
1594                 int fullH;
1595                 int pi, si;
1596                 int sx1, sx2, sy1, sy2; /* screen boundary */
1597                 int sw, sh;
1598                 int xo, yo;
1599                 int xs, ys;
1600         } *vars;
1601
1602         int isize = wPreferences.icon_size;
1603
1604         vars = (struct HeadVars *)wmalloc(sizeof(struct HeadVars) * heads);
1605
1606         for (head = 0; head < heads; ++head) {
1607 #if 0
1608                 WMRect rect = wGetRectForHead(scr, head);
1609 #else
1610                 WArea area = wGetUsableAreaForHead(scr, head, NULL, False);
1611                 WMRect rect = wmkrect(area.x1, area.y1, area.x2 - area.x1, area.y2 - area.y1);
1612 #endif
1613
1614                 vars[head].pi = vars[head].si = 0;
1615                 vars[head].sx1 = rect.pos.x;
1616                 vars[head].sy1 = rect.pos.y;
1617                 vars[head].sw = rect.size.width;
1618                 vars[head].sh = rect.size.height;
1619                 vars[head].sx2 = vars[head].sx1 + vars[head].sw;
1620                 vars[head].sy2 = vars[head].sy1 + vars[head].sh;
1621
1622 #if 0
1623                 if (scr->dock) {
1624                         if (scr->dock->on_right_side)
1625                                 vars[head].sx2 -= isize + DOCK_EXTRA_SPACE;
1626                         else
1627                                 vars[head].sx1 += isize + DOCK_EXTRA_SPACE;
1628                 }
1629 #endif
1630
1631                 vars[head].sw = isize * (vars[head].sw / isize);
1632                 vars[head].sh = isize * (vars[head].sh / isize);
1633                 vars[head].fullW = (vars[head].sx2 - vars[head].sx1) / isize;
1634                 vars[head].fullH = (vars[head].sy2 - vars[head].sy1) / isize;
1635
1636                 /* icon yard boundaries */
1637                 if (wPreferences.icon_yard & IY_VERT) {
1638                         vars[head].pf = vars[head].fullH;
1639                         vars[head].sf = vars[head].fullW;
1640                 } else {
1641                         vars[head].pf = vars[head].fullW;
1642                         vars[head].sf = vars[head].fullH;
1643                 }
1644                 if (wPreferences.icon_yard & IY_RIGHT) {
1645                         vars[head].xo = vars[head].sx2 - isize;
1646                         vars[head].xs = -1;
1647                 } else {
1648                         vars[head].xo = vars[head].sx1;
1649                         vars[head].xs = 1;
1650                 }
1651                 if (wPreferences.icon_yard & IY_TOP) {
1652                         vars[head].yo = vars[head].sy1;
1653                         vars[head].ys = 1;
1654                 } else {
1655                         vars[head].yo = vars[head].sy2 - isize;
1656                         vars[head].ys = -1;
1657                 }
1658         }
1659
1660 #define X ((wPreferences.icon_yard & IY_VERT) \
1661     ? vars[head].xo + vars[head].xs*(vars[head].si*isize) \
1662     : vars[head].xo + vars[head].xs*(vars[head].pi*isize))
1663
1664 #define Y ((wPreferences.icon_yard & IY_VERT) \
1665     ? vars[head].yo + vars[head].ys*(vars[head].pi*isize) \
1666     : vars[head].yo + vars[head].ys*(vars[head].si*isize))
1667
1668         /* arrange application icons */
1669         aicon = scr->app_icon_list;
1670         /* reverse them to avoid unnecessarily sliding of icons */
1671         while (aicon && aicon->next)
1672                 aicon = aicon->next;
1673
1674         while (aicon) {
1675                 if (!aicon->docked) {
1676                         /* CHECK: can icon be NULL here ? */
1677                         /* The intention here is to place the AppIcon on the head that
1678                          * contains most of the applications _main_ window. */
1679                         head = wGetHeadForWindow(aicon->icon->owner);
1680
1681                         if (aicon->x_pos != X || aicon->y_pos != Y) {
1682 #ifdef ANIMATIONS
1683                                 if (!wPreferences.no_animations) {
1684                                         SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos, X, Y);
1685                                 }
1686 #endif                          /* ANIMATIONS */
1687                         }
1688                         wAppIconMove(aicon, X, Y);
1689                         vars[head].pi++;
1690                         if (vars[head].pi >= vars[head].pf) {
1691                                 vars[head].pi = 0;
1692                                 vars[head].si++;
1693                         }
1694                 }
1695                 aicon = aicon->prev;
1696         }
1697
1698         /* arrange miniwindows */
1699         wwin = scr->focused_window;
1700         /* reverse them to avoid unnecessarily shuffling */
1701         while (wwin && wwin->prev)
1702                 wwin = wwin->prev;
1703
1704         while (wwin) {
1705                 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1706                     (wwin->frame->workspace == scr->current_workspace ||
1707                      IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1708
1709                         head = wGetHeadForWindow(wwin);
1710
1711                         if (arrangeAll || !wwin->flags.icon_moved) {
1712                                 if (wwin->icon_x != X || wwin->icon_y != Y) {
1713 #ifdef ANIMATIONS
1714                                         if (wPreferences.no_animations) {
1715                                                 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1716                                         } else {
1717                                                 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1718                                                             wwin->icon_y, X, Y);
1719                                         }
1720 #else
1721                                         XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1722 #endif                          /* ANIMATIONS */
1723                                 }
1724                                 wwin->icon_x = X;
1725                                 wwin->icon_y = Y;
1726
1727                                 vars[head].pi++;
1728                                 if (vars[head].pi >= vars[head].pf) {
1729                                         vars[head].pi = 0;
1730                                         vars[head].si++;
1731                                 }
1732                         }
1733                 }
1734                 if (arrangeAll) {
1735                         wwin->flags.icon_moved = 0;
1736                 }
1737                 /* we reversed the order, so we use next */
1738                 wwin = wwin->next;
1739         }
1740
1741         wfree(vars);
1742 }
1743
1744 #if 0
1745 void wArrangeIcons(WScreen * scr, Bool arrangeAll)
1746 {
1747         WWindow *wwin;
1748         WAppIcon *aicon;
1749         int pf;                 /* primary axis */
1750         int sf;                 /* secondary axis */
1751         int fullW;
1752         int fullH;
1753         int pi, si;
1754         int sx1, sx2, sy1, sy2; /* screen boundary */
1755         int sw, sh;
1756         int xo, yo;
1757         int xs, ys;
1758         int isize = wPreferences.icon_size;
1759
1760         /*
1761          * Find out screen boundaries.
1762          */
1763
1764         /*
1765          * Allows each head to have miniwindows
1766          */
1767         WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
1768
1769         sx1 = rect.pos.x;
1770         sy1 = rect.pos.y;
1771         sw = rect.size.width;
1772         sh = rect.size.height;
1773         sx2 = sx1 + sw;
1774         sy2 = sy1 + sh;
1775         if (scr->dock) {
1776                 if (scr->dock->on_right_side)
1777                         sx2 -= isize + DOCK_EXTRA_SPACE;
1778                 else
1779                         sx1 += isize + DOCK_EXTRA_SPACE;
1780         }
1781 #if 0
1782         sw = isize * (scr->scr_width / isize);
1783         sh = isize * (scr->scr_height / isize);
1784 #else
1785         sw = isize * (sw / isize);
1786         sh = isize * (sh / isize);
1787 #endif
1788         fullW = (sx2 - sx1) / isize;
1789         fullH = (sy2 - sy1) / isize;
1790
1791         /* icon yard boundaries */
1792         if (wPreferences.icon_yard & IY_VERT) {
1793                 pf = fullH;
1794                 sf = fullW;
1795         } else {
1796                 pf = fullW;
1797                 sf = fullH;
1798         }
1799         if (wPreferences.icon_yard & IY_RIGHT) {
1800                 xo = sx2 - isize;
1801                 xs = -1;
1802         } else {
1803                 xo = sx1;
1804                 xs = 1;
1805         }
1806         if (wPreferences.icon_yard & IY_TOP) {
1807                 yo = sy1;
1808                 ys = 1;
1809         } else {
1810                 yo = sy2 - isize;
1811                 ys = -1;
1812         }
1813
1814         /* arrange icons putting the most recently focused window
1815          * as the last icon */
1816 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1817     : xo + xs*(pi*isize))
1818 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1819     : yo + ys*(si*isize))
1820
1821         /* arrange application icons */
1822         aicon = scr->app_icon_list;
1823         /* reverse them to avoid unnecessarily sliding of icons */
1824         while (aicon && aicon->next)
1825                 aicon = aicon->next;
1826
1827         pi = 0;
1828         si = 0;
1829         while (aicon) {
1830                 if (!aicon->docked) {
1831                         if (aicon->x_pos != X || aicon->y_pos != Y) {
1832 #ifdef ANIMATIONS
1833                                 if (!wPreferences.no_animations) {
1834                                         SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos, X, Y);
1835                                 }
1836 #endif                          /* ANIMATIONS */
1837                         }
1838                         wAppIconMove(aicon, X, Y);
1839                         pi++;
1840                 }
1841                 /* we reversed the order so we use prev */
1842                 aicon = aicon->prev;
1843                 if (pi >= pf) {
1844                         pi = 0;
1845                         si++;
1846                 }
1847         }
1848
1849         /* arrange miniwindows */
1850
1851         wwin = scr->focused_window;
1852         /* reverse them to avoid unnecessarily shuffling */
1853         while (wwin && wwin->prev)
1854                 wwin = wwin->prev;
1855
1856         while (wwin) {
1857                 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1858                     (wwin->frame->workspace == scr->current_workspace ||
1859                      IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1860
1861                         if (arrangeAll || !wwin->flags.icon_moved) {
1862                                 if (wwin->icon_x != X || wwin->icon_y != Y) {
1863 #ifdef ANIMATIONS
1864                                         if (wPreferences.no_animations) {
1865                                                 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1866                                         } else {
1867                                                 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1868                                                             wwin->icon_y, X, Y);
1869                                         }
1870 #else
1871                                         XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1872 #endif                          /* ANIMATIONS */
1873                                 }
1874                                 wwin->icon_x = X;
1875                                 wwin->icon_y = Y;
1876                                 pi++;
1877                         }
1878                 }
1879                 if (arrangeAll) {
1880                         wwin->flags.icon_moved = 0;
1881                 }
1882                 /* we reversed the order, so we use next */
1883                 wwin = wwin->next;
1884                 if (pi >= pf) {
1885                         pi = 0;
1886                         si++;
1887                 }
1888         }
1889 }
1890 #endif
1891
1892 void wSelectWindow(WWindow * wwin, Bool flag)
1893 {
1894         WScreen *scr = wwin->screen_ptr;
1895
1896         if (flag) {
1897                 wwin->flags.selected = 1;
1898                 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1899
1900                 if (!HAS_BORDER(wwin)) {
1901                         XSetWindowBorderWidth(dpy, wwin->frame->core->window, FRAME_BORDER_WIDTH);
1902                 }
1903
1904                 if (!scr->selected_windows)
1905                         scr->selected_windows = WMCreateArray(4);
1906                 WMAddToArray(scr->selected_windows, wwin);
1907         } else {
1908                 wwin->flags.selected = 0;
1909                 XSetWindowBorder(dpy, wwin->frame->core->window, scr->frame_border_pixel);
1910
1911                 if (!HAS_BORDER(wwin)) {
1912                         XSetWindowBorderWidth(dpy, wwin->frame->core->window, 0);
1913                 }
1914
1915                 if (scr->selected_windows) {
1916                         WMRemoveFromArray(scr->selected_windows, wwin);
1917                 }
1918         }
1919 }
1920
1921 void wMakeWindowVisible(WWindow * wwin)
1922 {
1923         if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
1924                 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1925
1926         if (wwin->flags.shaded) {
1927                 wUnshadeWindow(wwin);
1928         }
1929         if (wwin->flags.hidden) {
1930                 WApplication *app;
1931
1932                 app = wApplicationOf(wwin->main_window);
1933                 if (app) {
1934                         /* trick to get focus to this window */
1935                         app->last_focused = wwin;
1936                         wUnhideApplication(app, False, False);
1937                 }
1938         }
1939         if (wwin->flags.miniaturized) {
1940                 wDeiconifyWindow(wwin);
1941         } else {
1942                 if (!WFLAGP(wwin, no_focusable))
1943                         wSetFocusTo(wwin->screen_ptr, wwin);
1944                 wRaiseFrame(wwin->frame->core);
1945         }
1946 }
1947
1948 /*
1949  * Do the animation while shading (called with what = SHADE)
1950  * or unshading (what = UNSHADE).
1951  */
1952 #ifdef ANIMATIONS
1953 static void shade_animate(WWindow *wwin, Bool what)
1954 {
1955         int y, s, w, h;
1956         time_t time0 = time(NULL);
1957
1958         if (wwin->flags.skip_next_animation && wPreferences.no_animations)
1959                 return;
1960
1961         switch(what) {
1962         case SHADE:
1963                 if (!wwin->screen_ptr->flags.startup) {
1964                         /* do the shading animation */
1965                         h = wwin->frame->core->height;
1966                         s = h / SHADE_STEPS;
1967                         if (s < 1)
1968                                 s = 1;
1969                         w = wwin->frame->core->width;
1970                         y = wwin->frame->top_width;
1971                         while (h > wwin->frame->top_width + 1) {
1972                                 XMoveWindow(dpy, wwin->client_win, 0, y);
1973                                 XResizeWindow(dpy, wwin->frame->core->window, w, h);
1974                                 XFlush(dpy);
1975
1976                                 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
1977                                         break;
1978
1979                                 if (SHADE_DELAY > 0) {
1980                                 wusleep(SHADE_DELAY * 1000L);
1981                                 } else {
1982                                         wusleep(10);
1983                                 }
1984                                 h -= s;
1985                         y -= s;
1986                         }
1987                         XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
1988                 }
1989                 break;
1990
1991         case UNSHADE:
1992                 h = wwin->frame->top_width + wwin->frame->bottom_width;
1993                 y = wwin->frame->top_width - wwin->client.height;
1994                 s = abs(y) / SHADE_STEPS;
1995                 if (s < 1)
1996                         s = 1;
1997                 w = wwin->frame->core->width;
1998                 XMoveWindow(dpy, wwin->client_win, 0, y);
1999                 if (s > 0) {
2000                         while (h < wwin->client.height + wwin->frame->top_width + wwin->frame->bottom_width) {
2001                                 XResizeWindow(dpy, wwin->frame->core->window, w, h);
2002                                 XMoveWindow(dpy, wwin->client_win, 0, y);
2003                                 XFlush(dpy);
2004                                 if (SHADE_DELAY > 0) {
2005                                         wusleep(SHADE_DELAY * 2000L / 3);
2006                                 } else {
2007                                         wusleep(10);
2008                                 }
2009                                 h += s;
2010                                 y += s;
2011
2012                                 if (time(NULL) - time0 > MAX_ANIMATION_TIME)
2013                                         break;
2014                         }
2015                 }
2016                 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
2017                 break;
2018         }
2019 }
2020 #else
2021 static void shade_animate(WWindow *wwin, Bool what) { return; }
2022 #endif /* ANIMATIONS */