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