removed broken optiomized selection frame patch
[wmaker-crm.git] / src / actions.c
blobb279542bbcb2efbf71b0a8bd6575fc607fd94682
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 wHideInspectorForWindow(wwin);
1219 wwin->flags.hidden = 1;
1220 wWindowUnmap(wwin);
1222 wClientSetState(wwin, IconicState, icon->icon_win);
1223 flushExpose();
1224 #ifdef WMSOUND
1225 wSoundPlay(WMSOUND_HIDE);
1226 #endif
1227 #ifdef ANIMATIONS
1228 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1229 !wwin->flags.skip_next_animation && animate) {
1230 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1231 wwin->frame->core->width, wwin->frame->core->height,
1232 icon_x, icon_y, icon->core->width, icon->core->height,
1233 True);
1235 #endif
1236 wwin->flags.skip_next_animation = 0;
1238 #ifdef GNOME_STUFF
1239 wGNOMEUpdateClientStateHint(wwin, False);
1240 #endif
1242 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1247 void
1248 wHideOtherApplications(WWindow *awin)
1250 WWindow *wwin;
1251 WApplication *tapp;
1252 #ifdef REDUCE_APPICONS
1253 char *tinstance, *tclass;
1254 unsigned int brokenwin = 0, match = 0;
1255 #endif
1257 if (!awin)
1258 return;
1259 wwin = awin->screen_ptr->focused_window;
1261 #ifdef REDUCE_APPICONS
1262 if (awin->wm_instance == NULL || awin->wm_class == NULL)
1263 brokenwin++;
1264 #endif
1266 while (wwin) {
1267 if (wwin!=awin
1268 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1269 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1270 && !wwin->flags.internal_window
1271 && wGetWindowOfInspectorForWindow(wwin) != awin
1272 && !WFLAGP(wwin, no_hide_others)) {
1274 #ifdef REDUCE_APPICONS
1275 match = 0;
1276 if (!brokenwin) {
1277 if ((tinstance = wwin->wm_instance) == NULL)
1278 tinstance = "";
1279 if ((tclass = wwin->wm_class) == NULL)
1280 tclass = "";
1281 if ((strcmp(awin->wm_instance, tinstance) == 0) &&
1282 (strcmp(awin->wm_class, tclass) == 0) )
1283 match++;
1285 #endif
1287 if (wwin->main_window==None || WFLAGP(wwin, no_appicon)) {
1288 if (!WFLAGP(wwin, no_miniaturizable)) {
1289 wwin->flags.skip_next_animation = 1;
1290 wIconifyWindow(wwin);
1292 } else if (wwin->main_window!=None
1293 #ifndef REDUCE_APPICONS
1294 && awin->main_window != wwin->main_window) {
1295 #else
1296 && (awin->main_window != wwin->main_window && !match)) {
1297 #endif
1298 tapp = wApplicationOf(wwin->main_window);
1299 if (tapp) {
1300 tapp->flags.skip_next_animation = 1;
1301 wHideApplication(tapp);
1302 } else {
1303 if (!WFLAGP(wwin, no_miniaturizable)) {
1304 wwin->flags.skip_next_animation = 1;
1305 wIconifyWindow(wwin);
1310 wwin = wwin->prev;
1313 wSetFocusTo(awin->screen_ptr, awin);
1319 void
1320 wHideApplication(WApplication *wapp)
1322 #ifdef REDUCE_APPICONS
1323 WApplication *tapp;
1324 char *tinstance, *tclass;
1325 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1326 #endif
1327 WScreen *scr;
1328 WWindow *wlist;
1329 int hadfocus;
1331 if (!wapp) {
1332 wwarning("trying to hide a non grouped window");
1333 return;
1335 if (!wapp->main_window_desc) {
1336 wwarning("group leader not found for window group");
1337 return;
1339 #ifdef REDUCE_APPICONS
1340 if ((wapp->main_window_desc->wm_instance == NULL) ||
1341 (wapp->main_window_desc->wm_class == NULL))
1342 nowmhints++;
1343 #endif
1344 scr = wapp->main_window_desc->screen_ptr;
1345 hadfocus = 0;
1346 wlist = scr->focused_window;
1347 if (!wlist)
1348 return;
1350 if (wlist->main_window == wapp->main_window)
1351 wapp->last_focused = wlist;
1352 else
1353 wapp->last_focused = NULL;
1354 while (wlist) {
1355 #ifdef REDUCE_APPICONS
1356 matchwmhints = matchworkspace = 0;
1357 if (!nowmhints) {
1358 tapp = wApplicationOf(wlist->main_window);
1359 tinstance = tclass = NULL;
1360 if (tapp) {
1361 if (tapp->main_window_desc) {
1362 tinstance = tapp->main_window_desc->wm_instance;
1363 tclass = tapp->main_window_desc->wm_class;
1366 if (tapp == NULL || tinstance == NULL || tclass == NULL) {
1367 /* Should never reach here */
1368 tinstance = "";
1369 tclass = "";
1371 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0) &&
1372 (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1373 matchwmhints++;
1375 if (wlist->frame) {
1376 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1377 matchworkspace++;
1379 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1380 matchworkspace) {
1381 #ifdef I_HATE_THIS
1383 #endif
1384 #else
1385 if (wlist->main_window == wapp->main_window) {
1386 #endif
1387 if (wlist->flags.focused) {
1388 hadfocus = 1;
1390 if (wapp->app_icon)
1391 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1392 wapp->app_icon->y_pos, wlist,
1393 !wapp->flags.skip_next_animation);
1395 wlist = wlist->prev;
1398 wapp->flags.skip_next_animation = 0;
1400 if (hadfocus) {
1401 if (wPreferences.focus_mode==WKF_CLICK) {
1402 wlist = scr->focused_window;
1403 while (wlist) {
1404 if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden
1405 && (wlist->flags.mapped || wlist->flags.shaded))
1406 break;
1407 wlist = wlist->prev;
1409 wSetFocusTo(scr, wlist);
1410 } else {
1411 wSetFocusTo(scr, NULL);
1415 wapp->flags.hidden = 1;
1417 if(wPreferences.auto_arrange_icons) {
1418 wArrangeIcons(scr, True);
1420 #ifdef HIDDENDOT
1421 if (wapp->app_icon)
1422 wAppIconPaint(wapp->app_icon);
1423 #endif
1429 static void
1430 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1431 int bringToCurrentWS)
1433 if (bringToCurrentWS)
1434 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1436 wwin->flags.hidden=0;
1437 wwin->flags.mapped=1;
1439 #ifdef WMSOUND
1440 wSoundPlay(WMSOUND_UNHIDE);
1441 #endif
1442 #ifdef ANIMATIONS
1443 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1444 && animate) {
1445 animateResize(wwin->screen_ptr, icon_x, icon_y,
1446 icon->core->width, icon->core->height,
1447 wwin->frame_x, wwin->frame_y,
1448 wwin->frame->core->width, wwin->frame->core->height,
1449 True);
1451 #endif
1452 wwin->flags.skip_next_animation = 0;
1453 XMapWindow(dpy, wwin->client_win);
1454 XMapWindow(dpy, wwin->frame->core->window);
1455 wClientSetState(wwin, NormalState, None);
1456 wRaiseFrame(wwin->frame->core);
1457 if (wwin->flags.inspector_open) {
1458 wUnhideInspectorForWindow(wwin);
1461 #ifdef GNOME_STUFF
1462 wGNOMEUpdateClientStateHint(wwin, False);
1463 #endif
1465 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1470 void
1471 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1473 WScreen *scr;
1474 WWindow *wlist, *next;
1475 WWindow *focused=NULL;
1476 #ifdef REDUCE_APPICONS
1477 char *tinstance, *tclass;
1478 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1479 #endif
1481 if (!wapp) {
1482 return;
1485 #ifdef REDUCE_APPICONS
1486 if ((wapp->main_window_desc->wm_class == NULL) ||
1487 (wapp->main_window_desc->wm_instance == NULL))
1488 nowmhints++;
1489 #endif
1491 scr = wapp->main_window_desc->screen_ptr;
1492 wlist = scr->focused_window;
1493 if (!wlist) return;
1494 /* goto beginning of list */
1495 while (wlist->prev)
1496 wlist = wlist->prev;
1498 while (wlist) {
1499 next = wlist->next;
1501 #ifndef REDUCE_APPICONS
1502 if (wlist->main_window == wapp->main_window) {
1503 #else
1504 matchwmhints = matchworkspace = 0;
1505 if (!nowmhints) {
1506 if ((tinstance = wlist->wm_instance) == NULL)
1507 tinstance = "";
1508 if ((tclass = wlist->wm_class) == NULL)
1509 tclass = "";
1510 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0)
1511 && (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1512 matchwmhints++;
1514 if (wlist->frame) {
1515 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1516 matchworkspace++;
1519 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1520 matchworkspace) {
1521 #endif
1522 if (wlist->flags.focused)
1523 focused = wlist;
1524 else if (!focused || !focused->flags.focused)
1525 focused = wlist;
1527 if (wlist->flags.miniaturized && wlist->icon) {
1528 if (bringToCurrentWS || wPreferences.sticky_icons
1529 || wlist->frame->workspace == scr->current_workspace) {
1530 if (!wlist->icon->mapped) {
1531 XMapWindow(dpy, wlist->icon->core->window);
1532 wlist->icon->mapped = 1;
1534 wlist->flags.hidden = 0;
1536 UpdateSwitchMenu(scr, wlist, ACTION_CHANGE_STATE);
1538 if (wlist->frame->workspace != scr->current_workspace)
1539 wWindowChangeWorkspace(wlist, scr->current_workspace);
1541 if (miniwindows) {
1542 wDeiconifyWindow(wlist);
1544 } else if (wlist->flags.hidden) {
1545 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1546 wapp->app_icon->y_pos, wlist,
1547 !wapp->flags.skip_next_animation,
1548 bringToCurrentWS);
1549 } else {
1550 if (bringToCurrentWS
1551 && wlist->frame->workspace != scr->current_workspace) {
1552 wWindowChangeWorkspace(wlist, scr->current_workspace);
1554 wRaiseFrame(wlist->frame->core);
1557 wlist = next;
1560 wapp->flags.skip_next_animation = 0;
1561 wapp->flags.hidden = 0;
1563 if (focused)
1564 wSetFocusTo(scr, focused);
1565 else if (wapp->last_focused && wapp->last_focused->flags.mapped)
1566 wSetFocusTo(scr, wapp->last_focused);
1567 wapp->last_focused = NULL;
1568 if (wPreferences.auto_arrange_icons) {
1569 wArrangeIcons(scr, True);
1571 #ifdef HIDDENDOT
1572 wAppIconPaint(wapp->app_icon);
1573 #endif
1578 void
1579 wShowAllWindows(WScreen *scr)
1581 WWindow *wwin, *old_foc;
1582 WApplication *wapp;
1584 old_foc = wwin = scr->focused_window;
1585 while (wwin) {
1586 if (!wwin->flags.internal_window &&
1587 (scr->current_workspace == wwin->frame->workspace
1588 || IS_OMNIPRESENT(wwin))) {
1589 if (wwin->flags.miniaturized) {
1590 wwin->flags.skip_next_animation = 1;
1591 wDeiconifyWindow(wwin);
1592 } else if (wwin->flags.hidden) {
1593 wapp = wApplicationOf(wwin->main_window);
1594 if (wapp) {
1595 wUnhideApplication(wapp, False, False);
1596 } else {
1597 wwin->flags.skip_next_animation = 1;
1598 wDeiconifyWindow(wwin);
1602 wwin = wwin->prev;
1604 wSetFocusTo(scr, old_foc);
1605 /*wRaiseFrame(old_foc->frame->core);*/
1609 void
1610 wRefreshDesktop(WScreen *scr)
1612 Window win;
1613 XSetWindowAttributes attr;
1615 attr.backing_store = NotUseful;
1616 attr.save_under = False;
1617 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1618 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1619 (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
1620 &attr);
1621 XMapRaised(dpy, win);
1622 XDestroyWindow(dpy, win);
1623 XFlush(dpy);
1627 void
1628 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1630 WWindow *wwin;
1631 WAppIcon *aicon;
1632 int pf; /* primary axis */
1633 int sf; /* secondary axis */
1634 int fullW;
1635 int fullH;
1636 int pi, si;
1637 int sx1, sx2, sy1, sy2; /* screen boundary */
1638 int sw, sh;
1639 int xo, yo;
1640 int xs, ys;
1641 int isize = wPreferences.icon_size;
1644 * Find out screen boundaries.
1646 sx1 = 0;
1647 sy1 = 0;
1648 sx2 = scr->scr_width;
1649 sy2 = scr->scr_height;
1650 if (scr->dock) {
1651 if (scr->dock->on_right_side)
1652 sx2 -= isize + DOCK_EXTRA_SPACE;
1653 else
1654 sx1 += isize + DOCK_EXTRA_SPACE;
1657 sw = isize * (scr->scr_width/isize);
1658 sh = isize * (scr->scr_height/isize);
1659 fullW = (sx2-sx1)/isize;
1660 fullH = (sy2-sy1)/isize;
1662 /* icon yard boundaries */
1663 if (wPreferences.icon_yard & IY_VERT) {
1664 pf = fullH;
1665 sf = fullW;
1666 } else {
1667 pf = fullW;
1668 sf = fullH;
1670 if (wPreferences.icon_yard & IY_RIGHT) {
1671 xo = sx2 - isize;
1672 xs = -1;
1673 } else {
1674 xo = sx1;
1675 xs = 1;
1677 if (wPreferences.icon_yard & IY_TOP) {
1678 yo = sy1;
1679 ys = 1;
1680 } else {
1681 yo = sy2 - isize;
1682 ys = -1;
1685 /* arrange icons putting the most recently focused window
1686 * as the last icon */
1687 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1688 : xo + xs*(pi*isize))
1689 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1690 : yo + ys*(si*isize))
1692 /* arrange application icons */
1693 aicon = scr->app_icon_list;
1694 /* reverse them to avoid unnecessarily sliding of icons */
1695 while (aicon && aicon->next)
1696 aicon = aicon->next;
1698 pi = 0;
1699 si = 0;
1700 while (aicon) {
1701 if (!aicon->docked) {
1702 if (aicon->x_pos != X || aicon->y_pos != Y) {
1703 #ifdef ANIMATIONS
1704 if (!wPreferences.no_animations) {
1705 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1706 X, Y);
1708 #endif /* ANIMATIONS */
1710 wAppIconMove(aicon, X, Y);
1711 pi++;
1713 /* we reversed the order so we use prev */
1714 aicon = aicon->prev;
1715 if (pi >= pf) {
1716 pi=0;
1717 si++;
1721 /* arrange miniwindows */
1723 wwin = scr->focused_window;
1724 /* reverse them to avoid unnecessarily shuffling */
1725 while (wwin && wwin->prev)
1726 wwin = wwin->prev;
1728 while (wwin) {
1729 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1730 (wwin->frame->workspace==scr->current_workspace ||
1731 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1733 if (arrangeAll || !wwin->flags.icon_moved) {
1734 if (wwin->icon_x != X || wwin->icon_y != Y) {
1735 #ifdef ANIMATIONS
1736 if (wPreferences.no_animations) {
1737 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1738 } else {
1739 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1740 wwin->icon_y, X, Y);
1742 #else
1743 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1744 #endif /* ANIMATIONS */
1746 wwin->icon_x = X;
1747 wwin->icon_y = Y;
1748 pi++;
1751 if (arrangeAll) {
1752 wwin->flags.icon_moved = 0;
1754 /* we reversed the order, so we use next */
1755 wwin = wwin->next;
1756 if (pi >= pf) {
1757 pi=0;
1758 si++;
1764 void
1765 wSelectWindow(WWindow *wwin, Bool flag)
1767 WScreen *scr = wwin->screen_ptr;
1769 if (flag) {
1770 wwin->flags.selected = 1;
1771 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1772 if (!scr->selected_windows)
1773 scr->selected_windows = WMCreateBag(4);
1774 WMPutInBag(scr->selected_windows, wwin);
1775 } else {
1776 wwin->flags.selected = 0;
1777 XSetWindowBorder(dpy, wwin->frame->core->window,
1778 scr->frame_border_pixel);
1779 if (scr->selected_windows) {
1780 WMRemoveFromBag(scr->selected_windows, wwin);
1786 void
1787 wMakeWindowVisible(WWindow *wwin)
1789 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
1790 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1792 if (wwin->flags.shaded) {
1793 wUnshadeWindow(wwin);
1795 if (wwin->flags.hidden) {
1796 WApplication *app;
1798 app = wApplicationOf(wwin->main_window);
1799 if (app)
1800 wUnhideApplication(app, False, False);
1801 } else if (wwin->flags.miniaturized) {
1802 wDeiconifyWindow(wwin);
1803 } else {
1804 if (!WFLAGP(wwin, no_focusable))
1805 wSetFocusTo(wwin->screen_ptr, wwin);
1806 wRaiseFrame(wwin->frame->core);