added patch with bugfixes for wings/textfield/panel exit with escape/bag etc
[wmaker-crm.git] / src / actions.c
blob86fea26dec892da73720b70d13a531390902d533
1 /* action.c- misc. window commands (miniaturize, hide etc.)
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997, 1998, 1999 Alfredo K. Kojima
6 * Copyright (c) 1998 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.
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.
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.
24 #include "wconfig.h"
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <math.h>
33 #include <time.h>
35 #include "WindowMaker.h"
36 #include "wcore.h"
37 #include "framewin.h"
38 #include "window.h"
39 #include "client.h"
40 #include "icon.h"
41 #include "funcs.h"
42 #include "application.h"
43 #include "actions.h"
44 #include "stacking.h"
45 #include "appicon.h"
46 #include "dock.h"
47 #include "appmenu.h"
48 #include "winspector.h"
49 #include "workspace.h"
51 #ifdef GNOME_STUFF
52 # include "gnome.h"
53 #endif
54 #ifdef KWM_HINTS
55 # include "kwm.h"
56 #endif
58 #ifdef WMSOUND
59 #include "wmsound.h"
60 #endif
63 /****** Global Variables ******/
64 extern Time LastTimestamp;
65 extern Time LastFocusChange;
67 extern Cursor wCursor[WCUR_LAST];
69 extern WPreferences wPreferences;
71 extern Atom _XA_WM_TAKE_FOCUS;
74 /******* Local Variables *******/
75 static struct {
76 int steps;
77 int delay;
78 } shadePars[5] = {
79 {SHADE_STEPS_UF, SHADE_DELAY_UF},
80 {SHADE_STEPS_F, SHADE_DELAY_F},
81 {SHADE_STEPS_M, SHADE_DELAY_M},
82 {SHADE_STEPS_S, SHADE_DELAY_S},
83 {SHADE_STEPS_U, SHADE_DELAY_U}};
85 #define SHADE_STEPS shadePars[(int)wPreferences.shade_speed].steps
86 #define SHADE_DELAY shadePars[(int)wPreferences.shade_speed].delay
89 static int ignoreTimestamp=0;
92 #ifdef ANIMATIONS
93 static void
94 processEvents(int event_count)
96 XEvent event;
99 * This is a hack. When animations are enabled, processing of
100 * events ocurred during a animation are delayed until it's end.
101 * Calls that consider the TimeStamp, like XSetInputFocus(), will
102 * fail because the TimeStamp is too old. Then, for example, if
103 * the user changes window focus while a miniaturize animation is
104 * in course, the window will not get focus properly after the end
105 * of the animation. This tries to workaround it by passing CurrentTime
106 * as the TimeStamp for XSetInputFocus() for all events ocurred during
107 * the animation.
109 ignoreTimestamp=1;
110 while (XPending(dpy) && event_count--) {
111 WMNextEvent(dpy, &event);
112 WMHandleEvent(&event);
114 ignoreTimestamp=0;
116 #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 static WScreen *old_scr=NULL;
138 WWindow *old_focused;
139 WWindow *focused=scr->focused_window;
140 int timestamp=LastTimestamp;
141 WApplication *oapp=NULL, *napp=NULL;
142 int wasfocused;
144 if (!old_scr)
145 old_scr=scr;
146 old_focused=old_scr->focused_window;
148 LastFocusChange = timestamp;
151 * This is a hack, because XSetInputFocus() should have a proper
152 * timestamp instead of CurrentTime but it seems that some times
153 * clients will not receive focus properly that way.
154 if (ignoreTimestamp)
156 timestamp = CurrentTime;
158 if (old_focused)
159 oapp = wApplicationOf(old_focused->main_window);
161 if (wwin == NULL) {
162 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
163 if (old_focused) {
164 wWindowUnfocus(old_focused);
166 if (oapp) {
167 wAppMenuUnmap(oapp->menu);
168 #ifdef NEWAPPICON
169 wApplicationDeactivate(oapp);
170 #endif
172 #ifdef KWM_HINTS
173 wKWMUpdateActiveWindowHint(scr);
174 wKWMSendEventMessage(NULL, WKWMFocusWindow);
175 #endif
176 return;
177 } else if(old_scr != scr && old_focused) {
178 wWindowUnfocus(old_focused);
181 wasfocused = wwin->flags.focused;
182 napp = wApplicationOf(wwin->main_window);
184 /* remember last workspace where the app has been */
185 if (napp)
186 napp->last_workspace = wwin->screen_ptr->current_workspace;
188 if (wwin->flags.mapped && !WFLAGP(wwin, no_focusable)) {
189 /* install colormap if colormap mode is lock mode */
190 if (wPreferences.colormap_mode==WKF_CLICK)
191 wColormapInstallForWindow(scr, wwin);
193 /* set input focus */
194 switch (wwin->focus_mode) {
195 case WFM_NO_INPUT:
196 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
197 break;
199 case WFM_PASSIVE:
200 case WFM_LOCALLY_ACTIVE:
201 XSetInputFocus(dpy, wwin->client_win, RevertToParent, timestamp);
202 break;
204 case WFM_GLOBALLY_ACTIVE:
205 break;
207 XFlush(dpy);
208 if (wwin->protocols.TAKE_FOCUS) {
209 wClientSendProtocol(wwin, _XA_WM_TAKE_FOCUS, timestamp);
211 XSync(dpy, False);
212 } else {
213 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
215 if (WFLAGP(wwin, no_focusable))
216 return;
218 /* if this is not the focused window focus it */
219 if (focused!=wwin) {
220 /* change the focus window list order */
221 if (wwin->prev)
222 wwin->prev->next = wwin->next;
224 if (wwin->next)
225 wwin->next->prev = wwin->prev;
227 wwin->prev = focused;
228 focused->next = wwin;
229 wwin->next = NULL;
230 scr->focused_window = wwin;
232 if (oapp && oapp != napp) {
233 wAppMenuUnmap(oapp->menu);
234 #ifdef NEWAPPICON
235 wApplicationDeactivate(oapp);
236 #endif
240 wWindowFocus(wwin, focused);
242 if (napp && !wasfocused) {
243 #ifdef USER_MENU
244 wUserMenuRefreshInstances(napp->menu, wwin);
245 #endif /* USER_MENU */
247 if (wwin->flags.mapped)
248 wAppMenuMap(napp->menu, wwin);
249 #ifdef NEWAPPICON
250 wApplicationActivate(napp);
251 #endif
253 #ifdef KWM_HINTS
254 wKWMUpdateActiveWindowHint(scr);
255 wKWMSendEventMessage(wwin, WKWMFocusWindow);
256 #endif
257 XFlush(dpy);
258 old_scr=scr;
262 void
263 wShadeWindow(WWindow *wwin)
265 time_t time0 = time(NULL);
266 #ifdef ANIMATIONS
267 int y, s, w, h;
268 #endif
270 if (wwin->flags.shaded)
271 return;
273 XLowerWindow(dpy, wwin->client_win);
275 #ifdef WMSOUND
276 wSoundPlay(WMSOUND_SHADE);
277 #endif
279 #ifdef ANIMATIONS
280 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
281 && !wPreferences.no_animations) {
282 /* do the shading animation */
283 h = wwin->frame->core->height;
284 s = h/SHADE_STEPS;
285 if (s < 1) s=1;
286 w = wwin->frame->core->width;
287 y = wwin->frame->top_width;
288 while (h>wwin->frame->top_width+1) {
289 XMoveWindow(dpy, wwin->client_win, 0, y);
290 XResizeWindow(dpy, wwin->frame->core->window, w, h);
291 XFlush(dpy);
293 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
294 break;
296 if (SHADE_DELAY > 0)
297 wusleep(SHADE_DELAY*1000L);
298 h-=s;
299 y-=s;
301 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
303 #endif /* ANIMATIONS */
305 wwin->flags.skip_next_animation = 0;
306 wwin->flags.shaded = 1;
307 wwin->flags.mapped = 0;
308 /* prevent window withdrawal when getting UnmapNotify */
309 XSelectInput(dpy, wwin->client_win,
310 wwin->event_mask & ~StructureNotifyMask);
311 XUnmapWindow(dpy, wwin->client_win);
312 XSelectInput(dpy, wwin->client_win, wwin->event_mask);
314 /* for the client it's just like iconification */
315 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
316 wwin->frame->top_width - 1);
318 wwin->client.y = wwin->frame_y - wwin->client.height
319 + wwin->frame->top_width;
320 wWindowSynthConfigureNotify(wwin);
323 wClientSetState(wwin, IconicState, None);
326 #ifdef GNOME_STUFF
327 wGNOMEUpdateClientStateHint(wwin, False);
328 #endif
329 #ifdef KWM_HINTS
330 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
331 wKWMSendEventMessage(wwin, WKWMChangedClient);
332 #endif
333 /* update window list to reflect shaded state */
334 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
336 #ifdef ANIMATIONS
337 if (!wwin->screen_ptr->flags.startup) {
338 /* Look at processEvents() for reason of this code. */
339 XSync(dpy, 0);
340 processEvents(XPending(dpy));
342 #endif
346 void
347 wUnshadeWindow(WWindow *wwin)
349 time_t time0 = time(NULL);
350 #ifdef ANIMATIONS
351 int y, s, w, h;
352 #endif /* ANIMATIONS */
355 if (!wwin->flags.shaded)
356 return;
358 wwin->flags.shaded = 0;
359 wwin->flags.mapped = 1;
360 XMapWindow(dpy, wwin->client_win);
362 #ifdef WMSOUND
363 wSoundPlay(WMSOUND_UNSHADE);
364 #endif
366 #ifdef ANIMATIONS
367 if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) {
368 /* do the shading animation */
369 h = wwin->frame->top_width + wwin->frame->bottom_width;
370 y = wwin->frame->top_width - wwin->client.height;
371 s = abs(y)/SHADE_STEPS;
372 if (s<1) s=1;
373 w = wwin->frame->core->width;
374 XMoveWindow(dpy, wwin->client_win, 0, y);
375 if (s>0) {
376 while (h < wwin->client.height + wwin->frame->top_width
377 + wwin->frame->bottom_width) {
378 XResizeWindow(dpy, wwin->frame->core->window, w, h);
379 XMoveWindow(dpy, wwin->client_win, 0, y);
380 XSync(dpy, 0);
381 if (SHADE_DELAY > 0)
382 wusleep(SHADE_DELAY*2000L/3);
383 h+=s;
384 y+=s;
386 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
387 break;
390 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
392 #endif /* ANIMATIONS */
394 wwin->flags.skip_next_animation = 0;
395 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
396 wwin->frame->top_width + wwin->client.height
397 + wwin->frame->bottom_width);
399 wwin->client.y = wwin->frame_y + wwin->frame->top_width;
400 wWindowSynthConfigureNotify(wwin);
403 wClientSetState(wwin, NormalState, None);
405 /* if the window is focused, set the focus again as it was disabled during
406 * shading */
407 if (wwin->flags.focused)
408 wSetFocusTo(wwin->screen_ptr, wwin);
410 #ifdef GNOME_STUFF
411 wGNOMEUpdateClientStateHint(wwin, False);
412 #endif
413 #ifdef KWM_HINTS
414 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
415 wKWMSendEventMessage(wwin, WKWMChangedClient);
416 #endif
418 /* update window list to reflect unshaded state */
419 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
424 void
425 wMaximizeWindow(WWindow *wwin, int directions)
427 int new_width, new_height, new_x, new_y;
428 WArea usableArea = wwin->screen_ptr->totalUsableArea;
431 if (WFLAGP(wwin, no_resizable))
432 return;
435 if (WFLAGP(wwin, full_maximize)) {
436 usableArea.x1 = 0;
437 usableArea.y1 = 0;
438 usableArea.x2 = wwin->screen_ptr->scr_width;
439 usableArea.y2 = wwin->screen_ptr->scr_height;
442 if (wwin->flags.shaded) {
443 wwin->flags.skip_next_animation = 1;
444 wUnshadeWindow(wwin);
446 wwin->flags.maximized = directions;
447 wwin->old_geometry.width = wwin->client.width;
448 wwin->old_geometry.height = wwin->client.height;
449 wwin->old_geometry.x = wwin->frame_x;
450 wwin->old_geometry.y = wwin->frame_y;
452 #ifdef KWM_HINTS
453 wKWMUpdateClientGeometryRestore(wwin);
454 #endif
456 if (directions & MAX_HORIZONTAL) {
458 new_width = (usableArea.x2-usableArea.x1)-FRAME_BORDER_WIDTH*2;
459 new_x = usableArea.x1;
461 } else {
463 new_x = wwin->frame_x;
464 new_width = wwin->frame->core->width;
468 if (directions & MAX_VERTICAL) {
470 new_height = (usableArea.y2-usableArea.y1)-FRAME_BORDER_WIDTH*2;
471 new_y = usableArea.y1;
472 if (WFLAGP(wwin, full_maximize))
473 new_y -= wwin->frame->top_width;
475 } else {
477 new_y = wwin->frame_y;
478 new_height = wwin->frame->core->height;
482 if (!WFLAGP(wwin, full_maximize)) {
483 new_height -= wwin->frame->top_width+wwin->frame->bottom_width;
486 wWindowConstrainSize(wwin, &new_width, &new_height);
487 wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
489 #ifdef GNOME_STUFF
490 wGNOMEUpdateClientStateHint(wwin, False);
491 #endif
492 #ifdef KWM_HINTS
493 wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
494 wKWMSendEventMessage(wwin, WKWMChangedClient);
495 #endif
497 #ifdef WMSOUND
498 wSoundPlay(WMSOUND_MAXIMIZE);
499 #endif
503 void
504 wUnmaximizeWindow(WWindow *wwin)
506 int restore_x, restore_y;
508 if (!wwin->flags.maximized)
509 return;
511 if (wwin->flags.shaded) {
512 wwin->flags.skip_next_animation = 1;
513 wUnshadeWindow(wwin);
515 restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ?
516 wwin->old_geometry.x : wwin->frame_x;
517 restore_y = (wwin->flags.maximized & MAX_VERTICAL) ?
518 wwin->old_geometry.y : wwin->frame_y;
519 wwin->flags.maximized = 0;
520 wWindowConfigure(wwin, restore_x, restore_y,
521 wwin->old_geometry.width, wwin->old_geometry.height);
523 #ifdef GNOME_STUFF
524 wGNOMEUpdateClientStateHint(wwin, False);
525 #endif
526 #ifdef KWM_HINTS
527 wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
528 wKWMSendEventMessage(wwin, WKWMChangedClient);
529 #endif
531 #ifdef WMSOUND
532 wSoundPlay(WMSOUND_UNMAXIMIZE);
533 #endif
536 #ifdef ANIMATIONS
537 static void
538 animateResizeFlip(WScreen *scr, int x, int y, int w, int h,
539 int fx, int fy, int fw, int fh, int steps)
541 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
542 float cx, cy, cw, ch;
543 float xstep, ystep, wstep, hstep;
544 XPoint points[5];
545 float dx, dch, midy;
546 float angle, final_angle, delta;
548 xstep = (float)(fx-x)/steps;
549 ystep = (float)(fy-y)/steps;
550 wstep = (float)(fw-w)/steps;
551 hstep = (float)(fh-h)/steps;
553 cx = (float)x;
554 cy = (float)y;
555 cw = (float)w;
556 ch = (float)h;
558 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F;
559 delta = (float)(final_angle/FRAMES);
560 for (angle=0;; angle+=delta) {
561 if (angle > final_angle)
562 angle = final_angle;
564 dx = (cw/10) - ((cw/5) * sin(angle));
565 dch = (ch/2) * cos(angle);
566 midy = cy + (ch/2);
568 points[0].x = cx + dx; points[0].y = midy - dch;
569 points[1].x = cx + cw - dx; points[1].y = points[0].y;
570 points[2].x = cx + cw + dx; points[2].y = midy + dch;
571 points[3].x = cx - dx; points[3].y = points[2].y;
572 points[4].x = points[0].x; points[4].y = points[0].y;
574 XGrabServer(dpy);
575 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
576 XFlush(dpy);
577 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
578 wusleep(MINIATURIZE_ANIMATION_DELAY_F);
579 #endif
581 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
582 XUngrabServer(dpy);
583 cx+=xstep;
584 cy+=ystep;
585 cw+=wstep;
586 ch+=hstep;
587 if (angle >= final_angle)
588 break;
591 XFlush(dpy);
593 #undef FRAMES
596 static void
597 animateResizeTwist(WScreen *scr, int x, int y, int w, int h,
598 int fx, int fy, int fw, int fh, int steps)
600 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
601 float cx, cy, cw, ch;
602 float xstep, ystep, wstep, hstep;
603 XPoint points[5];
604 float angle, final_angle, a, d, delta;
606 x += w/2;
607 y += h/2;
608 fx += fw/2;
609 fy += fh/2;
611 xstep = (float)(fx-x)/steps;
612 ystep = (float)(fy-y)/steps;
613 wstep = (float)(fw-w)/steps;
614 hstep = (float)(fh-h)/steps;
616 cx = (float)x;
617 cy = (float)y;
618 cw = (float)w;
619 ch = (float)h;
621 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T;
622 delta = (float)(final_angle/FRAMES);
623 for (angle=0;; angle+=delta) {
624 if (angle > final_angle)
625 angle = final_angle;
627 a = atan(ch/cw);
628 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
630 points[0].x = cx+cos(angle-a)*d;
631 points[0].y = cy+sin(angle-a)*d;
632 points[1].x = cx+cos(angle+a)*d;
633 points[1].y = cy+sin(angle+a)*d;
634 points[2].x = cx+cos(angle-a+WM_PI)*d;
635 points[2].y = cy+sin(angle-a+WM_PI)*d;
636 points[3].x = cx+cos(angle+a+WM_PI)*d;
637 points[3].y = cy+sin(angle+a+WM_PI)*d;
638 points[4].x = cx+cos(angle-a)*d;
639 points[4].y = cy+sin(angle-a)*d;
640 XGrabServer(dpy);
641 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
642 XFlush(dpy);
643 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
644 wusleep(MINIATURIZE_ANIMATION_DELAY_T);
645 #endif
647 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
648 XUngrabServer(dpy);
649 cx+=xstep;
650 cy+=ystep;
651 cw+=wstep;
652 ch+=hstep;
653 if (angle >= final_angle)
654 break;
657 XFlush(dpy);
659 #undef FRAMES
662 static void
663 animateResizeZoom(WScreen *scr, int x, int y, int w, int h,
664 int fx, int fy, int fw, int fh, int steps)
666 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
667 float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
668 float xstep, ystep, wstep, hstep;
669 int i, j;
671 xstep = (float)(fx-x)/steps;
672 ystep = (float)(fy-y)/steps;
673 wstep = (float)(fw-w)/steps;
674 hstep = (float)(fh-h)/steps;
676 for (j=0; j<FRAMES; j++) {
677 cx[j] = (float)x;
678 cy[j] = (float)y;
679 cw[j] = (float)w;
680 ch[j] = (float)h;
682 XGrabServer(dpy);
683 for (i=0; i<steps; i++) {
684 for (j=0; j<FRAMES; j++) {
685 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
686 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
688 XFlush(dpy);
689 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
690 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
691 #endif
692 for (j=0; j<FRAMES; j++) {
693 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
694 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
695 if (j<FRAMES-1) {
696 cx[j]=cx[j+1];
697 cy[j]=cy[j+1];
698 cw[j]=cw[j+1];
699 ch[j]=ch[j+1];
700 } else {
701 cx[j]+=xstep;
702 cy[j]+=ystep;
703 cw[j]+=wstep;
704 ch[j]+=hstep;
709 for (j=0; j<FRAMES; j++) {
710 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
711 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
713 XFlush(dpy);
714 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
715 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
716 #endif
717 for (j=0; j<FRAMES; j++) {
718 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
719 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
722 XUngrabServer(dpy);
724 #undef FRAMES
727 static void
728 animateResize(WScreen *scr, int x, int y, int w, int h,
729 int fx, int fy, int fw, int fh, int hiding)
731 int style = wPreferences.iconification_style; /* Catch the value */
732 int steps, k;
734 if (style == WIS_NONE)
735 return;
737 if (style == WIS_RANDOM) {
738 style = rand()%3;
741 k = (hiding ? 2 : 3);
742 switch(style) {
743 case WIS_TWIST:
744 steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
745 if (steps>0)
746 animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
747 break;
748 case WIS_FLIP:
749 steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
750 if (steps>0)
751 animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
752 break;
753 case WIS_ZOOM:
754 default:
755 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
756 if (steps>0)
757 animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
758 break;
761 #endif /* ANIMATIONS */
764 static void
765 flushExpose()
767 XEvent tmpev;
769 while (XCheckTypedEvent(dpy, Expose, &tmpev))
770 WMHandleEvent(&tmpev);
771 XSync(dpy, 0);
774 static void
775 unmapTransientsFor(WWindow *wwin)
777 WWindow *tmp;
780 tmp = wwin->screen_ptr->focused_window;
781 while (tmp) {
782 /* unmap the transients for this transient */
783 if (tmp!=wwin && tmp->transient_for == wwin->client_win
784 && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
785 || tmp->flags.shaded)) {
786 unmapTransientsFor(tmp);
787 tmp->flags.miniaturized = 1;
788 if (!tmp->flags.shaded) {
789 wWindowUnmap(tmp);
790 } else {
791 XUnmapWindow(dpy, tmp->frame->core->window);
794 if (!tmp->flags.shaded)
796 wClientSetState(tmp, IconicState, None);
797 #ifdef KWM_HINTS
798 wKWMUpdateClientStateHint(tmp, KWMIconifiedFlag);
799 wKWMSendEventMessage(tmp, WKWMRemoveWindow);
800 tmp->flags.kwm_hidden_for_modules = 1;
801 #endif
803 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
806 tmp = tmp->prev;
811 static void
812 mapTransientsFor(WWindow *wwin)
814 WWindow *tmp;
816 tmp = wwin->screen_ptr->focused_window;
817 while (tmp) {
818 /* recursively map the transients for this transient */
819 if (tmp!=wwin && tmp->transient_for == wwin->client_win
820 && /*!tmp->flags.mapped*/ tmp->flags.miniaturized
821 && tmp->icon==NULL) {
822 mapTransientsFor(tmp);
823 tmp->flags.miniaturized = 0;
824 if (!tmp->flags.shaded) {
825 wWindowMap(tmp);
826 } else {
827 XMapWindow(dpy, tmp->frame->core->window);
829 tmp->flags.semi_focused = 0;
831 if (!tmp->flags.shaded)
833 wClientSetState(tmp, NormalState, None);
834 #ifdef KWM_HINTS
835 wKWMUpdateClientStateHint(tmp, KWMIconifiedFlag);
836 if (tmp->flags.kwm_hidden_for_modules) {
837 wKWMSendEventMessage(tmp, WKWMAddWindow);
838 tmp->flags.kwm_hidden_for_modules = 0;
840 #endif
842 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
845 tmp = tmp->prev;
849 #if 0
850 static void
851 setupIconGrabs(WIcon *icon)
853 /* setup passive grabs on the icon */
854 XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
855 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
856 XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
857 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
858 XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
859 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
860 XSync(dpy, 0);
862 #endif
864 static WWindow*
865 recursiveTransientFor(WWindow *wwin)
867 int i;
869 if (!wwin)
870 return None;
872 /* hackish way to detect transient_for cycle */
873 i = wwin->screen_ptr->window_count+1;
875 while (wwin && wwin->transient_for != None && i>0) {
876 wwin = wWindowFor(wwin->transient_for);
877 i--;
879 if (i==0 && wwin) {
880 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
881 wwin->frame->title);
882 return NULL;
885 return wwin;
888 #if 0
889 static void
890 removeIconGrabs(WIcon *icon)
892 /* remove passive grabs on the icon */
893 XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
894 XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
895 XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);
896 XSync(dpy, 0);
898 #endif
901 void
902 wIconifyWindow(WWindow *wwin)
904 XWindowAttributes attribs;
905 int present;
908 if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
909 /* the window doesn't exist anymore */
910 return;
913 if (wwin->flags.miniaturized) {
914 return;
918 if (wwin->transient_for!=None) {
919 WWindow *owner = wWindowFor(wwin->transient_for);
921 if (owner && owner->flags.miniaturized)
922 return;
925 present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
927 /* if the window is in another workspace, simplify process */
928 if (present) {
929 /* icon creation may take a while */
930 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
931 ButtonMotionMask|ButtonReleaseMask, GrabModeAsync,
932 GrabModeAsync, None, None, CurrentTime);
935 if (!wPreferences.disable_miniwindows) {
936 if (!wwin->flags.icon_moved) {
937 PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y);
939 wwin->icon = wIconCreate(wwin);
941 wwin->icon->mapped = 1;
944 wwin->flags.miniaturized = 1;
945 wwin->flags.mapped = 0;
947 /* unmap transients */
949 unmapTransientsFor(wwin);
951 if (present) {
952 #ifdef WMSOUND
953 wSoundPlay(WMSOUND_ICONIFY);
954 #endif
956 XUngrabPointer(dpy, CurrentTime);
957 wWindowUnmap(wwin);
958 /* let all Expose events arrive so that we can repaint
959 * something before the animation starts (and the server is grabbed) */
960 XSync(dpy, 0);
962 if (wPreferences.disable_miniwindows)
963 wClientSetState(wwin, IconicState, None);
964 else
965 wClientSetState(wwin, IconicState, wwin->icon->icon_win);
967 flushExpose();
968 #ifdef ANIMATIONS
969 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
970 && !wPreferences.no_animations) {
971 int ix, iy, iw, ih;
973 if (!wPreferences.disable_miniwindows) {
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 KWM_HINTS
980 WArea area;
982 if (wKWMGetIconGeometry(wwin, &area)) {
983 ix = area.x1;
984 iy = area.y1;
985 iw = area.x2 - ix;
986 ih = area.y2 - iy;
987 } else
988 #endif /* KWM_HINTS */
990 ix = 0;
991 iy = 0;
992 iw = wwin->screen_ptr->scr_width;
993 ih = wwin->screen_ptr->scr_height;
996 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
997 wwin->frame->core->width, wwin->frame->core->height,
998 ix, iy, iw, ih, False);
1000 #endif
1003 wwin->flags.skip_next_animation = 0;
1005 if (!wPreferences.disable_miniwindows) {
1007 if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
1008 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)
1010 XMapWindow(dpy, wwin->icon->core->window);
1012 AddToStackList(wwin->icon->core);
1014 wLowerFrame(wwin->icon->core);
1017 if (present) {
1018 WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
1021 * It doesn't seem to be working and causes button event hangup
1022 * when deiconifying a transient window.
1023 setupIconGrabs(wwin->icon);
1025 if ((wwin->flags.focused
1026 || (owner && wwin->client_win == owner->client_win))
1027 && wPreferences.focus_mode==WKF_CLICK) {
1028 WWindow *tmp;
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;
1038 wSetFocusTo(wwin->screen_ptr, tmp);
1039 } else if (wPreferences.focus_mode!=WKF_CLICK) {
1040 wSetFocusTo(wwin->screen_ptr, NULL);
1043 #ifdef ANIMATIONS
1044 if (!wwin->screen_ptr->flags.startup) {
1045 Window clientwin = wwin->client_win;
1047 XSync(dpy, 0);
1048 processEvents(XPending(dpy));
1050 /* the window can disappear while doing the processEvents() */
1051 if (!wWindowFor(clientwin))
1052 return;
1054 #endif
1058 if (wwin->flags.selected && !wPreferences.disable_miniwindows)
1059 wIconSelect(wwin->icon);
1061 #ifdef GNOME_STUFF
1062 wGNOMEUpdateClientStateHint(wwin, False);
1063 #endif
1064 #ifdef KWM_HINTS
1065 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1066 wKWMSendEventMessage(wwin, WKWMChangedClient);
1067 #endif
1069 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1075 void
1076 wDeiconifyWindow(WWindow *wwin)
1078 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1080 if (!wwin->flags.miniaturized)
1081 return;
1083 if (wwin->transient_for != None
1084 && wwin->transient_for != wwin->screen_ptr->root_win) {
1085 WWindow *owner = recursiveTransientFor(wwin);
1087 if (owner && owner->flags.miniaturized) {
1088 wDeiconifyWindow(owner);
1089 wSetFocusTo(wwin->screen_ptr, wwin);
1090 wRaiseFrame(wwin->frame->core);
1091 return;
1095 wwin->flags.miniaturized = 0;
1096 if (!wwin->flags.shaded)
1097 wwin->flags.mapped = 1;
1099 if (!wPreferences.disable_miniwindows) {
1100 if (wwin->icon->selected)
1101 wIconSelect(wwin->icon);
1103 XUnmapWindow(dpy, wwin->icon->core->window);
1106 #ifdef WMSOUND
1107 wSoundPlay(WMSOUND_DEICONIFY);
1108 #endif
1110 /* if the window is in another workspace, do it silently */
1111 #ifdef ANIMATIONS
1112 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1113 && !wwin->flags.skip_next_animation) {
1114 int ix, iy, iw, ih;
1116 if (!wPreferences.disable_miniwindows) {
1117 ix = wwin->icon_x;
1118 iy = wwin->icon_y;
1119 iw = wwin->icon->core->width;
1120 ih = wwin->icon->core->height;
1121 } else {
1122 #ifdef KWM_HINTS
1123 WArea area;
1125 if (wKWMGetIconGeometry(wwin, &area)) {
1126 ix = area.x1;
1127 iy = area.y1;
1128 iw = area.x2 - ix;
1129 ih = area.y2 - iy;
1130 } else
1131 #endif /* KWM_HINTS */
1133 ix = 0;
1134 iy = 0;
1135 iw = wwin->screen_ptr->scr_width;
1136 ih = wwin->screen_ptr->scr_height;
1139 animateResize(wwin->screen_ptr, ix, iy, iw, ih,
1140 wwin->frame_x, wwin->frame_y,
1141 wwin->frame->core->width, wwin->frame->core->height,
1142 False);
1144 #endif /* ANIMATIONS */
1145 wwin->flags.skip_next_animation = 0;
1146 XGrabServer(dpy);
1147 if (!wwin->flags.shaded) {
1148 XMapWindow(dpy, wwin->client_win);
1150 XMapWindow(dpy, wwin->frame->core->window);
1151 wRaiseFrame(wwin->frame->core);
1152 if (!wwin->flags.shaded) {
1153 wClientSetState(wwin, NormalState, None);
1155 mapTransientsFor(wwin);
1157 if (!wPreferences.disable_miniwindows) {
1158 RemoveFromStackList(wwin->icon->core);
1159 /* removeIconGrabs(wwin->icon);*/
1160 wIconDestroy(wwin->icon);
1161 wwin->icon = NULL;
1163 XUngrabServer(dpy);
1165 if (wPreferences.focus_mode==WKF_CLICK)
1166 wSetFocusTo(wwin->screen_ptr, wwin);
1168 #ifdef ANIMATIONS
1169 if (!wwin->screen_ptr->flags.startup) {
1170 Window clientwin = wwin->client_win;
1172 XSync(dpy, 0);
1173 processEvents(XPending(dpy));
1175 if (!wWindowFor(clientwin))
1176 return;
1178 #endif
1180 if (wPreferences.auto_arrange_icons) {
1181 wArrangeIcons(wwin->screen_ptr, True);
1184 #ifdef GNOME_STUFF
1185 wGNOMEUpdateClientStateHint(wwin, False);
1186 #endif
1187 #ifdef KWM_HINTS
1188 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1189 wKWMSendEventMessage(wwin, WKWMChangedClient);
1190 #endif
1192 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1197 static void
1198 hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
1200 if (wwin->flags.miniaturized) {
1201 if (wwin->icon) {
1202 XUnmapWindow(dpy, wwin->icon->core->window);
1203 wwin->icon->mapped = 0;
1205 wwin->flags.hidden = 1;
1206 #ifdef GNOME_STUFF
1207 wGNOMEUpdateClientStateHint(wwin, False);
1208 #endif
1210 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1212 return;
1215 if (wwin->flags.inspector_open) {
1216 WWindow *pwin = wwin->inspector->frame;
1218 wWindowUnmap(pwin);
1219 pwin->flags.hidden = 1;
1221 wClientSetState(pwin, IconicState, icon->icon_win);
1224 wwin->flags.hidden = 1;
1225 wWindowUnmap(wwin);
1227 wClientSetState(wwin, IconicState, icon->icon_win);
1228 flushExpose();
1229 #ifdef WMSOUND
1230 wSoundPlay(WMSOUND_HIDE);
1231 #endif
1232 #ifdef ANIMATIONS
1233 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1234 !wwin->flags.skip_next_animation && animate) {
1235 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1236 wwin->frame->core->width, wwin->frame->core->height,
1237 icon_x, icon_y, icon->core->width, icon->core->height,
1238 True);
1240 #endif
1241 wwin->flags.skip_next_animation = 0;
1243 #ifdef GNOME_STUFF
1244 wGNOMEUpdateClientStateHint(wwin, False);
1245 #endif
1247 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1252 void
1253 wHideOtherApplications(WWindow *awin)
1255 WWindow *wwin;
1256 WApplication *tapp;
1257 #ifdef REDUCE_APPICONS
1258 char *tinstance, *tclass;
1259 unsigned int brokenwin = 0, match = 0;
1260 #endif
1262 if (!awin)
1263 return;
1264 wwin = awin->screen_ptr->focused_window;
1266 #ifdef REDUCE_APPICONS
1267 if (awin->wm_instance == NULL || awin->wm_class == NULL)
1268 brokenwin++;
1269 #endif
1271 while (wwin) {
1272 if (wwin!=awin
1273 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1274 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1275 && !wwin->flags.internal_window
1276 && (!wwin->flags.inspector_open || wwin->inspector->frame!=awin)
1277 && !WFLAGP(wwin, no_hide_others)) {
1279 #ifdef REDUCE_APPICONS
1280 match = 0;
1281 if (!brokenwin) {
1282 if ((tinstance = wwin->wm_instance) == NULL)
1283 tinstance = "";
1284 if ((tclass = wwin->wm_class) == NULL)
1285 tclass = "";
1286 if ((strcmp(awin->wm_instance, tinstance) == 0) &&
1287 (strcmp(awin->wm_class, tclass) == 0) )
1288 match++;
1290 #endif
1292 if (wwin->main_window==None || WFLAGP(wwin, no_appicon)) {
1293 if (!WFLAGP(wwin, no_miniaturizable)) {
1294 wwin->flags.skip_next_animation = 1;
1295 wIconifyWindow(wwin);
1297 } else if (wwin->main_window!=None
1298 #ifndef REDUCE_APPICONS
1299 && awin->main_window != wwin->main_window) {
1300 #else
1301 && (awin->main_window != wwin->main_window && !match)) {
1302 #endif
1303 tapp = wApplicationOf(wwin->main_window);
1304 if (tapp) {
1305 tapp->flags.skip_next_animation = 1;
1306 wHideApplication(tapp);
1307 } else {
1308 if (!WFLAGP(wwin, no_miniaturizable)) {
1309 wwin->flags.skip_next_animation = 1;
1310 wIconifyWindow(wwin);
1315 wwin = wwin->prev;
1318 wSetFocusTo(awin->screen_ptr, awin);
1324 void
1325 wHideApplication(WApplication *wapp)
1327 #ifdef REDUCE_APPICONS
1328 WApplication *tapp;
1329 char *tinstance, *tclass;
1330 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1331 #endif
1332 WScreen *scr;
1333 WWindow *wlist;
1334 int hadfocus;
1336 if (!wapp) {
1337 wwarning("trying to hide a non grouped window");
1338 return;
1340 if (!wapp->main_window_desc) {
1341 wwarning("group leader not found for window group");
1342 return;
1344 #ifdef REDUCE_APPICONS
1345 if ((wapp->main_window_desc->wm_instance == NULL) ||
1346 (wapp->main_window_desc->wm_class == NULL))
1347 nowmhints++;
1348 #endif
1349 scr = wapp->main_window_desc->screen_ptr;
1350 hadfocus = 0;
1351 wlist = scr->focused_window;
1352 if (!wlist)
1353 return;
1355 if (wlist->main_window == wapp->main_window)
1356 wapp->last_focused = wlist;
1357 else
1358 wapp->last_focused = NULL;
1359 while (wlist) {
1360 #ifdef REDUCE_APPICONS
1361 matchwmhints = matchworkspace = 0;
1362 if (!nowmhints) {
1363 tapp = wApplicationOf(wlist->main_window);
1364 tinstance = tclass = NULL;
1365 if (tapp) {
1366 if (tapp->main_window_desc) {
1367 tinstance = tapp->main_window_desc->wm_instance;
1368 tclass = tapp->main_window_desc->wm_class;
1371 if (tapp == NULL || tinstance == NULL || tclass == NULL) {
1372 /* Should never reach here */
1373 tinstance = "";
1374 tclass = "";
1376 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0) &&
1377 (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1378 matchwmhints++;
1380 if (wlist->frame) {
1381 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1382 matchworkspace++;
1384 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1385 matchworkspace) {
1386 #ifdef I_HATE_THIS
1388 #endif
1389 #else
1390 if (wlist->main_window == wapp->main_window) {
1391 #endif
1392 if (wlist->flags.focused) {
1393 hadfocus = 1;
1395 if (wapp->app_icon)
1396 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1397 wapp->app_icon->y_pos, wlist,
1398 !wapp->flags.skip_next_animation);
1400 wlist = wlist->prev;
1403 wapp->flags.skip_next_animation = 0;
1405 if (hadfocus) {
1406 if (wPreferences.focus_mode==WKF_CLICK) {
1407 wlist = scr->focused_window;
1408 while (wlist) {
1409 if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden
1410 && (wlist->flags.mapped || wlist->flags.shaded))
1411 break;
1412 wlist = wlist->prev;
1414 wSetFocusTo(scr, wlist);
1415 } else {
1416 wSetFocusTo(scr, NULL);
1420 wapp->flags.hidden = 1;
1422 if(wPreferences.auto_arrange_icons) {
1423 wArrangeIcons(scr, True);
1425 #ifdef HIDDENDOT
1426 if (wapp->app_icon)
1427 wAppIconPaint(wapp->app_icon);
1428 #endif
1434 static void
1435 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1436 int bringToCurrentWS)
1438 if (bringToCurrentWS)
1439 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1441 wwin->flags.hidden=0;
1442 wwin->flags.mapped=1;
1444 #ifdef WMSOUND
1445 wSoundPlay(WMSOUND_UNHIDE);
1446 #endif
1447 #ifdef ANIMATIONS
1448 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1449 && animate) {
1450 animateResize(wwin->screen_ptr, icon_x, icon_y,
1451 icon->core->width, icon->core->height,
1452 wwin->frame_x, wwin->frame_y,
1453 wwin->frame->core->width, wwin->frame->core->height,
1454 True);
1456 #endif
1457 wwin->flags.skip_next_animation = 0;
1458 XMapWindow(dpy, wwin->client_win);
1459 XMapWindow(dpy, wwin->frame->core->window);
1460 wClientSetState(wwin, NormalState, None);
1461 wRaiseFrame(wwin->frame->core);
1462 if (wwin->flags.inspector_open) {
1463 WWindow *pwin = wwin->inspector->frame;
1465 pwin->flags.hidden = 0;
1466 pwin->flags.mapped = 1;
1467 XMapWindow(dpy, pwin->client_win);
1468 XMapWindow(dpy, pwin->frame->core->window);
1469 wClientSetState(pwin, NormalState, None);
1472 #ifdef GNOME_STUFF
1473 wGNOMEUpdateClientStateHint(wwin, False);
1474 #endif
1476 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1481 void
1482 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1484 WScreen *scr;
1485 WWindow *wlist, *next;
1486 WWindow *focused=NULL;
1487 #ifdef REDUCE_APPICONS
1488 char *tinstance, *tclass;
1489 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1490 #endif
1492 if (!wapp) {
1493 return;
1496 #ifdef REDUCE_APPICONS
1497 if ((wapp->main_window_desc->wm_class == NULL) ||
1498 (wapp->main_window_desc->wm_instance == NULL))
1499 nowmhints++;
1500 #endif
1502 scr = wapp->main_window_desc->screen_ptr;
1503 wlist = scr->focused_window;
1504 if (!wlist) return;
1505 /* goto beginning of list */
1506 while (wlist->prev)
1507 wlist = wlist->prev;
1509 while (wlist) {
1510 next = wlist->next;
1512 #ifndef REDUCE_APPICONS
1513 if (wlist->main_window == wapp->main_window) {
1514 #else
1515 matchwmhints = matchworkspace = 0;
1516 if (!nowmhints) {
1517 if ((tinstance = wlist->wm_instance) == NULL)
1518 tinstance = "";
1519 if ((tclass = wlist->wm_class) == NULL)
1520 tclass = "";
1521 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0)
1522 && (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1523 matchwmhints++;
1525 if (wlist->frame) {
1526 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1527 matchworkspace++;
1530 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1531 matchworkspace) {
1532 #endif
1533 if (wlist->flags.focused)
1534 focused = wlist;
1535 else if (!focused || !focused->flags.focused)
1536 focused = wlist;
1538 if (wlist->flags.miniaturized && wlist->icon) {
1539 if (bringToCurrentWS || wPreferences.sticky_icons
1540 || wlist->frame->workspace == scr->current_workspace) {
1541 if (!wlist->icon->mapped) {
1542 XMapWindow(dpy, wlist->icon->core->window);
1543 wlist->icon->mapped = 1;
1545 wlist->flags.hidden = 0;
1547 UpdateSwitchMenu(scr, wlist, ACTION_CHANGE_STATE);
1549 if (wlist->frame->workspace != scr->current_workspace)
1550 wWindowChangeWorkspace(wlist, scr->current_workspace);
1552 if (miniwindows) {
1553 wDeiconifyWindow(wlist);
1555 } else if (wlist->flags.hidden) {
1556 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1557 wapp->app_icon->y_pos, wlist,
1558 !wapp->flags.skip_next_animation,
1559 bringToCurrentWS);
1560 } else {
1561 if (bringToCurrentWS
1562 && wlist->frame->workspace != scr->current_workspace) {
1563 wWindowChangeWorkspace(wlist, scr->current_workspace);
1565 wRaiseFrame(wlist->frame->core);
1568 wlist = next;
1571 wapp->flags.skip_next_animation = 0;
1572 wapp->flags.hidden = 0;
1574 if (focused)
1575 wSetFocusTo(scr, focused);
1576 else if (wapp->last_focused && wapp->last_focused->flags.mapped)
1577 wSetFocusTo(scr, wapp->last_focused);
1578 wapp->last_focused = NULL;
1579 if (wPreferences.auto_arrange_icons) {
1580 wArrangeIcons(scr, True);
1582 #ifdef HIDDENDOT
1583 wAppIconPaint(wapp->app_icon);
1584 #endif
1589 void
1590 wShowAllWindows(WScreen *scr)
1592 WWindow *wwin, *old_foc;
1593 WApplication *wapp;
1595 old_foc = wwin = scr->focused_window;
1596 while (wwin) {
1597 if (!wwin->flags.internal_window &&
1598 (scr->current_workspace == wwin->frame->workspace
1599 || IS_OMNIPRESENT(wwin))) {
1600 if (wwin->flags.miniaturized) {
1601 wwin->flags.skip_next_animation = 1;
1602 wDeiconifyWindow(wwin);
1603 } else if (wwin->flags.hidden) {
1604 wapp = wApplicationOf(wwin->main_window);
1605 if (wapp) {
1606 wUnhideApplication(wapp, False, False);
1607 } else {
1608 wwin->flags.skip_next_animation = 1;
1609 wDeiconifyWindow(wwin);
1613 wwin = wwin->prev;
1615 wSetFocusTo(scr, old_foc);
1616 /*wRaiseFrame(old_foc->frame->core);*/
1620 void
1621 wRefreshDesktop(WScreen *scr)
1623 Window win;
1624 XSetWindowAttributes attr;
1626 attr.backing_store = NotUseful;
1627 attr.save_under = False;
1628 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1629 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1630 (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
1631 &attr);
1632 XMapRaised(dpy, win);
1633 XDestroyWindow(dpy, win);
1634 XFlush(dpy);
1638 void
1639 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1641 WWindow *wwin;
1642 WAppIcon *aicon;
1643 int pf; /* primary axis */
1644 int sf; /* secondary axis */
1645 int fullW;
1646 int fullH;
1647 int pi, si;
1648 int sx1, sx2, sy1, sy2; /* screen boundary */
1649 int sw, sh;
1650 int xo, yo;
1651 int xs, ys;
1652 int isize = wPreferences.icon_size;
1655 * Find out screen boundaries.
1657 sx1 = 0;
1658 sy1 = 0;
1659 sx2 = scr->scr_width;
1660 sy2 = scr->scr_height;
1661 if (scr->dock) {
1662 if (scr->dock->on_right_side)
1663 sx2 -= isize + DOCK_EXTRA_SPACE;
1664 else
1665 sx1 += isize + DOCK_EXTRA_SPACE;
1668 sw = isize * (scr->scr_width/isize);
1669 sh = isize * (scr->scr_height/isize);
1670 fullW = (sx2-sx1)/isize;
1671 fullH = (sy2-sy1)/isize;
1673 /* icon yard boundaries */
1674 if (wPreferences.icon_yard & IY_VERT) {
1675 pf = fullH;
1676 sf = fullW;
1677 } else {
1678 pf = fullW;
1679 sf = fullH;
1681 if (wPreferences.icon_yard & IY_RIGHT) {
1682 xo = sx2 - isize;
1683 xs = -1;
1684 } else {
1685 xo = sx1;
1686 xs = 1;
1688 if (wPreferences.icon_yard & IY_TOP) {
1689 yo = sy1;
1690 ys = 1;
1691 } else {
1692 yo = sy2 - isize;
1693 ys = -1;
1696 /* arrange icons putting the most recently focused window
1697 * as the last icon */
1698 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1699 : xo + xs*(pi*isize))
1700 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1701 : yo + ys*(si*isize))
1703 /* arrange application icons */
1704 aicon = scr->app_icon_list;
1705 /* reverse them to avoid unnecessarily sliding of icons */
1706 while (aicon && aicon->next)
1707 aicon = aicon->next;
1709 pi = 0;
1710 si = 0;
1711 while (aicon) {
1712 if (!aicon->docked) {
1713 if (aicon->x_pos != X || aicon->y_pos != Y) {
1714 #ifdef ANIMATIONS
1715 if (!wPreferences.no_animations) {
1716 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1717 X, Y);
1719 #endif /* ANIMATIONS */
1721 wAppIconMove(aicon, X, Y);
1722 pi++;
1724 /* we reversed the order so we use prev */
1725 aicon = aicon->prev;
1726 if (pi >= pf) {
1727 pi=0;
1728 si++;
1732 /* arrange miniwindows */
1734 wwin = scr->focused_window;
1735 /* reverse them to avoid unnecessarily shuffling */
1736 while (wwin && wwin->prev)
1737 wwin = wwin->prev;
1739 while (wwin) {
1740 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1741 (wwin->frame->workspace==scr->current_workspace ||
1742 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1744 if (arrangeAll || !wwin->flags.icon_moved) {
1745 if (wwin->icon_x != X || wwin->icon_y != Y) {
1746 #ifdef ANIMATIONS
1747 if (wPreferences.no_animations) {
1748 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1749 } else {
1750 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1751 wwin->icon_y, X, Y);
1753 #else
1754 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1755 #endif /* ANIMATIONS */
1757 wwin->icon_x = X;
1758 wwin->icon_y = Y;
1759 pi++;
1762 if (arrangeAll) {
1763 wwin->flags.icon_moved = 0;
1765 /* we reversed the order, so we use next */
1766 wwin = wwin->next;
1767 if (pi >= pf) {
1768 pi=0;
1769 si++;
1775 void
1776 wSelectWindow(WWindow *wwin, Bool flag)
1778 WScreen *scr = wwin->screen_ptr;
1780 if (flag) {
1781 wwin->flags.selected = 1;
1782 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1783 if (!scr->selected_windows)
1784 scr->selected_windows = WMCreateBag(4);
1785 WMPutInBag(scr->selected_windows, wwin);
1786 } else {
1787 wwin->flags.selected = 0;
1788 XSetWindowBorder(dpy, wwin->frame->core->window,
1789 scr->frame_border_pixel);
1790 if (scr->selected_windows) {
1791 WMRemoveFromBag(scr->selected_windows, wwin);
1797 void
1798 wMakeWindowVisible(WWindow *wwin)
1800 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
1801 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1803 if (wwin->flags.shaded) {
1804 wUnshadeWindow(wwin);
1806 if (wwin->flags.hidden) {
1807 WApplication *app;
1809 app = wApplicationOf(wwin->main_window);
1810 if (app)
1811 wUnhideApplication(app, False, False);
1812 } else if (wwin->flags.miniaturized) {
1813 wDeiconifyWindow(wwin);
1814 } else {
1815 if (!WFLAGP(wwin, no_focusable))
1816 wSetFocusTo(wwin->screen_ptr, wwin);
1817 wRaiseFrame(wwin->frame->core);