Latest fixes, before releasing 0.50.0
[wmaker-crm.git] / src / actions.c
blob24bde0ea09b7f67e39940b0ac8b44d8eff08011b
1 /* action.c- misc. window commands (miniaturize, hide etc.)
2 *
3 * Window Maker 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.
23 #define HACK
25 #include "wconfig.h"
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <math.h>
34 #include <time.h>
36 #include "WindowMaker.h"
37 #include "wcore.h"
38 #include "framewin.h"
39 #include "window.h"
40 #include "client.h"
41 #include "icon.h"
42 #include "funcs.h"
43 #include "application.h"
44 #include "actions.h"
45 #include "stacking.h"
46 #include "appicon.h"
47 #include "dock.h"
48 #include "appmenu.h"
49 #include "winspector.h"
50 #include "list.h"
51 #include "workspace.h"
53 #ifdef GNOME_STUFF
54 # include "gnome.h"
55 #endif
56 #ifdef KWM_HINTS
57 # include "kwm.h"
58 #endif
60 #ifdef WMSOUND
61 #include "wmsound.h"
62 #endif
65 /****** Global Variables ******/
66 extern Time LastTimestamp;
67 extern Time LastFocusChange;
69 extern Cursor wCursor[WCUR_LAST];
71 extern WPreferences wPreferences;
73 extern Atom _XA_WM_TAKE_FOCUS;
75 /******* Local Variables *******/
76 static struct {
77 int steps;
78 int delay;
79 } shadePars[5] = {
80 {SHADE_STEPS_UF, SHADE_DELAY_UF},
81 {SHADE_STEPS_F, SHADE_DELAY_F},
82 {SHADE_STEPS_M, SHADE_DELAY_M},
83 {SHADE_STEPS_S, SHADE_DELAY_S},
84 {SHADE_STEPS_U, SHADE_DELAY_U}};
86 #define SHADE_STEPS shadePars[(int)wPreferences.shade_speed].steps
87 #define SHADE_DELAY shadePars[(int)wPreferences.shade_speed].delay
90 static int ignoreTimestamp=0;
93 #ifdef ANIMATIONS
94 static void
95 processEvents(int event_count)
97 XEvent event;
100 * This is a hack. When animations are enabled, processing of
101 * events ocurred during a animation are delayed until it's end.
102 * Calls that consider the TimeStamp, like XSetInputFocus(), will
103 * fail because the TimeStamp is too old. Then, for example, if
104 * the user changes window focus while a miniaturize animation is
105 * in course, the window will not get focus properly after the end
106 * of the animation. This tries to workaround it by passing CurrentTime
107 * as the TimeStamp for XSetInputFocus() for all events ocurred during
108 * the animation.
110 ignoreTimestamp=1;
111 while (XPending(dpy) && event_count--) {
112 WMNextEvent(dpy, &event);
113 WMHandleEvent(&event);
115 ignoreTimestamp=0;
117 #endif /* ANIMATIONS */
121 *----------------------------------------------------------------------
122 * wSetFocusTo--
123 * Changes the window focus to the one passed as argument.
124 * If the window to focus is not already focused, it will be brought
125 * to the head of the list of windows. Previously focused window is
126 * unfocused.
128 * Side effects:
129 * Window list may be reordered and the window focus is changed.
131 *----------------------------------------------------------------------
133 void
134 wSetFocusTo(WScreen *scr, WWindow *wwin)
136 WWindow *focused=scr->focused_window;
137 WWindow *owner = NULL;
138 int timestamp=LastTimestamp;
139 WApplication *oapp=NULL, *napp=NULL;
140 int wasfocused;
142 LastFocusChange = timestamp;
144 #ifndef HACK
145 if (ignoreTimestamp)
146 #endif
147 timestamp = CurrentTime;
149 if (focused)
150 oapp = wApplicationOf(focused->main_window);
152 if (wwin==NULL) {
153 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
154 if (focused) {
155 wWindowUnfocus(focused);
157 if (oapp) {
158 wAppMenuUnmap(oapp->menu);
159 #ifdef NEWAPPICON
160 wApplicationDeactivate(oapp);
161 #endif
163 #ifdef KWM_HINTS
164 wKWMUpdateActiveWindowHint(scr);
165 wKWMSendEventMessage(NULL, WKWMFocusWindow);
166 #endif
167 return;
169 wasfocused = wwin->flags.focused;
170 napp = wApplicationOf(wwin->main_window);
172 /* remember last workspace where the app has been */
173 if (napp)
174 napp->last_workspace = wwin->screen_ptr->current_workspace;
176 if (WFLAGP(wwin, no_focusable))
177 return;
179 if (wwin->flags.mapped) {
180 /* install colormap if colormap mode is lock mode */
181 if (wPreferences.colormap_mode==WKF_CLICK)
182 wColormapInstallForWindow(scr, wwin);
184 /* set input focus */
185 switch (wwin->focus_mode) {
186 case WFM_NO_INPUT:
187 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
188 break;
190 case WFM_PASSIVE:
191 case WFM_LOCALLY_ACTIVE:
192 XSetInputFocus(dpy, wwin->client_win, RevertToParent, timestamp);
193 break;
195 case WFM_GLOBALLY_ACTIVE:
196 break;
198 XFlush(dpy);
199 if (wwin->protocols.TAKE_FOCUS) {
200 wClientSendProtocol(wwin, _XA_WM_TAKE_FOCUS, timestamp);
202 XSync(dpy, False);
203 } else {
204 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
207 /* if this is not the focused window focus it */
208 if (focused!=wwin) {
209 int foo=0;
211 if (wwin->client_win == focused->transient_for)
212 wwin->flags.semi_focused = 0;
213 else if (wwin->transient_for == focused->client_win)
214 focused->flags.semi_focused = 1;
216 if (wwin->transient_for
217 && wwin->transient_for == focused->transient_for) {
218 owner = wWindowFor(wwin->transient_for);
219 if (owner && owner->flags.semi_focused) {
220 foo=1;
221 /* this is to override the unfocusing of the mainwindow
222 * in the next wWindowUnfocus() and avoid flickering */
223 owner->flags.semi_focused = 0;
226 /* unfocus previous window */
227 wWindowUnfocus(focused);
228 if (foo) {
229 owner->flags.semi_focused = 1;
231 /* change the focus window list order */
232 if (wwin->prev)
233 wwin->prev->next=wwin->next;
234 if (wwin->next)
235 wwin->next->prev=wwin->prev;
237 wwin->prev = focused;
238 focused->next = wwin;
239 wwin->next = NULL;
240 scr->focused_window = wwin;
242 if (oapp && oapp != napp) {
243 wAppMenuUnmap(oapp->menu);
244 #ifdef NEWAPPICON
245 wApplicationDeactivate(oapp);
246 #endif
249 if ((owner=wWindowFor(wwin->transient_for))
250 && !owner->flags.semi_focused) {
251 owner->flags.semi_focused = 1;
252 wWindowUnfocus(owner);
254 wWindowFocus(wwin);
255 if (napp && !wasfocused) {
256 wAppMenuMap(napp->menu, wwin);
257 #ifdef NEWAPPICON
258 wApplicationActivate(napp);
259 #endif
261 #ifdef KWM_HINTS
262 wKWMUpdateActiveWindowHint(scr);
263 wKWMSendEventMessage(wwin, WKWMFocusWindow);
264 #endif
265 XFlush(dpy);
269 void
270 wShadeWindow(WWindow *wwin)
272 XWindowAttributes attribs;
273 time_t time0 = time(NULL);
274 #ifdef ANIMATIONS
275 int y, s, w, h;
276 #endif
278 if (wwin->flags.shaded)
279 return;
281 XLowerWindow(dpy, wwin->client_win);
283 #ifdef WMSOUND
284 wSoundPlay(WMSOUND_SHADE);
285 #endif
287 #ifdef ANIMATIONS
288 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
289 && !wPreferences.no_animations) {
290 /* do the shading animation */
291 h = wwin->frame->core->height;
292 s = h/SHADE_STEPS;
293 if (s < 1) s=1;
294 w = wwin->frame->core->width;
295 y = wwin->frame->top_width;
296 while (h>wwin->frame->top_width+1) {
297 XMoveWindow(dpy, wwin->client_win, 0, y);
298 XResizeWindow(dpy, wwin->frame->core->window, w, h);
299 XFlush(dpy);
301 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
302 break;
304 if (SHADE_DELAY > 0)
305 wusleep(SHADE_DELAY*1000L);
306 h-=s;
307 y-=s;
309 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
311 #endif /* ANIMATIONS */
314 wwin->flags.skip_next_animation = 0;
315 XGetWindowAttributes(dpy, wwin->client_win, &attribs);
316 wwin->flags.shaded=1;
317 wwin->flags.mapped=0;
318 /* prevent window withdrawal when getting UnmapNotify */
319 XSelectInput(dpy, wwin->client_win,
320 attribs.your_event_mask & ~StructureNotifyMask);
321 XUnmapWindow(dpy, wwin->client_win);
322 XSelectInput(dpy, wwin->client_win, attribs.your_event_mask);
324 /* for the client it's just like iconification */
325 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
326 wwin->frame->top_width-1);
328 wwin->client.y = wwin->frame_y - wwin->client.height
329 + wwin->frame->top_width;
330 wWindowSynthConfigureNotify(wwin);
333 wClientSetState(wwin, IconicState, None);
336 #ifdef GNOME_STUFF
337 wGNOMEUpdateClientStateHint(wwin, False);
338 #endif
339 #ifdef KWM_HINTS
340 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
341 wKWMSendEventMessage(wwin, WKWMChangedClient);
342 #endif
343 /* update window list to reflect shaded state */
344 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
346 #ifdef ANIMATIONS
347 if (!wwin->screen_ptr->flags.startup) {
348 /* Look at processEvents() for reason of this code. */
349 XSync(dpy, 0);
350 processEvents(XPending(dpy));
352 #endif
356 void
357 wUnshadeWindow(WWindow *wwin)
359 time_t time0 = time(NULL);
360 #ifdef ANIMATIONS
361 int y, s, w, h;
362 #endif /* ANIMATIONS */
365 if (!wwin->flags.shaded)
366 return;
368 wwin->flags.shaded=0;
369 wwin->flags.mapped=1;
370 XMapWindow(dpy, wwin->client_win);
372 #ifdef WMSOUND
373 wSoundPlay(WMSOUND_UNSHADE);
374 #endif
376 #ifdef ANIMATIONS
377 if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) {
378 /* do the shading animation */
379 h = wwin->frame->top_width + wwin->frame->bottom_width;
380 y = wwin->frame->top_width - wwin->client.height;
381 s = abs(y)/SHADE_STEPS;
382 if (s<1) s=1;
383 w = wwin->frame->core->width;
384 XMoveWindow(dpy, wwin->client_win, 0, y);
385 if (s>0) {
386 while (h < wwin->client.height + wwin->frame->top_width
387 + wwin->frame->bottom_width) {
388 XResizeWindow(dpy, wwin->frame->core->window, w, h);
389 XMoveWindow(dpy, wwin->client_win, 0, y);
390 XSync(dpy, 0);
391 if (SHADE_DELAY > 0)
392 wusleep(SHADE_DELAY*2000L/3);
393 h+=s;
394 y+=s;
396 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
397 break;
400 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
402 #endif /* ANIMATIONS */
404 wwin->flags.skip_next_animation = 0;
405 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
406 wwin->frame->top_width + wwin->client.height
407 + wwin->frame->bottom_width);
409 wwin->client.y = wwin->frame_y + wwin->frame->top_width;
410 wWindowSynthConfigureNotify(wwin);
413 wClientSetState(wwin, NormalState, None);
415 /* if the window is focused, set the focus again as it was disabled during
416 * shading */
417 if (wwin->flags.focused)
418 wSetFocusTo(wwin->screen_ptr, wwin);
420 #ifdef GNOME_STUFF
421 wGNOMEUpdateClientStateHint(wwin, False);
422 #endif
423 #ifdef KWM_HINTS
424 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
425 wKWMSendEventMessage(wwin, WKWMChangedClient);
426 #endif
428 /* update window list to reflect unshaded state */
429 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
434 void
435 wMaximizeWindow(WWindow *wwin, int directions)
437 int new_width, new_height, new_x, new_y;
438 WArea usableArea = wwin->screen_ptr->totalUsableArea;
440 if (wwin->flags.shaded) {
441 wwin->flags.skip_next_animation = 1;
442 wUnshadeWindow(wwin);
444 wwin->flags.maximized = directions;
445 wwin->old_geometry.width = wwin->client.width;
446 wwin->old_geometry.height = wwin->client.height;
447 wwin->old_geometry.x = wwin->frame_x;
448 wwin->old_geometry.y = wwin->frame_y;
450 #ifdef KWM_HINTS
451 wKWMUpdateClientGeometryRestore(wwin);
452 #endif
454 if (directions & MAX_HORIZONTAL) {
456 new_width = (usableArea.x2-usableArea.x1)-FRAME_BORDER_WIDTH*2;
457 new_x = usableArea.x1;
459 } else {
461 new_x = wwin->frame_x;
462 new_width = wwin->frame->core->width;
466 if (directions & MAX_VERTICAL) {
468 new_height = (usableArea.y2-usableArea.y1)-FRAME_BORDER_WIDTH*2;
469 new_y = usableArea.y1;
471 } else {
473 new_y = wwin->frame_y;
474 new_height = wwin->frame->core->height;
477 new_height -= wwin->frame->top_width+wwin->frame->bottom_width;
479 wWindowConstrainSize(wwin, &new_width, &new_height);
480 wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
482 #ifdef GNOME_STUFF
483 wGNOMEUpdateClientStateHint(wwin, False);
484 #endif
485 #ifdef KWM_HINTS
486 wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
487 wKWMSendEventMessage(wwin, WKWMChangedClient);
488 #endif
490 #ifdef WMSOUND
491 wSoundPlay(WMSOUND_MAXIMIZE);
492 #endif
496 void
497 wUnmaximizeWindow(WWindow *wwin)
499 int restore_x, restore_y;
501 if (!wwin->flags.maximized)
502 return;
504 if (wwin->flags.shaded) {
505 wwin->flags.skip_next_animation = 1;
506 wUnshadeWindow(wwin);
508 restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ?
509 wwin->old_geometry.x : wwin->frame_x;
510 restore_y = (wwin->flags.maximized & MAX_VERTICAL) ?
511 wwin->old_geometry.y : wwin->frame_y;
512 wwin->flags.maximized = 0;
513 wWindowConfigure(wwin, restore_x, restore_y,
514 wwin->old_geometry.width, wwin->old_geometry.height);
516 #ifdef GNOME_STUFF
517 wGNOMEUpdateClientStateHint(wwin, False);
518 #endif
519 #ifdef KWM_HINTS
520 wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
521 wKWMSendEventMessage(wwin, WKWMChangedClient);
522 #endif
524 #ifdef WMSOUND
525 wSoundPlay(WMSOUND_UNMAXIMIZE);
526 #endif
529 #ifdef ANIMATIONS
530 static void
531 animateResizeFlip(WScreen *scr, int x, int y, int w, int h,
532 int fx, int fy, int fw, int fh, int steps)
534 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
535 float cx, cy, cw, ch;
536 float xstep, ystep, wstep, hstep;
537 XPoint points[5];
538 float dx, dch, midy;
539 float angle, final_angle, delta;
541 xstep = (float)(fx-x)/steps;
542 ystep = (float)(fy-y)/steps;
543 wstep = (float)(fw-w)/steps;
544 hstep = (float)(fh-h)/steps;
546 cx = (float)x;
547 cy = (float)y;
548 cw = (float)w;
549 ch = (float)h;
551 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F;
552 delta = (float)(final_angle/FRAMES);
553 for (angle=0;; angle+=delta) {
554 if (angle > final_angle)
555 angle = final_angle;
557 dx = (cw/10) - ((cw/5) * sin(angle));
558 dch = (ch/2) * cos(angle);
559 midy = cy + (ch/2);
561 points[0].x = cx + dx; points[0].y = midy - dch;
562 points[1].x = cx + cw - dx; points[1].y = points[0].y;
563 points[2].x = cx + cw + dx; points[2].y = midy + dch;
564 points[3].x = cx - dx; points[3].y = points[2].y;
565 points[4].x = points[0].x; points[4].y = points[0].y;
567 XGrabServer(dpy);
568 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
569 XFlush(dpy);
570 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
571 wusleep(MINIATURIZE_ANIMATION_DELAY_F);
572 #endif
574 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
575 XUngrabServer(dpy);
576 cx+=xstep;
577 cy+=ystep;
578 cw+=wstep;
579 ch+=hstep;
580 if (angle >= final_angle)
581 break;
584 XFlush(dpy);
586 #undef FRAMES
589 static void
590 animateResizeTwist(WScreen *scr, int x, int y, int w, int h,
591 int fx, int fy, int fw, int fh, int steps)
593 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
594 float cx, cy, cw, ch;
595 float xstep, ystep, wstep, hstep;
596 XPoint points[5];
597 float angle, final_angle, a, d, delta;
599 x += w/2;
600 y += h/2;
601 fx += fw/2;
602 fy += fh/2;
604 xstep = (float)(fx-x)/steps;
605 ystep = (float)(fy-y)/steps;
606 wstep = (float)(fw-w)/steps;
607 hstep = (float)(fh-h)/steps;
609 cx = (float)x;
610 cy = (float)y;
611 cw = (float)w;
612 ch = (float)h;
614 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T;
615 delta = (float)(final_angle/FRAMES);
616 for (angle=0;; angle+=delta) {
617 if (angle > final_angle)
618 angle = final_angle;
620 a = atan(ch/cw);
621 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
623 points[0].x = cx+cos(angle-a)*d;
624 points[0].y = cy+sin(angle-a)*d;
625 points[1].x = cx+cos(angle+a)*d;
626 points[1].y = cy+sin(angle+a)*d;
627 points[2].x = cx+cos(angle-a+WM_PI)*d;
628 points[2].y = cy+sin(angle-a+WM_PI)*d;
629 points[3].x = cx+cos(angle+a+WM_PI)*d;
630 points[3].y = cy+sin(angle+a+WM_PI)*d;
631 points[4].x = cx+cos(angle-a)*d;
632 points[4].y = cy+sin(angle-a)*d;
633 XGrabServer(dpy);
634 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
635 XFlush(dpy);
636 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
637 wusleep(MINIATURIZE_ANIMATION_DELAY_T);
638 #endif
640 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
641 XUngrabServer(dpy);
642 cx+=xstep;
643 cy+=ystep;
644 cw+=wstep;
645 ch+=hstep;
646 if (angle >= final_angle)
647 break;
650 XFlush(dpy);
652 #undef FRAMES
655 static void
656 animateResizeZoom(WScreen *scr, int x, int y, int w, int h,
657 int fx, int fy, int fw, int fh, int steps)
659 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
660 float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
661 float xstep, ystep, wstep, hstep;
662 int i, j;
664 xstep = (float)(fx-x)/steps;
665 ystep = (float)(fy-y)/steps;
666 wstep = (float)(fw-w)/steps;
667 hstep = (float)(fh-h)/steps;
669 for (j=0; j<FRAMES; j++) {
670 cx[j] = (float)x;
671 cy[j] = (float)y;
672 cw[j] = (float)w;
673 ch[j] = (float)h;
675 XGrabServer(dpy);
676 for (i=0; i<steps; i++) {
677 for (j=0; j<FRAMES; j++) {
678 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
679 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
681 XFlush(dpy);
682 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
683 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
684 #endif
685 for (j=0; j<FRAMES; j++) {
686 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
687 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
688 if (j<FRAMES-1) {
689 cx[j]=cx[j+1];
690 cy[j]=cy[j+1];
691 cw[j]=cw[j+1];
692 ch[j]=ch[j+1];
693 } else {
694 cx[j]+=xstep;
695 cy[j]+=ystep;
696 cw[j]+=wstep;
697 ch[j]+=hstep;
702 for (j=0; j<FRAMES; j++) {
703 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
704 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
706 XFlush(dpy);
707 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
708 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
709 #endif
710 for (j=0; j<FRAMES; j++) {
711 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
712 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
715 XUngrabServer(dpy);
717 #undef FRAMES
720 static void
721 animateResize(WScreen *scr, int x, int y, int w, int h,
722 int fx, int fy, int fw, int fh, int hiding)
724 int style = wPreferences.iconification_style; /* Catch the value */
725 int steps, k;
727 if (style == WIS_NONE)
728 return;
730 if (style == WIS_RANDOM) {
731 style = rand()%3;
734 k = (hiding ? 2 : 3);
735 switch(style) {
736 case WIS_TWIST:
737 steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
738 if (steps>0)
739 animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
740 break;
741 case WIS_FLIP:
742 steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
743 if (steps>0)
744 animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
745 break;
746 case WIS_ZOOM:
747 default:
748 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
749 if (steps>0)
750 animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
751 break;
754 #endif /* ANIMATIONS */
757 static void
758 flushExpose()
760 XEvent tmpev;
762 while (XCheckTypedEvent(dpy, Expose, &tmpev))
763 WMHandleEvent(&tmpev);
764 XSync(dpy, 0);
767 static void
768 unmapTransientsFor(WWindow *wwin)
770 WWindow *tmp;
771 XWindowAttributes attribs;
774 tmp = wwin->screen_ptr->focused_window;
775 while (tmp) {
776 /* unmap the transients for this transient */
777 if (tmp!=wwin && tmp->transient_for == wwin->client_win
778 && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
779 || tmp->flags.shaded)) {
780 unmapTransientsFor(tmp);
781 XGetWindowAttributes(dpy, tmp->client_win, &attribs);
782 tmp->flags.miniaturized=1;
783 if (!tmp->flags.shaded) {
784 tmp->flags.mapped=0;
785 XSelectInput(dpy, tmp->client_win,
786 attribs.your_event_mask & ~StructureNotifyMask);
787 XUnmapWindow(dpy, tmp->client_win);
788 XSelectInput(dpy, tmp->client_win, attribs.your_event_mask);
790 XUnmapWindow(dpy, tmp->frame->core->window);
791 if (!tmp->flags.shaded)
792 wClientSetState(tmp, IconicState, None);
793 #ifdef KWM_HINTS
794 wKWMUpdateClientStateHint(tmp, KWMIconifiedFlag);
795 wKWMSendEventMessage(tmp, WKWMRemoveWindow);
796 tmp->flags.kwm_hidden_for_modules = 1;
797 #endif
799 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
802 tmp = tmp->prev;
807 static void
808 mapTransientsFor(WWindow *wwin)
810 WWindow *tmp;
812 tmp = wwin->screen_ptr->focused_window;
813 while (tmp) {
814 /* recursively map the transients for this transient */
815 if (tmp!=wwin && tmp->transient_for == wwin->client_win
816 && /*!tmp->flags.mapped*/ tmp->flags.miniaturized
817 && tmp->icon==NULL) {
818 mapTransientsFor(tmp);
819 tmp->flags.miniaturized=0;
820 if (!tmp->flags.shaded) {
821 tmp->flags.mapped=1;
822 XMapWindow(dpy, tmp->client_win);
824 XMapWindow(dpy, tmp->frame->core->window);
825 tmp->flags.semi_focused = 0;
826 if (!tmp->flags.shaded)
827 wClientSetState(tmp, NormalState, None);
828 #ifdef KWM_HINTS
829 wKWMUpdateClientStateHint(tmp, KWMIconifiedFlag);
830 if (tmp->flags.kwm_hidden_for_modules) {
831 wKWMSendEventMessage(tmp, WKWMAddWindow);
832 tmp->flags.kwm_hidden_for_modules = 0;
834 #endif
836 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
839 tmp = tmp->prev;
844 static void
845 setupIconGrabs(WIcon *icon)
847 /* setup passive grabs on the icon */
848 XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
849 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
850 XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
851 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
852 XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
853 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
854 XSync(dpy, 0);
858 static WWindow*
859 recursiveTransientFor(WWindow *wwin)
861 int i;
863 if (!wwin)
864 return None;
866 /* hackish way to detect transient_for cycle */
867 i = wwin->screen_ptr->window_count+1;
869 while (wwin && wwin->transient_for != None && i>0) {
870 wwin = wWindowFor(wwin->transient_for);
871 i--;
873 if (i==0 && wwin) {
874 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
875 wwin->frame->title);
876 return NULL;
879 return wwin;
883 static void
884 removeIconGrabs(WIcon *icon)
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);
894 void
895 wIconifyWindow(WWindow *wwin)
897 XWindowAttributes attribs;
898 int present;
901 if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
902 /* the window doesn't exist anymore */
903 return;
906 if (wwin->flags.miniaturized)
907 return;
909 if (wwin->transient_for!=None) {
910 WWindow *owner = wWindowFor(wwin->transient_for);
912 if (owner && owner->flags.miniaturized)
913 return;
916 present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
918 /* if the window is in another workspace, simplify process */
919 if (present) {
920 /* icon creation may take a while */
921 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
922 ButtonMotionMask|ButtonReleaseMask, GrabModeAsync,
923 GrabModeAsync, None, None, CurrentTime);
926 if (!wwin->flags.icon_moved) {
927 PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y);
929 wwin->icon = wIconCreate(wwin);
931 wwin->flags.miniaturized=1;
932 wwin->flags.mapped=0;
934 /* unmap transients */
936 unmapTransientsFor(wwin);
938 if (present) {
939 #ifdef WMSOUND
940 wSoundPlay(WMSOUND_ICONIFY);
941 #endif
943 XUngrabPointer(dpy, CurrentTime);
944 /* prevent window withdrawal when getting UnmapNotify */
945 XSelectInput(dpy, wwin->client_win,
946 attribs.your_event_mask & ~StructureNotifyMask);
947 XUnmapWindow(dpy, wwin->client_win);
948 XSelectInput(dpy, wwin->client_win, attribs.your_event_mask);
949 XUnmapWindow(dpy, wwin->frame->core->window);
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 wClientSetState(wwin, IconicState, wwin->icon->icon_win);
954 flushExpose();
955 #ifdef ANIMATIONS
956 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
957 && !wPreferences.no_animations) {
958 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
959 wwin->frame->core->width, wwin->frame->core->height,
960 wwin->icon_x, wwin->icon_y,
961 wwin->icon->core->width, wwin->icon->core->height,
962 False);
964 #endif
967 wwin->flags.skip_next_animation = 0;
968 if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
969 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)
971 XMapWindow(dpy, wwin->icon->core->window);
972 AddToStackList(wwin->icon->core);
974 wLowerFrame(wwin->icon->core);
976 if (present) {
977 WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
978 setupIconGrabs(wwin->icon);
979 if ((wwin->flags.focused
980 || (owner && wwin->client_win == owner->client_win))
981 && wPreferences.focus_mode==WKF_CLICK) {
982 WWindow *tmp;
984 tmp = wwin->prev;
985 while (tmp) {
986 if (!WFLAGP(tmp, no_focusable)
987 && !(tmp->flags.hidden||tmp->flags.miniaturized))
988 break;
989 tmp = tmp->prev;
991 wSetFocusTo(wwin->screen_ptr, tmp);
992 } else if (wPreferences.focus_mode!=WKF_CLICK) {
993 wSetFocusTo(wwin->screen_ptr, NULL);
996 #ifdef ANIMATIONS
997 if (!wwin->screen_ptr->flags.startup) {
998 Window clientwin = wwin->client_win;
1000 XSync(dpy, 0);
1001 processEvents(XPending(dpy));
1003 /* the window can disappear while doing the processEvents() */
1004 if (!wWindowFor(clientwin))
1005 return;
1007 #endif
1011 if (wwin->flags.selected)
1012 wIconSelect(wwin->icon);
1014 #ifdef GNOME_STUFF
1015 wGNOMEUpdateClientStateHint(wwin, False);
1016 #endif
1017 #ifdef KWM_HINTS
1018 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1019 wKWMSendEventMessage(wwin, WKWMChangedClient);
1020 #endif
1022 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1027 void
1028 wDeiconifyWindow(WWindow *wwin)
1030 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1032 if (!wwin->flags.miniaturized)
1033 return;
1035 if (wwin->transient_for != None) {
1036 WWindow *owner = recursiveTransientFor(wwin);
1037 wDeiconifyWindow(owner);
1038 wSetFocusTo(wwin->screen_ptr, wwin);
1039 wRaiseFrame(wwin->frame->core);
1040 return;
1043 wwin->flags.miniaturized=0;
1044 if (!wwin->flags.shaded)
1045 wwin->flags.mapped=1;
1047 if (wwin->icon->selected)
1048 wIconSelect(wwin->icon);
1050 XUnmapWindow(dpy, wwin->icon->core->window);
1052 #ifdef WMSOUND
1053 wSoundPlay(WMSOUND_DEICONIFY);
1054 #endif
1056 /* if the window is in another workspace, do it silently */
1057 #ifdef ANIMATIONS
1058 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1059 && !wwin->flags.skip_next_animation) {
1060 animateResize(wwin->screen_ptr, wwin->icon_x, wwin->icon_y,
1061 wwin->icon->core->width, wwin->icon->core->height,
1062 wwin->frame_x, wwin->frame_y,
1063 wwin->frame->core->width, wwin->frame->core->height,
1064 False);
1066 #endif /* ANIMATIONS */
1067 wwin->flags.skip_next_animation = 0;
1068 XGrabServer(dpy);
1069 if (!wwin->flags.shaded) {
1070 XMapWindow(dpy, wwin->client_win);
1072 XMapWindow(dpy, wwin->frame->core->window);
1073 wRaiseFrame(wwin->frame->core);
1074 if (!wwin->flags.shaded) {
1075 wClientSetState(wwin, NormalState, None);
1077 mapTransientsFor(wwin);
1078 RemoveFromStackList(wwin->icon->core);
1079 removeIconGrabs(wwin->icon);
1080 wIconDestroy(wwin->icon);
1081 wwin->icon = NULL;
1083 XUngrabServer(dpy);
1084 if (wPreferences.focus_mode==WKF_CLICK
1085 || wPreferences.focus_mode==WKF_SLOPPY)
1086 wSetFocusTo(wwin->screen_ptr, wwin);
1088 #ifdef ANIMATIONS
1089 if (!wwin->screen_ptr->flags.startup) {
1090 Window clientwin = wwin->client_win;
1092 XSync(dpy, 0);
1093 processEvents(XPending(dpy));
1095 if (!wWindowFor(clientwin))
1096 return;
1098 #endif
1100 if (wPreferences.auto_arrange_icons) {
1101 wArrangeIcons(wwin->screen_ptr, True);
1104 #ifdef GNOME_STUFF
1105 wGNOMEUpdateClientStateHint(wwin, False);
1106 #endif
1107 #ifdef KWM_HINTS
1108 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1109 wKWMSendEventMessage(wwin, WKWMChangedClient);
1110 #endif
1112 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1117 static void
1118 hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
1120 XWindowAttributes attribs;
1123 if (wwin->flags.miniaturized) {
1124 XUnmapWindow(dpy, wwin->icon->core->window);
1125 wwin->flags.hidden = 1;
1126 wwin->icon->mapped = 0;
1127 #ifdef GNOME_STUFF
1128 wGNOMEUpdateClientStateHint(wwin, False);
1129 #endif
1131 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1133 return;
1136 if (wwin->flags.inspector_open) {
1137 WWindow *pwin = wwin->inspector->frame;
1139 XGetWindowAttributes(dpy, pwin->client_win, &attribs);
1140 pwin->flags.hidden = 1;
1141 pwin->flags.mapped = 0;
1142 /* prevent window withdrawal when getting UnmapNotify */
1143 XSelectInput(dpy, pwin->client_win,
1144 attribs.your_event_mask & ~StructureNotifyMask);
1145 XUnmapWindow(dpy, pwin->client_win);
1146 XSelectInput(dpy, pwin->client_win, attribs.your_event_mask);
1148 XUnmapWindow(dpy, pwin->frame->core->window);
1149 wClientSetState(pwin, IconicState, icon->icon_win);
1152 XGetWindowAttributes(dpy, wwin->client_win, &attribs);
1154 wwin->flags.hidden = 1;
1155 wwin->flags.mapped = 0;
1157 /* prevent window withdrawal when getting UnmapNotify */
1158 XSelectInput(dpy, wwin->client_win,
1159 attribs.your_event_mask & ~StructureNotifyMask);
1160 XUnmapWindow(dpy, wwin->client_win);
1161 XSelectInput(dpy, wwin->client_win, attribs.your_event_mask);
1163 XUnmapWindow(dpy, wwin->frame->core->window);
1164 wClientSetState(wwin, IconicState, icon->icon_win);
1165 flushExpose();
1166 #ifdef WMSOUND
1167 wSoundPlay(WMSOUND_HIDE);
1168 #endif
1169 #ifdef ANIMATIONS
1170 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1171 !wwin->flags.skip_next_animation && animate) {
1172 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1173 wwin->frame->core->width, wwin->frame->core->height,
1174 icon_x, icon_y, icon->core->width, icon->core->height,
1175 True);
1177 #endif
1178 wwin->flags.skip_next_animation = 0;
1180 #ifdef GNOME_STUFF
1181 wGNOMEUpdateClientStateHint(wwin, False);
1182 #endif
1184 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1190 void
1191 wHideOtherApplications(WWindow *awin)
1193 WWindow *wwin;
1194 WApplication *tapp;
1195 #ifdef REDUCE_APPICONS
1196 char *tinstance, *tclass;
1197 unsigned int brokenwin = 0, match = 0;
1198 #endif
1200 if (!awin)
1201 return;
1202 wwin = awin->screen_ptr->focused_window;
1204 #ifdef REDUCE_APPICONS
1205 if (awin->wm_instance == NULL || awin->wm_class == NULL)
1206 brokenwin++;
1207 #endif
1209 while (wwin) {
1210 if (wwin!=awin
1211 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1212 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1213 && !wwin->flags.internal_window
1214 && (!wwin->flags.inspector_open || wwin->inspector->frame!=awin)
1215 && !WFLAGP(wwin, no_hide_others)) {
1217 #ifdef REDUCE_APPICONS
1218 match = 0;
1219 if (!brokenwin) {
1220 if ((tinstance = wwin->wm_instance) == NULL)
1221 tinstance = "";
1222 if ((tclass = wwin->wm_class) == NULL)
1223 tclass = "";
1224 if ((strcmp(awin->wm_instance, tinstance) == 0) &&
1225 (strcmp(awin->wm_class, tclass) == 0) )
1226 match++;
1228 #endif
1230 if (wwin->main_window==None || WFLAGP(wwin, no_appicon)) {
1231 if (!WFLAGP(wwin, no_miniaturizable)) {
1232 wwin->flags.skip_next_animation = 1;
1233 wIconifyWindow(wwin);
1235 } else if (wwin->main_window!=None
1236 #ifndef REDUCE_APPICONS
1237 && awin->main_window != wwin->main_window) {
1238 #else
1239 && (awin->main_window != wwin->main_window && !match)) {
1240 #endif
1241 tapp = wApplicationOf(wwin->main_window);
1242 if (tapp) {
1243 tapp->flags.skip_next_animation = 1;
1244 wHideApplication(tapp);
1245 } else {
1246 if (!WFLAGP(wwin, no_miniaturizable)) {
1247 wwin->flags.skip_next_animation = 1;
1248 wIconifyWindow(wwin);
1253 wwin = wwin->prev;
1256 wSetFocusTo(awin->screen_ptr, awin);
1262 void
1263 wHideApplication(WApplication *wapp)
1265 #ifdef REDUCE_APPICONS
1266 WApplication *tapp;
1267 char *tinstance, *tclass;
1268 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1269 #endif
1270 WScreen *scr;
1271 WWindow *wlist;
1272 int hadfocus;
1274 if (!wapp) {
1275 wwarning("trying to hide a non grouped window");
1276 return;
1278 if (!wapp->main_window_desc) {
1279 wwarning("group leader not found for window group");
1280 return;
1282 #ifdef REDUCE_APPICONS
1283 if ((wapp->main_window_desc->wm_instance == NULL) ||
1284 (wapp->main_window_desc->wm_class == NULL))
1285 nowmhints++;
1286 #endif
1287 scr = wapp->main_window_desc->screen_ptr;
1288 hadfocus = 0;
1289 wlist = scr->focused_window;
1290 if (!wlist)
1291 return;
1293 if (wlist->main_window == wapp->main_window)
1294 wapp->last_focused = wlist;
1295 else
1296 wapp->last_focused = NULL;
1297 while (wlist) {
1298 #ifdef REDUCE_APPICONS
1299 matchwmhints = matchworkspace = 0;
1300 if (!nowmhints) {
1301 tapp = wApplicationOf(wlist->main_window);
1302 tinstance = tclass = NULL;
1303 if (tapp) {
1304 if (tapp->main_window_desc) {
1305 tinstance = tapp->main_window_desc->wm_instance;
1306 tclass = tapp->main_window_desc->wm_class;
1309 if (tapp == NULL || tinstance == NULL || tclass == NULL) {
1310 /* Should never reach here */
1311 tinstance = "";
1312 tclass = "";
1314 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0) &&
1315 (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1316 matchwmhints++;
1318 if (wlist->frame) {
1319 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1320 matchworkspace++;
1322 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1323 matchworkspace) {
1324 #ifdef I_HATE_THIS
1326 #endif
1327 #else
1328 if (wlist->main_window == wapp->main_window) {
1329 #endif
1330 if (wlist->flags.focused) {
1331 hadfocus = 1;
1333 if (wapp->app_icon)
1334 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1335 wapp->app_icon->y_pos, wlist,
1336 !wapp->flags.skip_next_animation);
1338 wlist = wlist->prev;
1341 wapp->flags.skip_next_animation = 0;
1343 if (hadfocus) {
1344 if (wPreferences.focus_mode==WKF_CLICK) {
1345 wlist = scr->focused_window;
1346 while (wlist) {
1347 if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden
1348 && (wlist->flags.mapped || wlist->flags.shaded))
1349 break;
1350 wlist = wlist->prev;
1352 wSetFocusTo(scr, wlist);
1353 } else {
1354 wSetFocusTo(scr, NULL);
1358 wapp->flags.hidden = 1;
1360 if(wPreferences.auto_arrange_icons) {
1361 wArrangeIcons(scr, True);
1368 static void
1369 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1370 int bringToCurrentWS)
1372 if (bringToCurrentWS)
1373 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1375 wwin->flags.hidden=0;
1376 wwin->flags.mapped=1;
1378 #ifdef WMSOUND
1379 wSoundPlay(WMSOUND_UNHIDE);
1380 #endif
1381 #ifdef ANIMATIONS
1382 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1383 && animate) {
1384 animateResize(wwin->screen_ptr, icon_x, icon_y,
1385 icon->core->width, icon->core->height,
1386 wwin->frame_x, wwin->frame_y,
1387 wwin->frame->core->width, wwin->frame->core->height,
1388 True);
1390 #endif
1391 wwin->flags.skip_next_animation = 0;
1392 XMapWindow(dpy, wwin->client_win);
1393 XMapWindow(dpy, wwin->frame->core->window);
1394 wClientSetState(wwin, NormalState, None);
1395 wRaiseFrame(wwin->frame->core);
1396 if (wwin->flags.inspector_open) {
1397 WWindow *pwin = wwin->inspector->frame;
1399 pwin->flags.hidden = 0;
1400 pwin->flags.mapped = 1;
1401 XMapWindow(dpy, pwin->client_win);
1402 XMapWindow(dpy, pwin->frame->core->window);
1403 wClientSetState(pwin, NormalState, None);
1406 #ifdef GNOME_STUFF
1407 wGNOMEUpdateClientStateHint(wwin, False);
1408 #endif
1410 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1415 void
1416 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1418 WScreen *scr;
1419 WWindow *wlist, *next;
1420 WWindow *focused=NULL;
1421 #ifdef REDUCE_APPICONS
1422 char *tinstance, *tclass;
1423 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1424 #endif
1426 if (!wapp) {
1427 return;
1430 #ifdef REDUCE_APPICONS
1431 if ((wapp->main_window_desc->wm_class == NULL) ||
1432 (wapp->main_window_desc->wm_instance == NULL))
1433 nowmhints++;
1434 #endif
1436 scr = wapp->main_window_desc->screen_ptr;
1437 wlist = scr->focused_window;
1438 if (!wlist) return;
1439 /* goto beginning of list */
1440 while (wlist->prev)
1441 wlist = wlist->prev;
1443 while (wlist) {
1444 next = wlist->next;
1446 #ifndef REDUCE_APPICONS
1447 if (wlist->main_window == wapp->main_window) {
1448 #else
1449 matchwmhints = matchworkspace = 0;
1450 if (!nowmhints) {
1451 if ((tinstance = wlist->wm_instance) == NULL)
1452 tinstance = "";
1453 if ((tclass = wlist->wm_class) == NULL)
1454 tclass = "";
1455 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0)
1456 && (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1457 matchwmhints++;
1459 if (wlist->frame) {
1460 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1461 matchworkspace++;
1464 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1465 matchworkspace) {
1466 #endif
1467 if (wlist->flags.focused)
1468 focused = wlist;
1469 else if (!focused || !focused->flags.focused)
1470 focused = wlist;
1472 if (wlist->flags.miniaturized && wlist->icon) {
1473 if (bringToCurrentWS || wPreferences.sticky_icons
1474 || wlist->frame->workspace == scr->current_workspace) {
1475 if (!wlist->icon->mapped) {
1476 XMapWindow(dpy, wlist->icon->core->window);
1477 wlist->icon->mapped = 1;
1479 wlist->flags.hidden = 0;
1481 UpdateSwitchMenu(scr, wlist, ACTION_CHANGE_STATE);
1483 if (wlist->frame->workspace != scr->current_workspace)
1484 wWindowChangeWorkspace(wlist, scr->current_workspace);
1486 if (miniwindows) {
1487 wDeiconifyWindow(wlist);
1489 } else if (wlist->flags.hidden) {
1490 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1491 wapp->app_icon->y_pos, wlist,
1492 !wapp->flags.skip_next_animation,
1493 bringToCurrentWS);
1494 } else {
1495 if (bringToCurrentWS
1496 && wlist->frame->workspace != scr->current_workspace) {
1497 wWindowChangeWorkspace(wlist, scr->current_workspace);
1499 wRaiseFrame(wlist->frame->core);
1502 wlist = next;
1505 wapp->flags.skip_next_animation = 0;
1506 wapp->flags.hidden = 0;
1508 if (focused)
1509 wSetFocusTo(scr, focused);
1510 else if (wapp->last_focused && wapp->last_focused->flags.mapped)
1511 wSetFocusTo(scr, wapp->last_focused);
1512 wapp->last_focused = NULL;
1513 if (wPreferences.auto_arrange_icons) {
1514 wArrangeIcons(scr, True);
1520 void
1521 wShowAllWindows(WScreen *scr)
1523 WWindow *wwin, *old_foc;
1524 WApplication *wapp;
1526 old_foc = wwin = scr->focused_window;
1527 while (wwin) {
1528 if (!wwin->flags.internal_window &&
1529 (scr->current_workspace == wwin->frame->workspace
1530 || IS_OMNIPRESENT(wwin))) {
1531 if (wwin->flags.miniaturized) {
1532 wwin->flags.skip_next_animation = 1;
1533 wDeiconifyWindow(wwin);
1534 } else if (wwin->flags.hidden) {
1535 wapp = wApplicationOf(wwin->main_window);
1536 if (wapp) {
1537 wUnhideApplication(wapp, False, False);
1538 } else {
1539 wwin->flags.skip_next_animation = 1;
1540 wDeiconifyWindow(wwin);
1544 wwin = wwin->prev;
1546 wSetFocusTo(scr, old_foc);
1547 /*wRaiseFrame(old_foc->frame->core);*/
1551 void
1552 wRefreshDesktop(WScreen *scr)
1554 Window win;
1555 XSetWindowAttributes attr;
1557 attr.backing_store = NotUseful;
1558 attr.save_under = False;
1559 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1560 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1561 (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
1562 &attr);
1563 XMapRaised(dpy, win);
1564 XDestroyWindow(dpy, win);
1565 XFlush(dpy);
1569 void
1570 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1572 WWindow *wwin;
1573 WAppIcon *aicon;
1574 int pf; /* primary axis */
1575 int sf; /* secondary axis */
1576 int fullW;
1577 int fullH;
1578 int pi, si;
1579 int sx1, sx2, sy1, sy2; /* screen boundary */
1580 int sw, sh;
1581 int xo, yo;
1582 int xs, ys;
1583 int isize = wPreferences.icon_size;
1586 * Find out screen boundaries.
1588 sx1 = 0;
1589 sy1 = 0;
1590 sx2 = scr->scr_width;
1591 sy2 = scr->scr_height;
1592 if (scr->dock) {
1593 if (scr->dock->on_right_side)
1594 sx2 -= isize + DOCK_EXTRA_SPACE;
1595 else
1596 sx1 += isize + DOCK_EXTRA_SPACE;
1599 sw = isize * (scr->scr_width/isize);
1600 sh = isize * (scr->scr_height/isize);
1601 fullW = (sx2-sx1)/isize;
1602 fullH = (sy2-sy1)/isize;
1604 /* icon yard boundaries */
1605 if (wPreferences.icon_yard & IY_VERT) {
1606 pf = fullH;
1607 sf = fullW;
1608 } else {
1609 pf = fullW;
1610 sf = fullH;
1612 if (wPreferences.icon_yard & IY_RIGHT) {
1613 xo = sx2 - isize;
1614 xs = -1;
1615 } else {
1616 xo = sx1;
1617 xs = 1;
1619 if (wPreferences.icon_yard & IY_TOP) {
1620 yo = sy1;
1621 ys = 1;
1622 } else {
1623 yo = sy2 - isize;
1624 ys = -1;
1627 /* arrange icons putting the most recently focused window
1628 * as the last icon */
1629 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1630 : xo + xs*(pi*isize))
1631 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1632 : yo + ys*(si*isize))
1634 /* arrange application icons */
1635 aicon = scr->app_icon_list;
1636 /* reverse them to avoid unnecessarily sliding of icons */
1637 while (aicon && aicon->next)
1638 aicon = aicon->next;
1640 pi = 0;
1641 si = 0;
1642 while (aicon) {
1643 if (!aicon->docked) {
1644 if (aicon->x_pos != X || aicon->y_pos != Y) {
1645 #ifdef ANIMATIONS
1646 if (!wPreferences.no_animations) {
1647 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1648 X, Y);
1650 #endif /* ANIMATIONS */
1652 wAppIconMove(aicon, X, Y);
1653 pi++;
1655 /* we reversed the order so we use prev */
1656 aicon = aicon->prev;
1657 if (pi >= pf) {
1658 pi=0;
1659 si++;
1663 /* arrange miniwindows */
1665 wwin = scr->focused_window;
1666 /* reverse them to avoid unnecessarily shuffling */
1667 while (wwin && wwin->prev)
1668 wwin = wwin->prev;
1670 while (wwin) {
1671 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1672 (wwin->frame->workspace==scr->current_workspace ||
1673 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1675 if (arrangeAll || !wwin->flags.icon_moved) {
1676 if (wwin->icon_x != X || wwin->icon_y != Y) {
1677 #ifdef ANIMATIONS
1678 if (wPreferences.no_animations) {
1679 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1680 } else {
1681 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1682 wwin->icon_y, X, Y);
1684 #else
1685 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1686 #endif /* ANIMATIONS */
1688 wwin->icon_x = X;
1689 wwin->icon_y = Y;
1690 wwin->flags.icon_moved = 0;
1691 pi++;
1694 /* we reversed the order, so we use next */
1695 wwin = wwin->next;
1696 if (pi >= pf) {
1697 pi=0;
1698 si++;
1704 void
1705 wSelectWindow(WWindow *wwin, Bool flag)
1707 WScreen *scr = wwin->screen_ptr;
1708 if (flag) {
1709 wwin->flags.selected = 1;
1710 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1711 scr->selected_windows = list_cons(wwin, scr->selected_windows);
1712 } else {
1713 wwin->flags.selected = 0;
1714 XSetWindowBorder(dpy, wwin->frame->core->window,
1715 scr->frame_border_pixel);
1716 scr->selected_windows = list_remove_elem(scr->selected_windows, wwin);
1721 void
1722 wMakeWindowVisible(WWindow *wwin)
1724 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1726 if (wwin->flags.shaded) {
1727 wUnshadeWindow(wwin);
1729 if (wwin->flags.hidden) {
1730 wUnhideApplication(wApplicationOf(wwin->main_window), False, False);
1731 } else if (wwin->flags.miniaturized) {
1732 wDeiconifyWindow(wwin);
1733 } else {
1734 wSetFocusTo(wwin->screen_ptr, wwin);
1735 wRaiseFrame(wwin->frame->core);