Added WMSetTabViewFont().
[wmaker-crm.git] / src / actions.c
blobe790274cba709994ac747203714e65999a5ad7ed
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 "list.h"
50 #include "workspace.h"
52 #ifdef GNOME_STUFF
53 # include "gnome.h"
54 #endif
55 #ifdef KWM_HINTS
56 # include "kwm.h"
57 #endif
59 #ifdef WMSOUND
60 #include "wmsound.h"
61 #endif
64 /****** Global Variables ******/
65 extern Time LastTimestamp;
66 extern Time LastFocusChange;
68 extern Cursor wCursor[WCUR_LAST];
70 extern WPreferences wPreferences;
72 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 */
122 *----------------------------------------------------------------------
123 * wSetFocusTo--
124 * Changes the window focus to the one passed as argument.
125 * If the window to focus is not already focused, it will be brought
126 * to the head of the list of windows. Previously focused window is
127 * unfocused.
129 * Side effects:
130 * Window list may be reordered and the window focus is changed.
132 *----------------------------------------------------------------------
134 void
135 wSetFocusTo(WScreen *scr, WWindow *wwin)
137 WWindow *focused=scr->focused_window;
138 int timestamp=LastTimestamp;
139 WApplication *oapp=NULL, *napp=NULL;
140 int wasfocused;
142 LastFocusChange = timestamp;
145 * This is a hack, because XSetInputFocus() should have a proper
146 * timestamp instead of CurrentTime but it seems that some times
147 * clients will not receive focus properly that way.
148 if (ignoreTimestamp)
150 timestamp = CurrentTime;
152 if (focused)
153 oapp = wApplicationOf(focused->main_window);
155 if (wwin == NULL) {
156 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
157 if (focused) {
158 wWindowUnfocus(focused);
160 if (oapp) {
161 wAppMenuUnmap(oapp->menu);
162 #ifdef NEWAPPICON
163 wApplicationDeactivate(oapp);
164 #endif
166 #ifdef KWM_HINTS
167 wKWMUpdateActiveWindowHint(scr);
168 wKWMSendEventMessage(NULL, WKWMFocusWindow);
169 #endif
170 return;
172 wasfocused = wwin->flags.focused;
173 napp = wApplicationOf(wwin->main_window);
175 /* remember last workspace where the app has been */
176 if (napp)
177 napp->last_workspace = wwin->screen_ptr->current_workspace;
179 if (wwin->flags.mapped && !WFLAGP(wwin, no_focusable)) {
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);
206 if (WFLAGP(wwin, no_focusable))
207 return;
209 /* if this is not the focused window focus it */
210 if (focused!=wwin) {
211 /* change the focus window list order */
212 if (wwin->prev)
213 wwin->prev->next = wwin->next;
215 if (wwin->next)
216 wwin->next->prev = wwin->prev;
218 wwin->prev = focused;
219 focused->next = wwin;
220 wwin->next = NULL;
221 scr->focused_window = wwin;
223 if (oapp && oapp != napp) {
224 wAppMenuUnmap(oapp->menu);
225 #ifdef NEWAPPICON
226 wApplicationDeactivate(oapp);
227 #endif
231 wWindowFocus(wwin, focused);
233 if (napp && !wasfocused) {
234 #ifdef USER_MENU
235 wUserMenuRefreshInstances(napp->menu, wwin);
236 #endif /* USER_MENU */
238 if (wwin->flags.mapped)
239 wAppMenuMap(napp->menu, wwin);
240 #ifdef NEWAPPICON
241 wApplicationActivate(napp);
242 #endif
244 #ifdef KWM_HINTS
245 wKWMUpdateActiveWindowHint(scr);
246 wKWMSendEventMessage(wwin, WKWMFocusWindow);
247 #endif
248 XFlush(dpy);
252 void
253 wShadeWindow(WWindow *wwin)
255 time_t time0 = time(NULL);
256 #ifdef ANIMATIONS
257 int y, s, w, h;
258 #endif
260 if (wwin->flags.shaded)
261 return;
263 XLowerWindow(dpy, wwin->client_win);
265 #ifdef WMSOUND
266 wSoundPlay(WMSOUND_SHADE);
267 #endif
269 #ifdef ANIMATIONS
270 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
271 && !wPreferences.no_animations) {
272 /* do the shading animation */
273 h = wwin->frame->core->height;
274 s = h/SHADE_STEPS;
275 if (s < 1) s=1;
276 w = wwin->frame->core->width;
277 y = wwin->frame->top_width;
278 while (h>wwin->frame->top_width+1) {
279 XMoveWindow(dpy, wwin->client_win, 0, y);
280 XResizeWindow(dpy, wwin->frame->core->window, w, h);
281 XFlush(dpy);
283 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
284 break;
286 if (SHADE_DELAY > 0)
287 wusleep(SHADE_DELAY*1000L);
288 h-=s;
289 y-=s;
291 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
293 #endif /* ANIMATIONS */
295 wwin->flags.skip_next_animation = 0;
296 wwin->flags.shaded = 1;
297 wwin->flags.mapped = 0;
298 /* prevent window withdrawal when getting UnmapNotify */
299 XSelectInput(dpy, wwin->client_win,
300 wwin->event_mask & ~StructureNotifyMask);
301 XUnmapWindow(dpy, wwin->client_win);
302 XSelectInput(dpy, wwin->client_win, wwin->event_mask);
304 /* for the client it's just like iconification */
305 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
306 wwin->frame->top_width - 1);
308 wwin->client.y = wwin->frame_y - wwin->client.height
309 + wwin->frame->top_width;
310 wWindowSynthConfigureNotify(wwin);
313 wClientSetState(wwin, IconicState, None);
316 #ifdef GNOME_STUFF
317 wGNOMEUpdateClientStateHint(wwin, False);
318 #endif
319 #ifdef KWM_HINTS
320 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
321 wKWMSendEventMessage(wwin, WKWMChangedClient);
322 #endif
323 /* update window list to reflect shaded state */
324 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
326 #ifdef ANIMATIONS
327 if (!wwin->screen_ptr->flags.startup) {
328 /* Look at processEvents() for reason of this code. */
329 XSync(dpy, 0);
330 processEvents(XPending(dpy));
332 #endif
336 void
337 wUnshadeWindow(WWindow *wwin)
339 time_t time0 = time(NULL);
340 #ifdef ANIMATIONS
341 int y, s, w, h;
342 #endif /* ANIMATIONS */
345 if (!wwin->flags.shaded)
346 return;
348 wwin->flags.shaded = 0;
349 wwin->flags.mapped = 1;
350 XMapWindow(dpy, wwin->client_win);
352 #ifdef WMSOUND
353 wSoundPlay(WMSOUND_UNSHADE);
354 #endif
356 #ifdef ANIMATIONS
357 if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) {
358 /* do the shading animation */
359 h = wwin->frame->top_width + wwin->frame->bottom_width;
360 y = wwin->frame->top_width - wwin->client.height;
361 s = abs(y)/SHADE_STEPS;
362 if (s<1) s=1;
363 w = wwin->frame->core->width;
364 XMoveWindow(dpy, wwin->client_win, 0, y);
365 if (s>0) {
366 while (h < wwin->client.height + wwin->frame->top_width
367 + wwin->frame->bottom_width) {
368 XResizeWindow(dpy, wwin->frame->core->window, w, h);
369 XMoveWindow(dpy, wwin->client_win, 0, y);
370 XSync(dpy, 0);
371 if (SHADE_DELAY > 0)
372 wusleep(SHADE_DELAY*2000L/3);
373 h+=s;
374 y+=s;
376 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
377 break;
380 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
382 #endif /* ANIMATIONS */
384 wwin->flags.skip_next_animation = 0;
385 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
386 wwin->frame->top_width + wwin->client.height
387 + wwin->frame->bottom_width);
389 wwin->client.y = wwin->frame_y + wwin->frame->top_width;
390 wWindowSynthConfigureNotify(wwin);
393 wClientSetState(wwin, NormalState, None);
395 /* if the window is focused, set the focus again as it was disabled during
396 * shading */
397 if (wwin->flags.focused)
398 wSetFocusTo(wwin->screen_ptr, wwin);
400 #ifdef GNOME_STUFF
401 wGNOMEUpdateClientStateHint(wwin, False);
402 #endif
403 #ifdef KWM_HINTS
404 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
405 wKWMSendEventMessage(wwin, WKWMChangedClient);
406 #endif
408 /* update window list to reflect unshaded state */
409 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
414 void
415 wMaximizeWindow(WWindow *wwin, int directions)
417 int new_width, new_height, new_x, new_y;
418 WArea usableArea = wwin->screen_ptr->totalUsableArea;
421 if (WFLAGP(wwin, no_resizable))
422 return;
425 if (WFLAGP(wwin, full_maximize)) {
426 usableArea.x1 = 0;
427 usableArea.y1 = 0;
428 usableArea.x2 = wwin->screen_ptr->scr_width;
429 usableArea.y2 = wwin->screen_ptr->scr_height;
432 if (wwin->flags.shaded) {
433 wwin->flags.skip_next_animation = 1;
434 wUnshadeWindow(wwin);
436 wwin->flags.maximized = directions;
437 wwin->old_geometry.width = wwin->client.width;
438 wwin->old_geometry.height = wwin->client.height;
439 wwin->old_geometry.x = wwin->frame_x;
440 wwin->old_geometry.y = wwin->frame_y;
442 #ifdef KWM_HINTS
443 wKWMUpdateClientGeometryRestore(wwin);
444 #endif
446 if (directions & MAX_HORIZONTAL) {
448 new_width = (usableArea.x2-usableArea.x1)-FRAME_BORDER_WIDTH*2;
449 new_x = usableArea.x1;
451 } else {
453 new_x = wwin->frame_x;
454 new_width = wwin->frame->core->width;
458 if (directions & MAX_VERTICAL) {
460 new_height = (usableArea.y2-usableArea.y1)-FRAME_BORDER_WIDTH*2;
461 new_y = usableArea.y1;
462 if (WFLAGP(wwin, full_maximize))
463 new_y -= wwin->frame->top_width;
465 } else {
467 new_y = wwin->frame_y;
468 new_height = wwin->frame->core->height;
472 if (!WFLAGP(wwin, full_maximize)) {
473 new_height -= wwin->frame->top_width+wwin->frame->bottom_width;
476 wWindowConstrainSize(wwin, &new_width, &new_height);
477 wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
479 #ifdef GNOME_STUFF
480 wGNOMEUpdateClientStateHint(wwin, False);
481 #endif
482 #ifdef KWM_HINTS
483 wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
484 wKWMSendEventMessage(wwin, WKWMChangedClient);
485 #endif
487 #ifdef WMSOUND
488 wSoundPlay(WMSOUND_MAXIMIZE);
489 #endif
493 void
494 wUnmaximizeWindow(WWindow *wwin)
496 int restore_x, restore_y;
498 if (!wwin->flags.maximized)
499 return;
501 if (wwin->flags.shaded) {
502 wwin->flags.skip_next_animation = 1;
503 wUnshadeWindow(wwin);
505 restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ?
506 wwin->old_geometry.x : wwin->frame_x;
507 restore_y = (wwin->flags.maximized & MAX_VERTICAL) ?
508 wwin->old_geometry.y : wwin->frame_y;
509 wwin->flags.maximized = 0;
510 wWindowConfigure(wwin, restore_x, restore_y,
511 wwin->old_geometry.width, wwin->old_geometry.height);
513 #ifdef GNOME_STUFF
514 wGNOMEUpdateClientStateHint(wwin, False);
515 #endif
516 #ifdef KWM_HINTS
517 wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
518 wKWMSendEventMessage(wwin, WKWMChangedClient);
519 #endif
521 #ifdef WMSOUND
522 wSoundPlay(WMSOUND_UNMAXIMIZE);
523 #endif
526 #ifdef ANIMATIONS
527 static void
528 animateResizeFlip(WScreen *scr, int x, int y, int w, int h,
529 int fx, int fy, int fw, int fh, int steps)
531 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
532 float cx, cy, cw, ch;
533 float xstep, ystep, wstep, hstep;
534 XPoint points[5];
535 float dx, dch, midy;
536 float angle, final_angle, delta;
538 xstep = (float)(fx-x)/steps;
539 ystep = (float)(fy-y)/steps;
540 wstep = (float)(fw-w)/steps;
541 hstep = (float)(fh-h)/steps;
543 cx = (float)x;
544 cy = (float)y;
545 cw = (float)w;
546 ch = (float)h;
548 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F;
549 delta = (float)(final_angle/FRAMES);
550 for (angle=0;; angle+=delta) {
551 if (angle > final_angle)
552 angle = final_angle;
554 dx = (cw/10) - ((cw/5) * sin(angle));
555 dch = (ch/2) * cos(angle);
556 midy = cy + (ch/2);
558 points[0].x = cx + dx; points[0].y = midy - dch;
559 points[1].x = cx + cw - dx; points[1].y = points[0].y;
560 points[2].x = cx + cw + dx; points[2].y = midy + dch;
561 points[3].x = cx - dx; points[3].y = points[2].y;
562 points[4].x = points[0].x; points[4].y = points[0].y;
564 XGrabServer(dpy);
565 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
566 XFlush(dpy);
567 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
568 wusleep(MINIATURIZE_ANIMATION_DELAY_F);
569 #endif
571 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
572 XUngrabServer(dpy);
573 cx+=xstep;
574 cy+=ystep;
575 cw+=wstep;
576 ch+=hstep;
577 if (angle >= final_angle)
578 break;
581 XFlush(dpy);
583 #undef FRAMES
586 static void
587 animateResizeTwist(WScreen *scr, int x, int y, int w, int h,
588 int fx, int fy, int fw, int fh, int steps)
590 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
591 float cx, cy, cw, ch;
592 float xstep, ystep, wstep, hstep;
593 XPoint points[5];
594 float angle, final_angle, a, d, delta;
596 x += w/2;
597 y += h/2;
598 fx += fw/2;
599 fy += fh/2;
601 xstep = (float)(fx-x)/steps;
602 ystep = (float)(fy-y)/steps;
603 wstep = (float)(fw-w)/steps;
604 hstep = (float)(fh-h)/steps;
606 cx = (float)x;
607 cy = (float)y;
608 cw = (float)w;
609 ch = (float)h;
611 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T;
612 delta = (float)(final_angle/FRAMES);
613 for (angle=0;; angle+=delta) {
614 if (angle > final_angle)
615 angle = final_angle;
617 a = atan(ch/cw);
618 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
620 points[0].x = cx+cos(angle-a)*d;
621 points[0].y = cy+sin(angle-a)*d;
622 points[1].x = cx+cos(angle+a)*d;
623 points[1].y = cy+sin(angle+a)*d;
624 points[2].x = cx+cos(angle-a+WM_PI)*d;
625 points[2].y = cy+sin(angle-a+WM_PI)*d;
626 points[3].x = cx+cos(angle+a+WM_PI)*d;
627 points[3].y = cy+sin(angle+a+WM_PI)*d;
628 points[4].x = cx+cos(angle-a)*d;
629 points[4].y = cy+sin(angle-a)*d;
630 XGrabServer(dpy);
631 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
632 XFlush(dpy);
633 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
634 wusleep(MINIATURIZE_ANIMATION_DELAY_T);
635 #endif
637 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
638 XUngrabServer(dpy);
639 cx+=xstep;
640 cy+=ystep;
641 cw+=wstep;
642 ch+=hstep;
643 if (angle >= final_angle)
644 break;
647 XFlush(dpy);
649 #undef FRAMES
652 static void
653 animateResizeZoom(WScreen *scr, int x, int y, int w, int h,
654 int fx, int fy, int fw, int fh, int steps)
656 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
657 float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
658 float xstep, ystep, wstep, hstep;
659 int i, j;
661 xstep = (float)(fx-x)/steps;
662 ystep = (float)(fy-y)/steps;
663 wstep = (float)(fw-w)/steps;
664 hstep = (float)(fh-h)/steps;
666 for (j=0; j<FRAMES; j++) {
667 cx[j] = (float)x;
668 cy[j] = (float)y;
669 cw[j] = (float)w;
670 ch[j] = (float)h;
672 XGrabServer(dpy);
673 for (i=0; i<steps; i++) {
674 for (j=0; j<FRAMES; j++) {
675 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
676 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
678 XFlush(dpy);
679 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
680 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
681 #endif
682 for (j=0; j<FRAMES; j++) {
683 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
684 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
685 if (j<FRAMES-1) {
686 cx[j]=cx[j+1];
687 cy[j]=cy[j+1];
688 cw[j]=cw[j+1];
689 ch[j]=ch[j+1];
690 } else {
691 cx[j]+=xstep;
692 cy[j]+=ystep;
693 cw[j]+=wstep;
694 ch[j]+=hstep;
699 for (j=0; j<FRAMES; j++) {
700 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
701 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
703 XFlush(dpy);
704 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
705 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
706 #endif
707 for (j=0; j<FRAMES; j++) {
708 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
709 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
712 XUngrabServer(dpy);
714 #undef FRAMES
717 static void
718 animateResize(WScreen *scr, int x, int y, int w, int h,
719 int fx, int fy, int fw, int fh, int hiding)
721 int style = wPreferences.iconification_style; /* Catch the value */
722 int steps, k;
724 if (style == WIS_NONE)
725 return;
727 if (style == WIS_RANDOM) {
728 style = rand()%3;
731 k = (hiding ? 2 : 3);
732 switch(style) {
733 case WIS_TWIST:
734 steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
735 if (steps>0)
736 animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
737 break;
738 case WIS_FLIP:
739 steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
740 if (steps>0)
741 animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
742 break;
743 case WIS_ZOOM:
744 default:
745 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
746 if (steps>0)
747 animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
748 break;
751 #endif /* ANIMATIONS */
754 static void
755 flushExpose()
757 XEvent tmpev;
759 while (XCheckTypedEvent(dpy, Expose, &tmpev))
760 WMHandleEvent(&tmpev);
761 XSync(dpy, 0);
764 static void
765 unmapTransientsFor(WWindow *wwin)
767 WWindow *tmp;
770 tmp = wwin->screen_ptr->focused_window;
771 while (tmp) {
772 /* unmap the transients for this transient */
773 if (tmp!=wwin && tmp->transient_for == wwin->client_win
774 && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
775 || tmp->flags.shaded)) {
776 unmapTransientsFor(tmp);
777 tmp->flags.miniaturized = 1;
778 if (!tmp->flags.shaded) {
779 wWindowUnmap(tmp);
780 } else {
781 XUnmapWindow(dpy, tmp->frame->core->window);
784 if (!tmp->flags.shaded)
786 wClientSetState(tmp, IconicState, None);
787 #ifdef KWM_HINTS
788 wKWMUpdateClientStateHint(tmp, KWMIconifiedFlag);
789 wKWMSendEventMessage(tmp, WKWMRemoveWindow);
790 tmp->flags.kwm_hidden_for_modules = 1;
791 #endif
793 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
796 tmp = tmp->prev;
801 static void
802 mapTransientsFor(WWindow *wwin)
804 WWindow *tmp;
806 tmp = wwin->screen_ptr->focused_window;
807 while (tmp) {
808 /* recursively map the transients for this transient */
809 if (tmp!=wwin && tmp->transient_for == wwin->client_win
810 && /*!tmp->flags.mapped*/ tmp->flags.miniaturized
811 && tmp->icon==NULL) {
812 mapTransientsFor(tmp);
813 tmp->flags.miniaturized = 0;
814 if (!tmp->flags.shaded) {
815 wWindowMap(tmp);
816 } else {
817 XMapWindow(dpy, tmp->frame->core->window);
819 tmp->flags.semi_focused = 0;
821 if (!tmp->flags.shaded)
823 wClientSetState(tmp, NormalState, None);
824 #ifdef KWM_HINTS
825 wKWMUpdateClientStateHint(tmp, KWMIconifiedFlag);
826 if (tmp->flags.kwm_hidden_for_modules) {
827 wKWMSendEventMessage(tmp, WKWMAddWindow);
828 tmp->flags.kwm_hidden_for_modules = 0;
830 #endif
832 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
835 tmp = tmp->prev;
839 #if 0
840 static void
841 setupIconGrabs(WIcon *icon)
843 /* setup passive grabs on the icon */
844 XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
845 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
846 XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
847 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
848 XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
849 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
850 XSync(dpy, 0);
852 #endif
854 static WWindow*
855 recursiveTransientFor(WWindow *wwin)
857 int i;
859 if (!wwin)
860 return None;
862 /* hackish way to detect transient_for cycle */
863 i = wwin->screen_ptr->window_count+1;
865 while (wwin && wwin->transient_for != None && i>0) {
866 wwin = wWindowFor(wwin->transient_for);
867 i--;
869 if (i==0 && wwin) {
870 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
871 wwin->frame->title);
872 return NULL;
875 return wwin;
878 #if 0
879 static void
880 removeIconGrabs(WIcon *icon)
882 /* remove passive grabs on the icon */
883 XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
884 XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
885 XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);
886 XSync(dpy, 0);
888 #endif
891 void
892 wIconifyWindow(WWindow *wwin)
894 XWindowAttributes attribs;
895 int present;
898 if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
899 /* the window doesn't exist anymore */
900 return;
903 if (wwin->flags.miniaturized) {
904 return;
908 if (wwin->transient_for!=None) {
909 WWindow *owner = wWindowFor(wwin->transient_for);
911 if (owner && owner->flags.miniaturized)
912 return;
915 present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
917 /* if the window is in another workspace, simplify process */
918 if (present) {
919 /* icon creation may take a while */
920 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
921 ButtonMotionMask|ButtonReleaseMask, GrabModeAsync,
922 GrabModeAsync, None, None, CurrentTime);
925 if (!wPreferences.disable_miniwindows) {
926 if (!wwin->flags.icon_moved) {
927 PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y);
929 wwin->icon = wIconCreate(wwin);
931 wwin->icon->mapped = 1;
934 wwin->flags.miniaturized = 1;
935 wwin->flags.mapped = 0;
937 /* unmap transients */
939 unmapTransientsFor(wwin);
941 if (present) {
942 #ifdef WMSOUND
943 wSoundPlay(WMSOUND_ICONIFY);
944 #endif
946 XUngrabPointer(dpy, CurrentTime);
947 wWindowUnmap(wwin);
948 /* let all Expose events arrive so that we can repaint
949 * something before the animation starts (and the server is grabbed) */
950 XSync(dpy, 0);
952 if (wPreferences.disable_miniwindows)
953 wClientSetState(wwin, IconicState, None);
954 else
955 wClientSetState(wwin, IconicState, wwin->icon->icon_win);
957 flushExpose();
958 #ifdef ANIMATIONS
959 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
960 && !wPreferences.no_animations) {
961 int ix, iy, iw, ih;
963 if (!wPreferences.disable_miniwindows) {
964 ix = wwin->icon_x;
965 iy = wwin->icon_y;
966 iw = wwin->icon->core->width;
967 ih = wwin->icon->core->height;
968 } else {
969 #ifdef KWM_HINTS
970 WArea area;
972 if (wKWMGetIconGeometry(wwin, &area)) {
973 ix = area.x1;
974 iy = area.y1;
975 iw = area.x2 - ix;
976 ih = area.y2 - iy;
977 } else
978 #endif /* KWM_HINTS */
980 ix = 0;
981 iy = 0;
982 iw = wwin->screen_ptr->scr_width;
983 ih = wwin->screen_ptr->scr_height;
986 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
987 wwin->frame->core->width, wwin->frame->core->height,
988 ix, iy, iw, ih, False);
990 #endif
993 wwin->flags.skip_next_animation = 0;
995 if (!wPreferences.disable_miniwindows) {
997 if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
998 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)
1000 XMapWindow(dpy, wwin->icon->core->window);
1002 AddToStackList(wwin->icon->core);
1004 wLowerFrame(wwin->icon->core);
1007 if (present) {
1008 WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
1011 * It doesn't seem to be working and causes button event hangup
1012 * when deiconifying a transient window.
1013 setupIconGrabs(wwin->icon);
1015 if ((wwin->flags.focused
1016 || (owner && wwin->client_win == owner->client_win))
1017 && wPreferences.focus_mode==WKF_CLICK) {
1018 WWindow *tmp;
1020 tmp = wwin->prev;
1021 while (tmp) {
1022 if (!WFLAGP(tmp, no_focusable)
1023 && !(tmp->flags.hidden||tmp->flags.miniaturized)
1024 && (wwin->frame->workspace == tmp->frame->workspace))
1025 break;
1026 tmp = tmp->prev;
1028 wSetFocusTo(wwin->screen_ptr, tmp);
1029 } else if (wPreferences.focus_mode!=WKF_CLICK) {
1030 wSetFocusTo(wwin->screen_ptr, NULL);
1033 #ifdef ANIMATIONS
1034 if (!wwin->screen_ptr->flags.startup) {
1035 Window clientwin = wwin->client_win;
1037 XSync(dpy, 0);
1038 processEvents(XPending(dpy));
1040 /* the window can disappear while doing the processEvents() */
1041 if (!wWindowFor(clientwin))
1042 return;
1044 #endif
1048 if (wwin->flags.selected && !wPreferences.disable_miniwindows)
1049 wIconSelect(wwin->icon);
1051 #ifdef GNOME_STUFF
1052 wGNOMEUpdateClientStateHint(wwin, False);
1053 #endif
1054 #ifdef KWM_HINTS
1055 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1056 wKWMSendEventMessage(wwin, WKWMChangedClient);
1057 #endif
1059 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1065 void
1066 wDeiconifyWindow(WWindow *wwin)
1068 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1070 if (!wwin->flags.miniaturized)
1071 return;
1073 if (wwin->transient_for != None
1074 && wwin->transient_for != wwin->screen_ptr->root_win) {
1075 WWindow *owner = recursiveTransientFor(wwin);
1077 if (owner && owner->flags.miniaturized) {
1078 wDeiconifyWindow(owner);
1079 wSetFocusTo(wwin->screen_ptr, wwin);
1080 wRaiseFrame(wwin->frame->core);
1081 return;
1085 wwin->flags.miniaturized = 0;
1086 if (!wwin->flags.shaded)
1087 wwin->flags.mapped = 1;
1089 if (!wPreferences.disable_miniwindows) {
1090 if (wwin->icon->selected)
1091 wIconSelect(wwin->icon);
1093 XUnmapWindow(dpy, wwin->icon->core->window);
1096 #ifdef WMSOUND
1097 wSoundPlay(WMSOUND_DEICONIFY);
1098 #endif
1100 /* if the window is in another workspace, do it silently */
1101 #ifdef ANIMATIONS
1102 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1103 && !wwin->flags.skip_next_animation) {
1104 int ix, iy, iw, ih;
1106 if (!wPreferences.disable_miniwindows) {
1107 ix = wwin->icon_x;
1108 iy = wwin->icon_y;
1109 iw = wwin->icon->core->width;
1110 ih = wwin->icon->core->height;
1111 } else {
1112 #ifdef KWM_HINTS
1113 WArea area;
1115 if (wKWMGetIconGeometry(wwin, &area)) {
1116 ix = area.x1;
1117 iy = area.y1;
1118 iw = area.x2 - ix;
1119 ih = area.y2 - iy;
1120 } else
1121 #endif /* KWM_HINTS */
1123 ix = 0;
1124 iy = 0;
1125 iw = wwin->screen_ptr->scr_width;
1126 ih = wwin->screen_ptr->scr_height;
1129 animateResize(wwin->screen_ptr, ix, iy, iw, ih,
1130 wwin->frame_x, wwin->frame_y,
1131 wwin->frame->core->width, wwin->frame->core->height,
1132 False);
1134 #endif /* ANIMATIONS */
1135 wwin->flags.skip_next_animation = 0;
1136 XGrabServer(dpy);
1137 if (!wwin->flags.shaded) {
1138 XMapWindow(dpy, wwin->client_win);
1140 XMapWindow(dpy, wwin->frame->core->window);
1141 wRaiseFrame(wwin->frame->core);
1142 if (!wwin->flags.shaded) {
1143 wClientSetState(wwin, NormalState, None);
1145 mapTransientsFor(wwin);
1147 if (!wPreferences.disable_miniwindows) {
1148 RemoveFromStackList(wwin->icon->core);
1149 /* removeIconGrabs(wwin->icon);*/
1150 wIconDestroy(wwin->icon);
1151 wwin->icon = NULL;
1153 XUngrabServer(dpy);
1155 if (wPreferences.focus_mode==WKF_CLICK)
1156 wSetFocusTo(wwin->screen_ptr, wwin);
1158 #ifdef ANIMATIONS
1159 if (!wwin->screen_ptr->flags.startup) {
1160 Window clientwin = wwin->client_win;
1162 XSync(dpy, 0);
1163 processEvents(XPending(dpy));
1165 if (!wWindowFor(clientwin))
1166 return;
1168 #endif
1170 if (wPreferences.auto_arrange_icons) {
1171 wArrangeIcons(wwin->screen_ptr, True);
1174 #ifdef GNOME_STUFF
1175 wGNOMEUpdateClientStateHint(wwin, False);
1176 #endif
1177 #ifdef KWM_HINTS
1178 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1179 wKWMSendEventMessage(wwin, WKWMChangedClient);
1180 #endif
1182 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1187 static void
1188 hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
1190 if (wwin->flags.miniaturized) {
1191 if (wwin->icon) {
1192 XUnmapWindow(dpy, wwin->icon->core->window);
1193 wwin->icon->mapped = 0;
1195 wwin->flags.hidden = 1;
1196 #ifdef GNOME_STUFF
1197 wGNOMEUpdateClientStateHint(wwin, False);
1198 #endif
1200 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1202 return;
1205 if (wwin->flags.inspector_open) {
1206 WWindow *pwin = wwin->inspector->frame;
1208 wWindowUnmap(pwin);
1209 pwin->flags.hidden = 1;
1211 wClientSetState(pwin, IconicState, icon->icon_win);
1214 wwin->flags.hidden = 1;
1215 wWindowUnmap(wwin);
1217 wClientSetState(wwin, IconicState, icon->icon_win);
1218 flushExpose();
1219 #ifdef WMSOUND
1220 wSoundPlay(WMSOUND_HIDE);
1221 #endif
1222 #ifdef ANIMATIONS
1223 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1224 !wwin->flags.skip_next_animation && animate) {
1225 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1226 wwin->frame->core->width, wwin->frame->core->height,
1227 icon_x, icon_y, icon->core->width, icon->core->height,
1228 True);
1230 #endif
1231 wwin->flags.skip_next_animation = 0;
1233 #ifdef GNOME_STUFF
1234 wGNOMEUpdateClientStateHint(wwin, False);
1235 #endif
1237 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1242 void
1243 wHideOtherApplications(WWindow *awin)
1245 WWindow *wwin;
1246 WApplication *tapp;
1247 #ifdef REDUCE_APPICONS
1248 char *tinstance, *tclass;
1249 unsigned int brokenwin = 0, match = 0;
1250 #endif
1252 if (!awin)
1253 return;
1254 wwin = awin->screen_ptr->focused_window;
1256 #ifdef REDUCE_APPICONS
1257 if (awin->wm_instance == NULL || awin->wm_class == NULL)
1258 brokenwin++;
1259 #endif
1261 while (wwin) {
1262 if (wwin!=awin
1263 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1264 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1265 && !wwin->flags.internal_window
1266 && (!wwin->flags.inspector_open || wwin->inspector->frame!=awin)
1267 && !WFLAGP(wwin, no_hide_others)) {
1269 #ifdef REDUCE_APPICONS
1270 match = 0;
1271 if (!brokenwin) {
1272 if ((tinstance = wwin->wm_instance) == NULL)
1273 tinstance = "";
1274 if ((tclass = wwin->wm_class) == NULL)
1275 tclass = "";
1276 if ((strcmp(awin->wm_instance, tinstance) == 0) &&
1277 (strcmp(awin->wm_class, tclass) == 0) )
1278 match++;
1280 #endif
1282 if (wwin->main_window==None || WFLAGP(wwin, no_appicon)) {
1283 if (!WFLAGP(wwin, no_miniaturizable)) {
1284 wwin->flags.skip_next_animation = 1;
1285 wIconifyWindow(wwin);
1287 } else if (wwin->main_window!=None
1288 #ifndef REDUCE_APPICONS
1289 && awin->main_window != wwin->main_window) {
1290 #else
1291 && (awin->main_window != wwin->main_window && !match)) {
1292 #endif
1293 tapp = wApplicationOf(wwin->main_window);
1294 if (tapp) {
1295 tapp->flags.skip_next_animation = 1;
1296 wHideApplication(tapp);
1297 } else {
1298 if (!WFLAGP(wwin, no_miniaturizable)) {
1299 wwin->flags.skip_next_animation = 1;
1300 wIconifyWindow(wwin);
1305 wwin = wwin->prev;
1308 wSetFocusTo(awin->screen_ptr, awin);
1314 void
1315 wHideApplication(WApplication *wapp)
1317 #ifdef REDUCE_APPICONS
1318 WApplication *tapp;
1319 char *tinstance, *tclass;
1320 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1321 #endif
1322 WScreen *scr;
1323 WWindow *wlist;
1324 int hadfocus;
1326 if (!wapp) {
1327 wwarning("trying to hide a non grouped window");
1328 return;
1330 if (!wapp->main_window_desc) {
1331 wwarning("group leader not found for window group");
1332 return;
1334 #ifdef REDUCE_APPICONS
1335 if ((wapp->main_window_desc->wm_instance == NULL) ||
1336 (wapp->main_window_desc->wm_class == NULL))
1337 nowmhints++;
1338 #endif
1339 scr = wapp->main_window_desc->screen_ptr;
1340 hadfocus = 0;
1341 wlist = scr->focused_window;
1342 if (!wlist)
1343 return;
1345 if (wlist->main_window == wapp->main_window)
1346 wapp->last_focused = wlist;
1347 else
1348 wapp->last_focused = NULL;
1349 while (wlist) {
1350 #ifdef REDUCE_APPICONS
1351 matchwmhints = matchworkspace = 0;
1352 if (!nowmhints) {
1353 tapp = wApplicationOf(wlist->main_window);
1354 tinstance = tclass = NULL;
1355 if (tapp) {
1356 if (tapp->main_window_desc) {
1357 tinstance = tapp->main_window_desc->wm_instance;
1358 tclass = tapp->main_window_desc->wm_class;
1361 if (tapp == NULL || tinstance == NULL || tclass == NULL) {
1362 /* Should never reach here */
1363 tinstance = "";
1364 tclass = "";
1366 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0) &&
1367 (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1368 matchwmhints++;
1370 if (wlist->frame) {
1371 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1372 matchworkspace++;
1374 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1375 matchworkspace) {
1376 #ifdef I_HATE_THIS
1378 #endif
1379 #else
1380 if (wlist->main_window == wapp->main_window) {
1381 #endif
1382 if (wlist->flags.focused) {
1383 hadfocus = 1;
1385 if (wapp->app_icon)
1386 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1387 wapp->app_icon->y_pos, wlist,
1388 !wapp->flags.skip_next_animation);
1390 wlist = wlist->prev;
1393 wapp->flags.skip_next_animation = 0;
1395 if (hadfocus) {
1396 if (wPreferences.focus_mode==WKF_CLICK) {
1397 wlist = scr->focused_window;
1398 while (wlist) {
1399 if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden
1400 && (wlist->flags.mapped || wlist->flags.shaded))
1401 break;
1402 wlist = wlist->prev;
1404 wSetFocusTo(scr, wlist);
1405 } else {
1406 wSetFocusTo(scr, NULL);
1410 wapp->flags.hidden = 1;
1412 if(wPreferences.auto_arrange_icons) {
1413 wArrangeIcons(scr, True);
1415 #ifdef HIDDENDOT
1416 if (wapp->app_icon)
1417 wAppIconPaint(wapp->app_icon);
1418 #endif
1424 static void
1425 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1426 int bringToCurrentWS)
1428 if (bringToCurrentWS)
1429 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1431 wwin->flags.hidden=0;
1432 wwin->flags.mapped=1;
1434 #ifdef WMSOUND
1435 wSoundPlay(WMSOUND_UNHIDE);
1436 #endif
1437 #ifdef ANIMATIONS
1438 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1439 && animate) {
1440 animateResize(wwin->screen_ptr, icon_x, icon_y,
1441 icon->core->width, icon->core->height,
1442 wwin->frame_x, wwin->frame_y,
1443 wwin->frame->core->width, wwin->frame->core->height,
1444 True);
1446 #endif
1447 wwin->flags.skip_next_animation = 0;
1448 XMapWindow(dpy, wwin->client_win);
1449 XMapWindow(dpy, wwin->frame->core->window);
1450 wClientSetState(wwin, NormalState, None);
1451 wRaiseFrame(wwin->frame->core);
1452 if (wwin->flags.inspector_open) {
1453 WWindow *pwin = wwin->inspector->frame;
1455 pwin->flags.hidden = 0;
1456 pwin->flags.mapped = 1;
1457 XMapWindow(dpy, pwin->client_win);
1458 XMapWindow(dpy, pwin->frame->core->window);
1459 wClientSetState(pwin, NormalState, None);
1462 #ifdef GNOME_STUFF
1463 wGNOMEUpdateClientStateHint(wwin, False);
1464 #endif
1466 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1471 void
1472 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1474 WScreen *scr;
1475 WWindow *wlist, *next;
1476 WWindow *focused=NULL;
1477 #ifdef REDUCE_APPICONS
1478 char *tinstance, *tclass;
1479 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1480 #endif
1482 if (!wapp) {
1483 return;
1486 #ifdef REDUCE_APPICONS
1487 if ((wapp->main_window_desc->wm_class == NULL) ||
1488 (wapp->main_window_desc->wm_instance == NULL))
1489 nowmhints++;
1490 #endif
1492 scr = wapp->main_window_desc->screen_ptr;
1493 wlist = scr->focused_window;
1494 if (!wlist) return;
1495 /* goto beginning of list */
1496 while (wlist->prev)
1497 wlist = wlist->prev;
1499 while (wlist) {
1500 next = wlist->next;
1502 #ifndef REDUCE_APPICONS
1503 if (wlist->main_window == wapp->main_window) {
1504 #else
1505 matchwmhints = matchworkspace = 0;
1506 if (!nowmhints) {
1507 if ((tinstance = wlist->wm_instance) == NULL)
1508 tinstance = "";
1509 if ((tclass = wlist->wm_class) == NULL)
1510 tclass = "";
1511 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0)
1512 && (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1513 matchwmhints++;
1515 if (wlist->frame) {
1516 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1517 matchworkspace++;
1520 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1521 matchworkspace) {
1522 #endif
1523 if (wlist->flags.focused)
1524 focused = wlist;
1525 else if (!focused || !focused->flags.focused)
1526 focused = wlist;
1528 if (wlist->flags.miniaturized && wlist->icon) {
1529 if (bringToCurrentWS || wPreferences.sticky_icons
1530 || wlist->frame->workspace == scr->current_workspace) {
1531 if (!wlist->icon->mapped) {
1532 XMapWindow(dpy, wlist->icon->core->window);
1533 wlist->icon->mapped = 1;
1535 wlist->flags.hidden = 0;
1537 UpdateSwitchMenu(scr, wlist, ACTION_CHANGE_STATE);
1539 if (wlist->frame->workspace != scr->current_workspace)
1540 wWindowChangeWorkspace(wlist, scr->current_workspace);
1542 if (miniwindows) {
1543 wDeiconifyWindow(wlist);
1545 } else if (wlist->flags.hidden) {
1546 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1547 wapp->app_icon->y_pos, wlist,
1548 !wapp->flags.skip_next_animation,
1549 bringToCurrentWS);
1550 } else {
1551 if (bringToCurrentWS
1552 && wlist->frame->workspace != scr->current_workspace) {
1553 wWindowChangeWorkspace(wlist, scr->current_workspace);
1555 wRaiseFrame(wlist->frame->core);
1558 wlist = next;
1561 wapp->flags.skip_next_animation = 0;
1562 wapp->flags.hidden = 0;
1564 if (focused)
1565 wSetFocusTo(scr, focused);
1566 else if (wapp->last_focused && wapp->last_focused->flags.mapped)
1567 wSetFocusTo(scr, wapp->last_focused);
1568 wapp->last_focused = NULL;
1569 if (wPreferences.auto_arrange_icons) {
1570 wArrangeIcons(scr, True);
1572 #ifdef HIDDENDOT
1573 wAppIconPaint(wapp->app_icon);
1574 #endif
1579 void
1580 wShowAllWindows(WScreen *scr)
1582 WWindow *wwin, *old_foc;
1583 WApplication *wapp;
1585 old_foc = wwin = scr->focused_window;
1586 while (wwin) {
1587 if (!wwin->flags.internal_window &&
1588 (scr->current_workspace == wwin->frame->workspace
1589 || IS_OMNIPRESENT(wwin))) {
1590 if (wwin->flags.miniaturized) {
1591 wwin->flags.skip_next_animation = 1;
1592 wDeiconifyWindow(wwin);
1593 } else if (wwin->flags.hidden) {
1594 wapp = wApplicationOf(wwin->main_window);
1595 if (wapp) {
1596 wUnhideApplication(wapp, False, False);
1597 } else {
1598 wwin->flags.skip_next_animation = 1;
1599 wDeiconifyWindow(wwin);
1603 wwin = wwin->prev;
1605 wSetFocusTo(scr, old_foc);
1606 /*wRaiseFrame(old_foc->frame->core);*/
1610 void
1611 wRefreshDesktop(WScreen *scr)
1613 Window win;
1614 XSetWindowAttributes attr;
1616 attr.backing_store = NotUseful;
1617 attr.save_under = False;
1618 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1619 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1620 (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
1621 &attr);
1622 XMapRaised(dpy, win);
1623 XDestroyWindow(dpy, win);
1624 XFlush(dpy);
1628 void
1629 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1631 WWindow *wwin;
1632 WAppIcon *aicon;
1633 int pf; /* primary axis */
1634 int sf; /* secondary axis */
1635 int fullW;
1636 int fullH;
1637 int pi, si;
1638 int sx1, sx2, sy1, sy2; /* screen boundary */
1639 int sw, sh;
1640 int xo, yo;
1641 int xs, ys;
1642 int isize = wPreferences.icon_size;
1645 * Find out screen boundaries.
1647 sx1 = 0;
1648 sy1 = 0;
1649 sx2 = scr->scr_width;
1650 sy2 = scr->scr_height;
1651 if (scr->dock) {
1652 if (scr->dock->on_right_side)
1653 sx2 -= isize + DOCK_EXTRA_SPACE;
1654 else
1655 sx1 += isize + DOCK_EXTRA_SPACE;
1658 sw = isize * (scr->scr_width/isize);
1659 sh = isize * (scr->scr_height/isize);
1660 fullW = (sx2-sx1)/isize;
1661 fullH = (sy2-sy1)/isize;
1663 /* icon yard boundaries */
1664 if (wPreferences.icon_yard & IY_VERT) {
1665 pf = fullH;
1666 sf = fullW;
1667 } else {
1668 pf = fullW;
1669 sf = fullH;
1671 if (wPreferences.icon_yard & IY_RIGHT) {
1672 xo = sx2 - isize;
1673 xs = -1;
1674 } else {
1675 xo = sx1;
1676 xs = 1;
1678 if (wPreferences.icon_yard & IY_TOP) {
1679 yo = sy1;
1680 ys = 1;
1681 } else {
1682 yo = sy2 - isize;
1683 ys = -1;
1686 /* arrange icons putting the most recently focused window
1687 * as the last icon */
1688 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1689 : xo + xs*(pi*isize))
1690 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1691 : yo + ys*(si*isize))
1693 /* arrange application icons */
1694 aicon = scr->app_icon_list;
1695 /* reverse them to avoid unnecessarily sliding of icons */
1696 while (aicon && aicon->next)
1697 aicon = aicon->next;
1699 pi = 0;
1700 si = 0;
1701 while (aicon) {
1702 if (!aicon->docked) {
1703 if (aicon->x_pos != X || aicon->y_pos != Y) {
1704 #ifdef ANIMATIONS
1705 if (!wPreferences.no_animations) {
1706 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1707 X, Y);
1709 #endif /* ANIMATIONS */
1711 wAppIconMove(aicon, X, Y);
1712 pi++;
1714 /* we reversed the order so we use prev */
1715 aicon = aicon->prev;
1716 if (pi >= pf) {
1717 pi=0;
1718 si++;
1722 /* arrange miniwindows */
1724 wwin = scr->focused_window;
1725 /* reverse them to avoid unnecessarily shuffling */
1726 while (wwin && wwin->prev)
1727 wwin = wwin->prev;
1729 while (wwin) {
1730 if (wwin->icon && wwin->flags.miniaturized &&/*!wwin->flags.hidden &&*/
1731 (wwin->frame->workspace==scr->current_workspace ||
1732 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1734 if (arrangeAll || !wwin->flags.icon_moved) {
1735 if (wwin->icon_x != X || wwin->icon_y != Y) {
1736 #ifdef ANIMATIONS
1737 if (wPreferences.no_animations) {
1738 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1739 } else {
1740 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1741 wwin->icon_y, X, Y);
1743 #else
1744 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1745 #endif /* ANIMATIONS */
1747 wwin->icon_x = X;
1748 wwin->icon_y = Y;
1749 pi++;
1752 if (arrangeAll) {
1753 wwin->flags.icon_moved = 0;
1755 /* we reversed the order, so we use next */
1756 wwin = wwin->next;
1757 if (pi >= pf) {
1758 pi=0;
1759 si++;
1765 void
1766 wSelectWindow(WWindow *wwin, Bool flag)
1768 WScreen *scr = wwin->screen_ptr;
1769 if (flag) {
1770 wwin->flags.selected = 1;
1771 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1772 scr->selected_windows = list_cons(wwin, scr->selected_windows);
1773 } else {
1774 wwin->flags.selected = 0;
1775 XSetWindowBorder(dpy, wwin->frame->core->window,
1776 scr->frame_border_pixel);
1777 scr->selected_windows = list_remove_elem(scr->selected_windows, wwin);
1782 void
1783 wMakeWindowVisible(WWindow *wwin)
1785 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
1786 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1788 if (wwin->flags.shaded) {
1789 wUnshadeWindow(wwin);
1791 if (wwin->flags.hidden) {
1792 WApplication *app;
1794 app = wApplicationOf(wwin->main_window);
1795 if (app)
1796 wUnhideApplication(app, False, False);
1797 } else if (wwin->flags.miniaturized) {
1798 wDeiconifyWindow(wwin);
1799 } else {
1800 if (!WFLAGP(wwin, no_focusable))
1801 wSetFocusTo(wwin->screen_ptr, wwin);
1802 wRaiseFrame(wwin->frame->core);