Initial revision
[wmaker-crm.git] / src / actions.c
blobdaec8d96a7083faf3bdd18854c975eb3c4918c84
1 /* action.c- misc. window commands (miniaturize, hide etc.)
2 *
3 * WindowMaker window manager
4 *
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
22 #include "wconfig.h"
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <math.h>
31 #include "WindowMaker.h"
32 #include "wcore.h"
33 #include "framewin.h"
34 #include "window.h"
35 #include "client.h"
36 #include "icon.h"
37 #include "funcs.h"
38 #include "application.h"
39 #include "actions.h"
40 #include "stacking.h"
41 #include "appicon.h"
42 #include "dock.h"
43 #include "appmenu.h"
44 #include "winspector.h"
46 #ifdef WMSOUND
47 #include "wmsound.h"
48 #endif
51 /****** Global Variables ******/
52 extern Time LastTimestamp;
53 extern Time LastFocusChange;
55 extern Cursor wCursor[WCUR_LAST];
57 extern WPreferences wPreferences;
59 extern Atom _XA_WM_TAKE_FOCUS;
61 /******* Local Variables *******/
62 static struct {
63 int steps;
64 int delay;
65 } shadePars[5] = {
66 {SHADE_STEPS_UF, SHADE_DELAY_UF},
67 {SHADE_STEPS_F, SHADE_DELAY_F},
68 {SHADE_STEPS_M, SHADE_DELAY_M},
69 {SHADE_STEPS_S, SHADE_DELAY_S},
70 {SHADE_STEPS_U, SHADE_DELAY_U}};
72 #define SHADE_STEPS shadePars[wPreferences.shade_speed].steps
73 #define SHADE_DELAY shadePars[wPreferences.shade_speed].delay
76 static int ignoreTimestamp=0;
79 #ifdef ANIMATIONS
80 static void
81 processEvents(int event_count)
83 XEvent event;
86 * This is a hack. When animations are enabled, processing of
87 * events ocurred during a animation are delayed until it's end.
88 * Calls that consider the TimeStamp, like XSetInputFocus(), will
89 * fail because the TimeStamp is too old. Then, for example, if
90 * the user changes window focus while a miniaturize animation is
91 * in course, the window will not get focus properly after the end
92 * of the animation. This tries to workaround it by passing CurrentTime
93 * as the TimeStamp for XSetInputFocus() for all events ocurred during
94 * the animation.
96 ignoreTimestamp=1;
97 while (event_count--) {
98 WMNextEvent(dpy, &event);
99 WMHandleEvent(&event);
101 ignoreTimestamp=0;
103 #endif /* ANIMATIONS */
107 *----------------------------------------------------------------------
108 * wSetFocusTo--
109 * Changes the window focus to the one passed as argument.
110 * If the window to focus is not already focused, it will be brought
111 * to the head of the list of windows. Previously focused window is
112 * unfocused.
114 * Side effects:
115 * Window list may be reordered and the window focus is changed.
117 *----------------------------------------------------------------------
119 void
120 wSetFocusTo(WScreen *scr, WWindow *wwin)
122 WWindow *focused=scr->focused_window;
123 WWindow *owner = NULL;
124 int timestamp=LastTimestamp;
125 WApplication *oapp=NULL, *napp=NULL;
126 int wasfocused;
128 LastFocusChange = timestamp;
130 if (ignoreTimestamp)
131 timestamp=CurrentTime;
133 if (focused)
134 oapp = wApplicationOf(focused->main_window);
136 if (wwin==NULL) {
137 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
138 if (focused) {
139 wWindowUnfocus(focused);
141 if (oapp) {
142 wAppMenuUnmap(oapp->menu);
143 #ifdef NEWAPPICON
144 wApplicationDeactivate(oapp);
145 #endif
147 return;
149 wasfocused = wwin->flags.focused;
150 napp = wApplicationOf(wwin->main_window);
152 /* remember last workspace where the app has been */
153 if (napp)
154 napp->last_workspace = wwin->screen_ptr->current_workspace;
156 if (wwin->window_flags.no_focusable)
157 return;
159 if (wwin->flags.mapped) {
160 /* install colormap if colormap mode is lock mode */
161 if (wPreferences.colormap_mode==WKF_CLICK)
162 wColormapInstallForWindow(scr, wwin);
164 /* set input focus */
165 switch (wwin->focus_mode) {
166 case WFM_NO_INPUT:
167 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
168 break;
170 case WFM_PASSIVE:
171 case WFM_LOCALLY_ACTIVE:
172 XSetInputFocus(dpy, wwin->client_win, RevertToParent, timestamp);
173 break;
175 case WFM_GLOBALLY_ACTIVE:
176 break;
178 XFlush(dpy);
179 if (wwin->protocols.TAKE_FOCUS) {
180 wClientSendProtocol(wwin, _XA_WM_TAKE_FOCUS, timestamp);
182 XSync(dpy, False);
183 } else {
184 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
187 /* if this is not the focused window focus it */
188 if (focused!=wwin) {
189 int foo=0;
191 if (wwin->client_win == focused->transient_for)
192 wwin->flags.semi_focused = 0;
193 else if (wwin->transient_for == focused->client_win)
194 focused->flags.semi_focused = 1;
196 if (wwin->transient_for
197 && wwin->transient_for == focused->transient_for) {
198 owner = wWindowFor(wwin->transient_for);
199 if (owner && owner->flags.semi_focused) {
200 foo=1;
201 /* this is to override the unfocusing of the mainwindow
202 * in the next wWindowUnfocus() and avoid flickering */
203 owner->flags.semi_focused = 0;
206 /* unfocus previous window */
207 wWindowUnfocus(focused);
208 if (foo) {
209 owner->flags.semi_focused = 1;
211 /* change the focus window list order */
212 if (wwin->prev)
213 wwin->prev->next=wwin->next;
214 if (wwin->next)
215 wwin->next->prev=wwin->prev;
217 wwin->prev = focused;
218 focused->next = wwin;
219 wwin->next = NULL;
220 scr->focused_window = wwin;
222 if (oapp && oapp != napp) {
223 wAppMenuUnmap(oapp->menu);
224 #ifdef NEWAPPICON
225 wApplicationDeactivate(oapp);
226 #endif
229 if ((owner=wWindowFor(wwin->transient_for))
230 && !owner->flags.semi_focused) {
231 owner->flags.semi_focused = 1;
232 wWindowUnfocus(owner);
234 wWindowFocus(wwin);
235 if (napp && !wasfocused) {
236 wAppMenuMap(napp->menu, wwin);
237 #ifdef NEWAPPICON
238 wApplicationActivate(napp);
239 #endif
241 XFlush(dpy);
245 void
246 wShadeWindow(WWindow *wwin)
248 XWindowAttributes attribs;
249 #ifdef ANIMATIONS
250 int y, s, w, h;
251 #endif
253 if (wwin->flags.shaded)
254 return;
256 XLowerWindow(dpy, wwin->client_win);
258 #ifdef WMSOUND
259 wSoundPlay(WMSOUND_SHADE);
260 #endif
262 #ifdef ANIMATIONS
263 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
264 && !wPreferences.no_animations) {
265 /* do the shading animation */
266 h = wwin->frame->core->height;
267 s = h/SHADE_STEPS;
268 if (s < 1) s=1;
269 w = wwin->frame->core->width;
270 y = wwin->frame->top_width;
271 while (h>wwin->frame->top_width+1) {
272 XMoveWindow(dpy, wwin->client_win, 0, y);
273 XResizeWindow(dpy, wwin->frame->core->window, w, h);
274 XSync(dpy, 0);
275 if (SHADE_DELAY > 0)
276 wusleep(SHADE_DELAY*1000L);
277 h-=s;
278 y-=s;
280 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
282 #endif /* ANIMATIONS */
285 wwin->flags.skip_next_animation = 0;
286 XGetWindowAttributes(dpy, wwin->client_win, &attribs);
287 wwin->flags.shaded=1;
288 wwin->flags.mapped=0;
289 /* prevent window withdrawal when getting UnmapNotify */
290 XSelectInput(dpy, wwin->client_win,
291 attribs.your_event_mask & ~StructureNotifyMask);
292 XUnmapWindow(dpy, wwin->client_win);
293 XSelectInput(dpy, wwin->client_win, attribs.your_event_mask);
295 /* for the client it's just like iconification */
296 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
297 wwin->frame->top_width-1);
298 wClientSetState(wwin, IconicState, None);
300 /* update window list to reflect shaded state */
301 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
303 #ifdef ANIMATIONS
304 if (!wwin->screen_ptr->flags.startup) {
305 XSync(dpy, 0);
306 processEvents(XPending(dpy));
308 #endif
312 void
313 wUnshadeWindow(WWindow *wwin)
315 #ifdef ANIMATIONS
316 int y, s, w, h;
317 #endif /* ANIMATIONS */
320 if (!wwin->flags.shaded)
321 return;
323 wwin->flags.shaded=0;
324 wwin->flags.mapped=1;
325 XMapWindow(dpy, wwin->client_win);
327 #ifdef WMSOUND
328 wSoundPlay(WMSOUND_UNSHADE);
329 #endif
331 #ifdef ANIMATIONS
332 if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) {
333 /* do the shading animation */
334 h = wwin->frame->top_width + wwin->frame->bottom_width;
335 y = wwin->frame->top_width - wwin->client.height;
336 s = abs(y)/SHADE_STEPS;
337 if (s<1) s=1;
338 w = wwin->frame->core->width;
339 XMoveWindow(dpy, wwin->client_win, 0, y);
340 if (s>0) {
341 while (h < wwin->client.height + wwin->frame->top_width
342 + wwin->frame->bottom_width) {
343 XResizeWindow(dpy, wwin->frame->core->window, w, h);
344 XMoveWindow(dpy, wwin->client_win, 0, y);
345 XSync(dpy, 0);
346 if (SHADE_DELAY > 0)
347 wusleep(SHADE_DELAY*2000L/3);
348 h+=s;
349 y+=s;
352 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
354 #endif /* ANIMATIONS */
357 wwin->flags.skip_next_animation = 0;
358 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
359 wwin->frame->top_width + wwin->client.height
360 + wwin->frame->bottom_width);
362 wClientSetState(wwin, NormalState, None);
363 /* if the window is focused, set the focus again as it was disabled during
364 * shading */
365 if (wwin->flags.focused)
366 wSetFocusTo(wwin->screen_ptr, wwin);
368 /* update window list to reflect unshaded state */
369 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
373 void
374 wMaximizeWindow(WWindow *wwin, int directions)
376 int new_width, new_height, new_x, new_y;
378 if (wwin->flags.shaded) {
379 wwin->flags.skip_next_animation = 1;
380 wUnshadeWindow(wwin);
382 wwin->flags.maximized = directions;
383 wwin->old_geometry.width = wwin->client.width;
384 wwin->old_geometry.height = wwin->client.height;
385 wwin->old_geometry.x = wwin->frame_x;
386 wwin->old_geometry.y = wwin->frame_y;
387 if (directions & MAX_HORIZONTAL) {
388 new_width = wwin->screen_ptr->scr_width-FRAME_BORDER_WIDTH*2;
390 new_x = 0;
391 if ((wPreferences.icon_yard & IY_VERT)
392 && wPreferences.no_window_over_icons) {
394 new_width -= wPreferences.icon_size;
395 if (!(wPreferences.icon_yard & IY_RIGHT))
396 new_x += wPreferences.icon_size;
399 if (wPreferences.no_window_under_dock
400 && wwin->screen_ptr->dock) {
401 new_width -= wPreferences.icon_size + DOCK_EXTRA_SPACE;
402 if (!wwin->screen_ptr->dock->on_right_side)
403 new_x += wPreferences.icon_size + DOCK_EXTRA_SPACE;
405 } else {
406 new_x = wwin->frame_x;
407 new_width = wwin->frame->core->width;
410 if (directions & MAX_VERTICAL) {
411 new_height = wwin->screen_ptr->scr_height-FRAME_BORDER_WIDTH*2;
412 new_y = 0;
413 if (!(wPreferences.icon_yard & IY_VERT)
414 && wPreferences.no_window_over_icons) {
416 new_height -= wPreferences.icon_size;
418 if (wPreferences.icon_yard & IY_TOP)
419 new_y += wPreferences.icon_size;
421 } else {
422 new_y = wwin->frame_y;
423 new_height = wwin->frame->core->height;
425 new_height -= wwin->frame->top_width+wwin->frame->bottom_width;
427 wWindowConstrainSize(wwin, &new_width, &new_height);
428 wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
430 #ifdef WMSOUND
431 wSoundPlay(WMSOUND_MAXIMIZE);
432 #endif
436 void
437 wUnmaximizeWindow(WWindow *wwin)
439 int restore_x, restore_y;
441 if (wwin->flags.shaded) {
442 wwin->flags.skip_next_animation = 1;
443 wUnshadeWindow(wwin);
445 restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ?
446 wwin->old_geometry.x : wwin->frame_x;
447 restore_y = (wwin->flags.maximized & MAX_VERTICAL) ?
448 wwin->old_geometry.y : wwin->frame_y;
449 wwin->flags.maximized = 0;
450 wWindowConfigure(wwin, restore_x, restore_y,
451 wwin->old_geometry.width, wwin->old_geometry.height);
453 #ifdef WMSOUND
454 wSoundPlay(WMSOUND_UNMAXIMIZE);
455 #endif
458 #ifdef ANIMATIONS
459 static void
460 animateResizeFlip(WScreen *scr, int x, int y, int w, int h,
461 int fx, int fy, int fw, int fh, int steps)
463 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
464 float cx, cy, cw, ch;
465 float xstep, ystep, wstep, hstep;
466 XPoint points[5];
467 float dx, dch, midy;
468 float angle, final_angle, delta;
470 xstep = (float)(fx-x)/steps;
471 ystep = (float)(fy-y)/steps;
472 wstep = (float)(fw-w)/steps;
473 hstep = (float)(fh-h)/steps;
475 cx = (float)x;
476 cy = (float)y;
477 cw = (float)w;
478 ch = (float)h;
480 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F;
481 delta = (float)(final_angle/FRAMES);
482 for (angle=0;; angle+=delta) {
483 if (angle > final_angle)
484 angle = final_angle;
486 dx = (cw/10) - ((cw/5) * sin(angle));
487 dch = (ch/2) * cos(angle);
488 midy = cy + (ch/2);
490 points[0].x = cx + dx; points[0].y = midy - dch;
491 points[1].x = cx + cw - dx; points[1].y = points[0].y;
492 points[2].x = cx + cw + dx; points[2].y = midy + dch;
493 points[3].x = cx - dx; points[3].y = points[2].y;
494 points[4].x = points[0].x; points[4].y = points[0].y;
496 XGrabServer(dpy);
497 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
498 XFlush(dpy);
499 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
500 wusleep(MINIATURIZE_ANIMATION_DELAY_F);
501 #endif
503 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
504 XUngrabServer(dpy);
505 cx+=xstep;
506 cy+=ystep;
507 cw+=wstep;
508 ch+=hstep;
509 if (angle >= final_angle)
510 break;
513 XFlush(dpy);
515 #undef FRAMES
518 static void
519 animateResizeTwist(WScreen *scr, int x, int y, int w, int h,
520 int fx, int fy, int fw, int fh, int steps)
522 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
523 float cx, cy, cw, ch;
524 float xstep, ystep, wstep, hstep;
525 XPoint points[5];
526 float angle, final_angle, a, d, delta;
528 x += w/2;
529 y += h/2;
530 fx += fw/2;
531 fy += fh/2;
533 xstep = (float)(fx-x)/steps;
534 ystep = (float)(fy-y)/steps;
535 wstep = (float)(fw-w)/steps;
536 hstep = (float)(fh-h)/steps;
538 cx = (float)x;
539 cy = (float)y;
540 cw = (float)w;
541 ch = (float)h;
543 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T;
544 delta = (float)(final_angle/FRAMES);
545 for (angle=0;; angle+=delta) {
546 if (angle > final_angle)
547 angle = final_angle;
549 a = atan(ch/cw);
550 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
552 points[0].x = cx+cos(angle-a)*d;
553 points[0].y = cy+sin(angle-a)*d;
554 points[1].x = cx+cos(angle+a)*d;
555 points[1].y = cy+sin(angle+a)*d;
556 points[2].x = cx+cos(angle-a+WM_PI)*d;
557 points[2].y = cy+sin(angle-a+WM_PI)*d;
558 points[3].x = cx+cos(angle+a+WM_PI)*d;
559 points[3].y = cy+sin(angle+a+WM_PI)*d;
560 points[4].x = cx+cos(angle-a)*d;
561 points[4].y = cy+sin(angle-a)*d;
562 XGrabServer(dpy);
563 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
564 XFlush(dpy);
565 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
566 wusleep(MINIATURIZE_ANIMATION_DELAY_T);
567 #endif
569 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
570 XUngrabServer(dpy);
571 cx+=xstep;
572 cy+=ystep;
573 cw+=wstep;
574 ch+=hstep;
575 if (angle >= final_angle)
576 break;
579 XFlush(dpy);
581 #undef FRAMES
584 static void
585 animateResizeZoom(WScreen *scr, int x, int y, int w, int h,
586 int fx, int fy, int fw, int fh, int steps)
588 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
589 float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
590 float xstep, ystep, wstep, hstep;
591 int i, j;
593 xstep = (float)(fx-x)/steps;
594 ystep = (float)(fy-y)/steps;
595 wstep = (float)(fw-w)/steps;
596 hstep = (float)(fh-h)/steps;
598 for (j=0; j<FRAMES; j++) {
599 cx[j] = (float)x;
600 cy[j] = (float)y;
601 cw[j] = (float)w;
602 ch[j] = (float)h;
604 XGrabServer(dpy);
605 for (i=0; i<steps; i++) {
606 for (j=0; j<FRAMES; j++) {
607 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
608 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
610 XFlush(dpy);
611 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
612 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
613 #endif
614 for (j=0; j<FRAMES; j++) {
615 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
616 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
617 if (j<FRAMES-1) {
618 cx[j]=cx[j+1];
619 cy[j]=cy[j+1];
620 cw[j]=cw[j+1];
621 ch[j]=ch[j+1];
622 } else {
623 cx[j]+=xstep;
624 cy[j]+=ystep;
625 cw[j]+=wstep;
626 ch[j]+=hstep;
631 for (j=0; j<FRAMES; j++) {
632 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
633 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
635 XFlush(dpy);
636 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
637 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
638 #endif
639 for (j=0; j<FRAMES; j++) {
640 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
641 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
644 XUngrabServer(dpy);
646 #undef FRAMES
649 static void
650 animateResize(WScreen *scr, int x, int y, int w, int h,
651 int fx, int fy, int fw, int fh, int hiding)
653 int style = wPreferences.iconification_style; /* Catch the value */
654 int steps, k;
656 if (style == WIS_NONE)
657 return;
659 k = (hiding ? 2 : 3);
660 switch(style) {
661 case WIS_TWIST:
662 steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
663 if (steps>0)
664 animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
665 break;
666 case WIS_FLIP:
667 steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
668 if (steps>0)
669 animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
670 break;
671 case WIS_ZOOM:
672 default:
673 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
674 if (steps>0)
675 animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
676 break;
679 #endif /* ANIMATIONS */
682 /* Here are defined the miniaturize animation functions. The above defined
683 * functions, use a separate function that implements the animation for each
684 * different style, and a wrapper that calls them accordingly.
685 * The below function is a single function that implements all the miniaturize
686 * animation styles in one single function, using switch{} and if() statements
687 * to differentiate them.
688 * The above code is more generic and elegant, letting one to extend it very
689 * easily (though I don't think one would ;), but will make the code a little
690 * bit bigger, using three functions and a wrapper.
691 * The below version, is smaller, being optimised for size, but is less
692 * elegant, and harder to be extended. Also is harder to read.
693 * I let them both here so you can take a look, and decide which one you like
694 * more. I would use the above functions because they are nicer, and easier to
695 * read and follow, and only a little bit bigger. -Dan
699 #ifdef ANIMATIONS_DONT_USE_THIS
700 static void
701 animateResize(WScreen *scr, int x, int y, int w, int h,
702 int fx, int fy, int fw, int fh, int hiding)
704 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
705 float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
706 float xstep, ystep, wstep, hstep;
707 XPoint points[5];
708 float angle, final_angle, a, d, delta, dx, dch, midy, twist=0.5;
709 int style = wPreferences.iconification_style; /* Catch the value */
710 /* to avoid changes while animating */
711 int frames, steps, delay, i, j;
713 if (style == WIS_NONE)
714 return;
716 switch(style) {
717 case WIS_TWIST:
718 frames = MINIATURIZE_ANIMATION_FRAMES_T;
719 steps = MINIATURIZE_ANIMATION_STEPS_T;
720 delay = MINIATURIZE_ANIMATION_DELAY_T;
721 twist = MINIATURIZE_ANIMATION_TWIST_T;
722 break;
723 case WIS_FLIP:
724 frames = MINIATURIZE_ANIMATION_FRAMES_F;
725 steps = MINIATURIZE_ANIMATION_STEPS_F;
726 delay = MINIATURIZE_ANIMATION_DELAY_F;
727 twist = MINIATURIZE_ANIMATION_TWIST_F;
728 break;
729 case WIS_ZOOM:
730 default:
731 frames = MINIATURIZE_ANIMATION_FRAMES_Z;
732 steps = MINIATURIZE_ANIMATION_STEPS_Z;
733 delay = MINIATURIZE_ANIMATION_DELAY_Z;
734 break;
737 steps = (hiding ? (steps*2)/3 : steps);
738 if (steps == 0)
739 return;
741 if (style == WIS_TWIST) {
742 x += w/2;
743 y += h/2;
744 fx += fw/2;
745 fy += fh/2;
747 xstep = (float)(fx-x)/steps;
748 ystep = (float)(fy-y)/steps;
749 wstep = (float)(fw-w)/steps;
750 hstep = (float)(fh-h)/steps;
751 for (j=0; j<frames; j++) {
752 cx[j] = (float)x;
753 cy[j] = (float)y;
754 cw[j] = (float)w;
755 ch[j] = (float)h;
758 if (style==WIS_TWIST || style==WIS_FLIP) {
759 final_angle = 2*WM_PI*twist;
760 delta = (float)(final_angle/frames);
761 for (angle=0;; angle+=delta) {
762 if (angle > final_angle)
763 angle = final_angle;
764 switch (style) {
765 case WIS_TWIST:
766 a = atan(ch[0]/cw[0]);
767 d = sqrt((cw[0]/2)*(cw[0]/2)+(ch[0]/2)*(ch[0]/2));
768 points[0].x = cx[0]+cos(angle-a)*d;
769 points[0].y = cy[0]+sin(angle-a)*d;
770 points[1].x = cx[0]+cos(angle+a)*d;
771 points[1].y = cy[0]+sin(angle+a)*d;
772 points[2].x = cx[0]+cos(angle-a+WM_PI)*d;
773 points[2].y = cy[0]+sin(angle-a+WM_PI)*d;
774 points[3].x = cx[0]+cos(angle+a+WM_PI)*d;
775 points[3].y = cy[0]+sin(angle+a+WM_PI)*d;
776 points[4].x = cx[0]+cos(angle-a)*d;
777 points[4].y = cy[0]+sin(angle-a)*d;
778 break;
779 case WIS_FLIP:
780 dx = (cw[0]/10) - ((cw[0]/5) * sin(angle));
781 dch = (ch[0]/2) * cos(angle);
782 midy = cy[0] + (ch[0]/2);
783 points[0].x = cx[0] + dx; points[0].y = midy - dch;
784 points[1].x = cx[0] + cw[0] - dx; points[1].y = points[0].y;
785 points[2].x = cx[0] + cw[0] + dx; points[2].y = midy + dch;
786 points[3].x = cx[0] - dx; points[3].y = points[2].y;
787 points[4].x = points[0].x; points[4].y = points[0].y;
788 break;
791 XGrabServer(dpy);
792 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
793 XFlush(dpy);
794 if (delay>0)
795 wusleep(delay);
797 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
798 XUngrabServer(dpy);
799 cx[0]+=xstep;
800 cy[0]+=ystep;
801 cw[0]+=wstep;
802 ch[0]+=hstep;
803 if (angle >= final_angle)
804 break;
807 XFlush(dpy);
808 } else {
809 /* Zoom or default */
810 XGrabServer(dpy);
811 for (i=0; i<steps; i++) {
812 for (j=0; j<frames; j++) {
813 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
814 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
816 XFlush(dpy);
817 if (delay>0)
818 wusleep(delay);
820 for (j=0; j<frames; j++) {
821 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
822 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
823 if (j<frames-1) {
824 cx[j]=cx[j+1];
825 cy[j]=cy[j+1];
826 cw[j]=cw[j+1];
827 ch[j]=ch[j+1];
828 } else {
829 cx[j]+=xstep;
830 cy[j]+=ystep;
831 cw[j]+=wstep;
832 ch[j]+=hstep;
837 for (j=0; j<frames; j++) {
838 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
839 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
841 XFlush(dpy);
842 if (delay>0)
843 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
845 for (j=0; j<frames; j++) {
846 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
847 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
850 XUngrabServer(dpy);
853 #undef FRAMES
854 #endif /* ANIMATIONS */
857 static void
858 flushExpose()
860 XEvent tmpev;
862 while (XCheckTypedEvent(dpy, Expose, &tmpev))
863 WMHandleEvent(&tmpev);
864 XSync(dpy, 0);
867 static void
868 unmapTransientsFor(WWindow *wwin)
870 WWindow *tmp;
871 XWindowAttributes attribs;
874 tmp = wwin->screen_ptr->focused_window;
875 while (tmp) {
876 /* unmap the transients for this transient */
877 if (tmp!=wwin && tmp->transient_for == wwin->client_win
878 && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
879 || tmp->flags.shaded)) {
880 unmapTransientsFor(tmp);
881 XGetWindowAttributes(dpy, tmp->client_win, &attribs);
882 tmp->flags.miniaturized=1;
883 if (!tmp->flags.shaded) {
884 tmp->flags.mapped=0;
885 XSelectInput(dpy, tmp->client_win,
886 attribs.your_event_mask & ~StructureNotifyMask);
887 XUnmapWindow(dpy, tmp->client_win);
888 XSelectInput(dpy, tmp->client_win, attribs.your_event_mask);
890 XUnmapWindow(dpy, tmp->frame->core->window);
891 if (!tmp->flags.shaded)
892 wClientSetState(tmp, IconicState, None);
893 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
895 tmp = tmp->prev;
900 static void
901 mapTransientsFor(WWindow *wwin)
903 WWindow *tmp;
905 tmp = wwin->screen_ptr->focused_window;
906 while (tmp) {
907 /* recursively map the transients for this transient */
908 if (tmp!=wwin && tmp->transient_for == wwin->client_win
909 && /*!tmp->flags.mapped*/ tmp->flags.miniaturized
910 && tmp->icon==NULL) {
911 mapTransientsFor(tmp);
912 tmp->flags.miniaturized=0;
913 if (!tmp->flags.shaded) {
914 tmp->flags.mapped=1;
915 XMapWindow(dpy, tmp->client_win);
917 XMapWindow(dpy, tmp->frame->core->window);
918 tmp->flags.semi_focused = 0;
919 if (!tmp->flags.shaded)
920 wClientSetState(tmp, NormalState, None);
921 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
923 tmp = tmp->prev;
928 static void
929 setupIconGrabs(WIcon *icon)
931 /* setup passive grabs on the icon */
932 XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
933 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
934 XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
935 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
936 XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
937 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
938 XSync(dpy, 0);
942 static WWindow*
943 recursiveTransientFor(WWindow *wwin)
945 if (!wwin)
946 return None;
948 /* TODO: a buggy client can put this in a infinite loop */
949 while (wwin->transient_for != None)
950 wwin = wWindowFor(wwin->transient_for);
952 return wwin;
956 static void
957 removeIconGrabs(WIcon *icon)
959 /* remove passive grabs on the icon */
960 XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
961 XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
962 XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);
963 XSync(dpy, 0);
967 void
968 wIconifyWindow(WWindow *wwin)
970 XWindowAttributes attribs;
971 int present;
974 if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
975 /* the window doesn't exist anymore */
976 return;
979 if (wwin->flags.miniaturized)
980 return;
982 if (wwin->transient_for!=None) {
983 WWindow *owner = wWindowFor(wwin->transient_for);
985 if (owner && owner->flags.miniaturized)
986 return;
989 present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
991 /* if the window is in another workspace, simplify process */
992 if (present) {
993 /* icon creation may take a while */
994 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
995 ButtonMotionMask|ButtonReleaseMask, GrabModeAsync,
996 GrabModeAsync, None, None, CurrentTime);
999 if (!wwin->flags.icon_moved) {
1000 PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y);
1002 wwin->icon = wIconCreate(wwin);
1004 wwin->flags.miniaturized=1;
1005 wwin->flags.mapped=0;
1007 /* unmap transients */
1009 unmapTransientsFor(wwin);
1011 if (present) {
1012 XUngrabPointer(dpy, CurrentTime);
1013 /* prevent window withdrawal when getting UnmapNotify */
1014 XSelectInput(dpy, wwin->client_win,
1015 attribs.your_event_mask & ~StructureNotifyMask);
1016 XUnmapWindow(dpy, wwin->client_win);
1017 XSelectInput(dpy, wwin->client_win, attribs.your_event_mask);
1018 XUnmapWindow(dpy, wwin->frame->core->window);
1019 /* let all Expose events arrive so that we can repaint
1020 * something before the animation starts (and the server is grabbed) */
1021 XSync(dpy, 0);
1022 wClientSetState(wwin, IconicState, wwin->icon->icon_win);
1023 flushExpose();
1024 #ifdef ANIMATIONS
1025 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
1026 && !wPreferences.no_animations) {
1027 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1028 wwin->frame->core->width, wwin->frame->core->height,
1029 wwin->icon_x, wwin->icon_y,
1030 wwin->icon->core->width, wwin->icon->core->height,
1031 False);
1033 #endif
1036 wwin->flags.skip_next_animation = 0;
1037 if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
1038 wwin->window_flags.omnipresent || wPreferences.sticky_icons)
1039 XMapWindow(dpy, wwin->icon->core->window);
1040 AddToStackList(wwin->icon->core);
1041 #ifndef STRICTNS
1042 wLowerFrame(wwin->icon->core);
1043 #endif
1045 if (present) {
1046 setupIconGrabs(wwin->icon);
1047 if ((wwin->flags.focused || wwin->client_win ==
1048 recursiveTransientFor(wwin->screen_ptr->focused_window)->client_win)
1049 && wPreferences.focus_mode==WKF_CLICK) {
1050 WWindow *tmp;
1052 tmp = wwin->prev;
1053 while (tmp) {
1054 if (!tmp->window_flags.no_focusable
1055 && !(tmp->flags.hidden||tmp->flags.miniaturized))
1056 break;
1057 tmp = tmp->prev;
1059 wSetFocusTo(wwin->screen_ptr, tmp);
1060 } else if (wPreferences.focus_mode!=WKF_CLICK) {
1061 wSetFocusTo(wwin->screen_ptr, NULL);
1064 #ifdef WMSOUND
1065 if (present) {
1066 wSoundPlay(WMSOUND_ICONIFY);
1068 #endif
1070 #ifdef ANIMATIONS
1072 if (!wwin->screen_ptr->flags.startup) {
1073 XSync(dpy, 0);
1074 processEvents(XPending(dpy));
1077 #endif
1081 if (wwin->flags.selected)
1082 wIconSelect(wwin->icon);
1084 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1090 void
1091 wDeiconifyWindow(WWindow *wwin)
1093 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1095 if (!wwin->flags.miniaturized)
1096 return;
1098 if (wwin->transient_for != None) {
1099 WWindow *owner = recursiveTransientFor(wwin);
1100 wDeiconifyWindow(owner);
1101 wSetFocusTo(wwin->screen_ptr, wwin);
1102 wRaiseFrame(wwin->frame->core);
1103 return;
1106 wwin->flags.miniaturized=0;
1107 if (!wwin->flags.shaded)
1108 wwin->flags.mapped=1;
1110 if (wwin->icon->selected)
1111 wIconSelect(wwin->icon);
1113 XUnmapWindow(dpy, wwin->icon->core->window);
1115 /* if the window is in another workspace, do it silently */
1116 #ifdef ANIMATIONS
1117 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1118 && !wwin->flags.skip_next_animation) {
1119 animateResize(wwin->screen_ptr, wwin->icon_x, wwin->icon_y,
1120 wwin->icon->core->width, wwin->icon->core->height,
1121 wwin->frame_x, wwin->frame_y,
1122 wwin->frame->core->width, wwin->frame->core->height,
1123 False);
1125 #endif /* ANIMATIONS */
1126 wwin->flags.skip_next_animation = 0;
1127 XGrabServer(dpy);
1128 if (!wwin->flags.shaded) {
1129 XMapWindow(dpy, wwin->client_win);
1131 XMapWindow(dpy, wwin->frame->core->window);
1132 wRaiseFrame(wwin->frame->core);
1133 if (!wwin->flags.shaded) {
1134 wClientSetState(wwin, NormalState, None);
1136 mapTransientsFor(wwin);
1137 RemoveFromStackList(wwin->icon->core);
1138 removeIconGrabs(wwin->icon);
1139 wIconDestroy(wwin->icon);
1140 wwin->icon = NULL;
1142 XUngrabServer(dpy);
1143 if (wPreferences.focus_mode==WKF_CLICK
1144 || wPreferences.focus_mode==WKF_SLOPPY)
1145 wSetFocusTo(wwin->screen_ptr, wwin);
1147 #ifdef WMSOUND
1148 wSoundPlay(WMSOUND_DEICONIFY);
1149 #endif
1151 #ifdef ANIMATIONS
1152 if (!wwin->screen_ptr->flags.startup) {
1153 XSync(dpy, 0);
1154 processEvents(XPending(dpy));
1156 #endif
1158 if (wPreferences.auto_arrange_icons) {
1159 wArrangeIcons(wwin->screen_ptr, True);
1162 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1168 static void
1169 hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
1171 XWindowAttributes attribs;
1174 if (wwin->flags.miniaturized) {
1175 XUnmapWindow(dpy, wwin->icon->core->window);
1176 wwin->flags.hidden = 1;
1177 wwin->icon->mapped = 0;
1178 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1179 return;
1182 if (wwin->flags.inspector_open) {
1183 WWindow *pwin = wwin->inspector->frame;
1185 XGetWindowAttributes(dpy, pwin->client_win, &attribs);
1186 pwin->flags.hidden = 1;
1187 pwin->flags.mapped = 0;
1188 /* prevent window withdrawal when getting UnmapNotify */
1189 XSelectInput(dpy, pwin->client_win,
1190 attribs.your_event_mask & ~StructureNotifyMask);
1191 XUnmapWindow(dpy, pwin->client_win);
1192 XSelectInput(dpy, pwin->client_win, attribs.your_event_mask);
1194 XUnmapWindow(dpy, pwin->frame->core->window);
1195 wClientSetState(pwin, IconicState, icon->icon_win);
1198 XGetWindowAttributes(dpy, wwin->client_win, &attribs);
1200 wwin->flags.hidden = 1;
1201 wwin->flags.mapped = 0;
1203 /* prevent window withdrawal when getting UnmapNotify */
1204 XSelectInput(dpy, wwin->client_win,
1205 attribs.your_event_mask & ~StructureNotifyMask);
1206 XUnmapWindow(dpy, wwin->client_win);
1207 XSelectInput(dpy, wwin->client_win, attribs.your_event_mask);
1209 XUnmapWindow(dpy, wwin->frame->core->window);
1210 wClientSetState(wwin, IconicState, icon->icon_win);
1211 flushExpose();
1212 #ifdef ANIMATIONS
1213 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1214 !wwin->flags.skip_next_animation && animate) {
1215 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1216 wwin->frame->core->width, wwin->frame->core->height,
1217 icon_x, icon_y, icon->core->width, icon->core->height,
1218 True);
1220 #endif
1221 wwin->flags.skip_next_animation = 0;
1223 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1225 #ifdef WMSOUND
1226 wSoundPlay(WMSOUND_HIDE);
1227 #endif
1232 void
1233 wHideOtherApplications(WWindow *awin)
1235 WWindow *wwin;
1236 WApplication *tapp;
1237 #ifdef REDUCE_APPICONS
1238 char *tinstance, *tclass;
1239 unsigned int brokenwin = 0, match = 0;
1240 #endif
1242 if (!awin)
1243 return;
1244 wwin = awin->screen_ptr->focused_window;
1246 #ifdef REDUCE_APPICONS
1247 if (awin->wm_instance == NULL || awin->wm_class == NULL)
1248 brokenwin++;
1249 #endif
1251 while (wwin) {
1252 if (wwin!=awin
1253 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1254 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1255 && !wwin->flags.internal_window
1256 && (!wwin->flags.inspector_open || wwin->inspector->frame!=awin)
1257 && !wwin->window_flags.no_hide_others) {
1259 #ifdef REDUCE_APPICONS
1260 match = 0;
1261 if (!brokenwin) {
1262 if ((tinstance = wwin->wm_instance) == NULL)
1263 tinstance = "";
1264 if ((tclass = wwin->wm_class) == NULL)
1265 tclass = "";
1266 if ((strcmp(awin->wm_instance, tinstance) == 0) &&
1267 (strcmp(awin->wm_class, tclass) == 0) )
1268 match++;
1270 #endif
1272 if (wwin->main_window==None) {
1273 if (!wwin->window_flags.no_miniaturizable) {
1274 wwin->flags.skip_next_animation = 1;
1275 wIconifyWindow(wwin);
1277 } else if (wwin->main_window!=None
1278 #ifndef REDUCE_APPICONS
1279 && awin->main_window != wwin->main_window) {
1280 #else
1281 && (awin->main_window != wwin->main_window && !match)) {
1282 #endif
1283 tapp = wApplicationOf(wwin->main_window);
1284 if (tapp) {
1285 tapp->flags.skip_next_animation = 1;
1286 wHideApplication(tapp);
1287 } else {
1288 if (!wwin->window_flags.no_miniaturizable) {
1289 wwin->flags.skip_next_animation = 1;
1290 wIconifyWindow(wwin);
1295 wwin = wwin->prev;
1298 wSetFocusTo(awin->screen_ptr, awin);
1304 void
1305 wHideApplication(WApplication *wapp)
1307 #ifdef REDUCE_APPICONS
1308 WApplication *tapp;
1309 char *tinstance, *tclass;
1310 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1311 #endif
1312 WScreen *scr;
1313 WWindow *wlist;
1314 int hadfocus;
1316 if (!wapp) {
1317 wwarning("trying to hide a non grouped window");
1318 return;
1320 if (!wapp->main_window_desc) {
1321 wwarning("group leader not found for window group");
1322 return;
1324 #ifdef REDUCE_APPICONS
1325 if ((wapp->main_window_desc->wm_instance == NULL) ||
1326 (wapp->main_window_desc->wm_class == NULL))
1327 nowmhints++;
1328 #endif
1329 scr = wapp->main_window_desc->screen_ptr;
1330 hadfocus = 0;
1331 wlist = scr->focused_window;
1332 if (!wlist)
1333 return;
1335 if (wlist->main_window == wapp->main_window)
1336 wapp->last_focused = wlist;
1337 else
1338 wapp->last_focused = NULL;
1339 while (wlist) {
1340 #ifdef REDUCE_APPICONS
1341 matchwmhints = matchworkspace = 0;
1342 if (!nowmhints) {
1343 tapp = wApplicationOf(wlist->main_window);
1344 tinstance = tclass = NULL;
1345 if (tapp) {
1346 if (tapp->main_window_desc) {
1347 tinstance = tapp->main_window_desc->wm_instance;
1348 tclass = tapp->main_window_desc->wm_class;
1351 if (tapp == NULL || tinstance == NULL || tclass == NULL) {
1352 /* Should never reach here */
1353 tinstance = "";
1354 tclass = "";
1356 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0) &&
1357 (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1358 matchwmhints++;
1360 if (wlist->frame) {
1361 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1362 matchworkspace++;
1364 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1365 matchworkspace) {
1366 #ifdef I_HATE_THIS
1368 #endif
1369 #else
1370 if (wlist->main_window == wapp->main_window) {
1371 #endif
1372 if (wlist->flags.focused) {
1373 hadfocus = 1;
1375 if (wapp->app_icon)
1376 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1377 wapp->app_icon->y_pos, wlist,
1378 !wapp->flags.skip_next_animation);
1380 wlist = wlist->prev;
1383 wapp->flags.skip_next_animation = 0;
1385 if (hadfocus) {
1386 if (wPreferences.focus_mode==WKF_CLICK) {
1387 wlist = scr->focused_window;
1388 while (wlist) {
1389 if (!wlist->window_flags.no_focusable && !wlist->flags.hidden
1390 && (wlist->flags.mapped || wlist->flags.shaded))
1391 break;
1392 wlist = wlist->prev;
1394 wSetFocusTo(scr, wlist);
1395 } else {
1396 wSetFocusTo(scr, NULL);
1400 wapp->flags.hidden = 1;
1406 static void
1407 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1408 int bringToCurrentWS)
1410 if (bringToCurrentWS)
1411 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1413 wwin->flags.hidden=0;
1414 wwin->flags.mapped=1;
1415 #ifdef ANIMATIONS
1416 /* something is redundant here. animate passed here is
1417 * !wwin->flags.skip_next_animation, so this flag is tested twice.
1418 * Either we shold not test skip_next_animation here, or don't pass
1419 * animate to this function. -Dan
1421 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1422 !wwin->flags.skip_next_animation && animate) {
1423 animateResize(wwin->screen_ptr, icon_x, icon_y,
1424 icon->core->width, icon->core->height,
1425 wwin->frame_x, wwin->frame_y,
1426 wwin->frame->core->width, wwin->frame->core->height,
1427 True);
1429 #endif
1430 wwin->flags.skip_next_animation = 0;
1431 XMapWindow(dpy, wwin->client_win);
1432 XMapWindow(dpy, wwin->frame->core->window);
1433 wClientSetState(wwin, NormalState, None);
1434 wRaiseFrame(wwin->frame->core);
1435 if (wwin->flags.inspector_open) {
1436 WWindow *pwin = wwin->inspector->frame;
1438 pwin->flags.hidden = 0;
1439 pwin->flags.mapped = 1;
1440 XMapWindow(dpy, pwin->client_win);
1441 XMapWindow(dpy, pwin->frame->core->window);
1442 wClientSetState(pwin, NormalState, None);
1445 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1447 #ifdef WMSOUND
1448 wSoundPlay(WMSOUND_UNHIDE);
1449 #endif
1453 void
1454 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1456 WScreen *scr;
1457 WWindow *wlist, *next;
1458 WWindow *focused=NULL;
1459 #ifdef REDUCE_APPICONS
1460 char *tinstance, *tclass;
1461 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1462 #endif
1464 if (!wapp) {
1465 return;
1468 #ifdef REDUCE_APPICONS
1469 if ((wapp->main_window_desc->wm_class == NULL) ||
1470 (wapp->main_window_desc->wm_instance == NULL))
1471 nowmhints++;
1472 #endif
1474 scr = wapp->main_window_desc->screen_ptr;
1475 wlist = scr->focused_window;
1476 if (!wlist) return;
1477 /* goto beginning of list */
1478 while (wlist->prev)
1479 wlist = wlist->prev;
1481 while (wlist) {
1482 next = wlist->next;
1484 #ifndef REDUCE_APPICONS
1485 if (wlist->main_window == wapp->main_window) {
1486 #else
1487 matchwmhints = matchworkspace = 0;
1488 if (!nowmhints) {
1489 if ((tinstance = wlist->wm_instance) == NULL)
1490 tinstance = "";
1491 if ((tclass = wlist->wm_class) == NULL)
1492 tclass = "";
1493 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0)
1494 && (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1495 matchwmhints++;
1497 if (wlist->frame) {
1498 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1499 matchworkspace++;
1502 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1503 matchworkspace) {
1504 #endif
1505 if (wlist->flags.focused)
1506 focused = wlist;
1507 else if (!focused || !focused->flags.focused)
1508 focused = wlist;
1510 if (wlist->flags.miniaturized && wlist->icon) {
1511 if (bringToCurrentWS || wPreferences.sticky_icons
1512 || wlist->frame->workspace == scr->current_workspace) {
1513 if (!wlist->icon->mapped) {
1514 XMapWindow(dpy, wlist->icon->core->window);
1515 wlist->icon->mapped = 1;
1517 wlist->flags.hidden = 0;
1518 UpdateSwitchMenu(scr, wlist, ACTION_CHANGE_STATE);
1519 if (wlist->frame->workspace != scr->current_workspace)
1520 wWindowChangeWorkspace(wlist, scr->current_workspace);
1522 if (miniwindows) {
1523 wDeiconifyWindow(wlist);
1525 } else if (wlist->flags.hidden) {
1526 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1527 wapp->app_icon->y_pos, wlist,
1528 !wapp->flags.skip_next_animation,
1529 bringToCurrentWS);
1530 } else {
1531 if (bringToCurrentWS
1532 && wlist->frame->workspace != scr->current_workspace) {
1533 wWindowChangeWorkspace(wlist, scr->current_workspace);
1535 wRaiseFrame(wlist->frame->core);
1538 wlist = next;
1541 wapp->flags.skip_next_animation = 0;
1542 wapp->flags.hidden = 0;
1544 if (focused)
1545 wSetFocusTo(scr, focused);
1546 else if (wapp->last_focused && wapp->last_focused->flags.mapped)
1547 wSetFocusTo(scr, wapp->last_focused);
1548 wapp->last_focused = NULL;
1549 if (wPreferences.auto_arrange_icons) {
1550 wArrangeIcons(scr, True);
1556 void
1557 wShowAllWindows(WScreen *scr)
1559 WWindow *wwin, *old_foc;
1560 WApplication *wapp;
1562 old_foc = wwin = scr->focused_window;
1563 while (wwin) {
1564 if (!wwin->flags.internal_window &&
1565 (scr->current_workspace == wwin->frame->workspace
1566 || wwin->window_flags.omnipresent)) {
1567 if (wwin->flags.miniaturized) {
1568 wwin->flags.skip_next_animation = 1;
1569 wDeiconifyWindow(wwin);
1570 } else if (wwin->flags.hidden) {
1571 wapp = wApplicationOf(wwin->main_window);
1572 if (wapp) {
1573 wUnhideApplication(wapp, False, False);
1574 } else {
1575 wwin->flags.skip_next_animation = 1;
1576 wDeiconifyWindow(wwin);
1580 wwin = wwin->prev;
1582 wSetFocusTo(scr, old_foc);
1583 /*wRaiseFrame(old_foc->frame->core);*/
1587 void
1588 wRefreshDesktop(WScreen *scr)
1590 Window win;
1591 XSetWindowAttributes attr;
1593 attr.backing_store = NotUseful;
1594 attr.save_under = False;
1595 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1596 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1597 (Visual *) CopyFromParent, CWBackingStore|CWSaveUnder,
1598 &attr);
1599 XMapRaised(dpy, win);
1600 XDestroyWindow(dpy, win);
1601 XFlush(dpy);
1605 void
1606 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1608 WWindow *wwin;
1609 WAppIcon *aicon;
1610 int pf; /* primary axis */
1611 int sf; /* secondary axis */
1612 int fullW;
1613 int fullH;
1614 int pi, si;
1615 int sx1, sx2, sy1, sy2; /* screen boundary */
1616 int sw, sh;
1617 int xo, yo;
1618 int xs, ys;
1619 int isize = wPreferences.icon_size;
1622 * Find out screen boundaries.
1624 sx1 = 0;
1625 sy1 = 0;
1626 sx2 = scr->scr_width;
1627 sy2 = scr->scr_height;
1628 if (scr->dock) {
1629 if (scr->dock->on_right_side)
1630 sx2 -= isize + DOCK_EXTRA_SPACE;
1631 else
1632 sx1 += isize + DOCK_EXTRA_SPACE;
1635 sw = isize * (scr->scr_width/isize);
1636 sh = isize * (scr->scr_height/isize);
1637 fullW = (sx2-sx1)/isize;
1638 fullH = (sy2-sy1)/isize;
1640 /* icon yard boundaries */
1641 if (wPreferences.icon_yard & IY_VERT) {
1642 pf = fullH;
1643 sf = fullW;
1644 } else {
1645 pf = fullW;
1646 sf = fullH;
1648 if (wPreferences.icon_yard & IY_RIGHT) {
1649 xo = sx2 - isize;
1650 xs = -1;
1651 } else {
1652 xo = sx1;
1653 xs = 1;
1655 if (wPreferences.icon_yard & IY_TOP) {
1656 yo = sy1;
1657 ys = 1;
1658 } else {
1659 yo = sy2 - isize;
1660 ys = -1;
1663 /* arrange icons putting the most recently focused window
1664 * as the last icon */
1665 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1666 : xo + xs*(pi*isize))
1667 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1668 : yo + ys*(si*isize))
1670 /* arrange application icons */
1671 aicon = scr->app_icon_list;
1672 /* reverse them to avoid unnecessarily sliding of icons */
1673 while (aicon && aicon->next)
1674 aicon = aicon->next;
1676 pi = 0;
1677 si = 0;
1678 while (aicon) {
1679 if (!aicon->docked) {
1680 if (aicon->x_pos != X || aicon->y_pos != Y) {
1681 #ifdef ANIMATIONS
1682 if (!wPreferences.no_animations) {
1683 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1684 X, Y);
1686 #endif /* ANIMATIONS */
1688 wAppIconMove(aicon, X, Y);
1689 pi++;
1691 /* we reversed the order so we use prev */
1692 aicon = aicon->prev;
1693 if (pi >= pf) {
1694 pi=0;
1695 si++;
1699 /* arrange miniwindows */
1701 wwin = scr->focused_window;
1702 /* reverse them to avoid unnecessarily shuffling */
1703 while (wwin && wwin->prev)
1704 wwin = wwin->prev;
1706 while (wwin) {
1707 if (wwin->icon && wwin->flags.miniaturized &&
1708 (wwin->frame->workspace==scr->current_workspace ||
1709 wwin->window_flags.omnipresent ||
1710 wPreferences.sticky_icons)) {
1712 if (arrangeAll || !wwin->flags.icon_moved) {
1713 if (wwin->icon_x != X || wwin->icon_y != Y) {
1714 #ifdef ANIMATIONS
1715 if (wPreferences.no_animations) {
1716 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1717 } else {
1718 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1719 wwin->icon_y, X, Y);
1721 #else
1722 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1723 #endif /* ANIMATIONS */
1725 wwin->icon_x = X;
1726 wwin->icon_y = Y;
1727 wwin->flags.icon_moved = 0;
1728 pi++;
1731 /* we reversed the order, so we use next */
1732 wwin = wwin->next;
1733 if (pi >= pf) {
1734 pi=0;
1735 si++;