Window Maker 0.20.3
[wmaker-crm.git] / src / actions.c
blobe13b3422c4e9ecfe0125e2167504eede47a8b422
1 /* action.c- misc. window commands (miniaturize, hide etc.)
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
22 #include "wconfig.h"
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <math.h>
30 #include <time.h>
32 #include "WindowMaker.h"
33 #include "wcore.h"
34 #include "framewin.h"
35 #include "window.h"
36 #include "client.h"
37 #include "icon.h"
38 #include "funcs.h"
39 #include "application.h"
40 #include "actions.h"
41 #include "stacking.h"
42 #include "appicon.h"
43 #include "dock.h"
44 #include "appmenu.h"
45 #include "winspector.h"
46 #include "list.h"
47 #include "workspace.h"
49 #ifdef WMSOUND
50 #include "wmsound.h"
51 #endif
54 /****** Global Variables ******/
55 extern Time LastTimestamp;
56 extern Time LastFocusChange;
58 extern Cursor wCursor[WCUR_LAST];
60 extern WPreferences wPreferences;
62 extern Atom _XA_WM_TAKE_FOCUS;
64 /******* Local Variables *******/
65 static struct {
66 int steps;
67 int delay;
68 } shadePars[5] = {
69 {SHADE_STEPS_UF, SHADE_DELAY_UF},
70 {SHADE_STEPS_F, SHADE_DELAY_F},
71 {SHADE_STEPS_M, SHADE_DELAY_M},
72 {SHADE_STEPS_S, SHADE_DELAY_S},
73 {SHADE_STEPS_U, SHADE_DELAY_U}};
75 #define SHADE_STEPS shadePars[(int)wPreferences.shade_speed].steps
76 #define SHADE_DELAY shadePars[(int)wPreferences.shade_speed].delay
79 static int ignoreTimestamp=0;
82 #ifdef ANIMATIONS
83 static void
84 processEvents(int event_count)
86 XEvent event;
89 * This is a hack. When animations are enabled, processing of
90 * events ocurred during a animation are delayed until it's end.
91 * Calls that consider the TimeStamp, like XSetInputFocus(), will
92 * fail because the TimeStamp is too old. Then, for example, if
93 * the user changes window focus while a miniaturize animation is
94 * in course, the window will not get focus properly after the end
95 * of the animation. This tries to workaround it by passing CurrentTime
96 * as the TimeStamp for XSetInputFocus() for all events ocurred during
97 * the animation.
99 ignoreTimestamp=1;
100 while (event_count--) {
101 WMNextEvent(dpy, &event);
102 WMHandleEvent(&event);
104 ignoreTimestamp=0;
106 #endif /* ANIMATIONS */
110 *----------------------------------------------------------------------
111 * wSetFocusTo--
112 * Changes the window focus to the one passed as argument.
113 * If the window to focus is not already focused, it will be brought
114 * to the head of the list of windows. Previously focused window is
115 * unfocused.
117 * Side effects:
118 * Window list may be reordered and the window focus is changed.
120 *----------------------------------------------------------------------
122 void
123 wSetFocusTo(WScreen *scr, WWindow *wwin)
125 WWindow *focused=scr->focused_window;
126 WWindow *owner = NULL;
127 int timestamp=LastTimestamp;
128 WApplication *oapp=NULL, *napp=NULL;
129 int wasfocused;
131 LastFocusChange = timestamp;
133 if (ignoreTimestamp)
134 timestamp=CurrentTime;
136 if (focused)
137 oapp = wApplicationOf(focused->main_window);
139 if (wwin==NULL) {
140 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
141 if (focused) {
142 wWindowUnfocus(focused);
144 if (oapp) {
145 wAppMenuUnmap(oapp->menu);
146 #ifdef NEWAPPICON
147 wApplicationDeactivate(oapp);
148 #endif
150 return;
152 wasfocused = wwin->flags.focused;
153 napp = wApplicationOf(wwin->main_window);
155 /* remember last workspace where the app has been */
156 if (napp)
157 napp->last_workspace = wwin->screen_ptr->current_workspace;
159 if (wwin->window_flags.no_focusable)
160 return;
162 if (wwin->flags.mapped) {
163 /* install colormap if colormap mode is lock mode */
164 if (wPreferences.colormap_mode==WKF_CLICK)
165 wColormapInstallForWindow(scr, wwin);
167 /* set input focus */
168 switch (wwin->focus_mode) {
169 case WFM_NO_INPUT:
170 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
171 break;
173 case WFM_PASSIVE:
174 case WFM_LOCALLY_ACTIVE:
175 XSetInputFocus(dpy, wwin->client_win, RevertToParent, timestamp);
176 break;
178 case WFM_GLOBALLY_ACTIVE:
179 break;
181 XFlush(dpy);
182 if (wwin->protocols.TAKE_FOCUS) {
183 wClientSendProtocol(wwin, _XA_WM_TAKE_FOCUS, timestamp);
185 XSync(dpy, False);
186 } else {
187 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
190 /* if this is not the focused window focus it */
191 if (focused!=wwin) {
192 int foo=0;
194 if (wwin->client_win == focused->transient_for)
195 wwin->flags.semi_focused = 0;
196 else if (wwin->transient_for == focused->client_win)
197 focused->flags.semi_focused = 1;
199 if (wwin->transient_for
200 && wwin->transient_for == focused->transient_for) {
201 owner = wWindowFor(wwin->transient_for);
202 if (owner && owner->flags.semi_focused) {
203 foo=1;
204 /* this is to override the unfocusing of the mainwindow
205 * in the next wWindowUnfocus() and avoid flickering */
206 owner->flags.semi_focused = 0;
209 /* unfocus previous window */
210 wWindowUnfocus(focused);
211 if (foo) {
212 owner->flags.semi_focused = 1;
214 /* change the focus window list order */
215 if (wwin->prev)
216 wwin->prev->next=wwin->next;
217 if (wwin->next)
218 wwin->next->prev=wwin->prev;
220 wwin->prev = focused;
221 focused->next = wwin;
222 wwin->next = NULL;
223 scr->focused_window = wwin;
225 if (oapp && oapp != napp) {
226 wAppMenuUnmap(oapp->menu);
227 #ifdef NEWAPPICON
228 wApplicationDeactivate(oapp);
229 #endif
232 if ((owner=wWindowFor(wwin->transient_for))
233 && !owner->flags.semi_focused) {
234 owner->flags.semi_focused = 1;
235 wWindowUnfocus(owner);
237 wWindowFocus(wwin);
238 if (napp && !wasfocused) {
239 wAppMenuMap(napp->menu, wwin);
240 #ifdef NEWAPPICON
241 wApplicationActivate(napp);
242 #endif
244 XFlush(dpy);
248 void
249 wShadeWindow(WWindow *wwin)
251 XWindowAttributes attribs;
252 time_t time0 = time(NULL);
253 #ifdef ANIMATIONS
254 int y, s, w, h;
255 #endif
257 if (wwin->flags.shaded)
258 return;
260 XLowerWindow(dpy, wwin->client_win);
262 #ifdef WMSOUND
263 wSoundPlay(WMSOUND_SHADE);
264 #endif
266 #ifdef ANIMATIONS
267 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
268 && !wPreferences.no_animations) {
269 /* do the shading animation */
270 h = wwin->frame->core->height;
271 s = h/SHADE_STEPS;
272 if (s < 1) s=1;
273 w = wwin->frame->core->width;
274 y = wwin->frame->top_width;
275 while (h>wwin->frame->top_width+1) {
276 XMoveWindow(dpy, wwin->client_win, 0, y);
277 XResizeWindow(dpy, wwin->frame->core->window, w, h);
278 XFlush(dpy);
280 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
281 break;
283 if (SHADE_DELAY > 0)
284 wusleep(SHADE_DELAY*1000L);
285 h-=s;
286 y-=s;
288 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
290 #endif /* ANIMATIONS */
293 wwin->flags.skip_next_animation = 0;
294 XGetWindowAttributes(dpy, wwin->client_win, &attribs);
295 wwin->flags.shaded=1;
296 wwin->flags.mapped=0;
297 /* prevent window withdrawal when getting UnmapNotify */
298 XSelectInput(dpy, wwin->client_win,
299 attribs.your_event_mask & ~StructureNotifyMask);
300 XUnmapWindow(dpy, wwin->client_win);
301 XSelectInput(dpy, wwin->client_win, attribs.your_event_mask);
303 /* for the client it's just like iconification */
304 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
305 wwin->frame->top_width-1);
307 wClientSetState(wwin, IconicState, None);
310 /* update window list to reflect shaded state */
311 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
313 #ifdef ANIMATIONS
314 if (!wwin->screen_ptr->flags.startup) {
315 /* Look at processEvents() for reason of this code. */
316 XSync(dpy, 0);
317 processEvents(XPending(dpy));
319 #endif
323 void
324 wUnshadeWindow(WWindow *wwin)
326 time_t time0 = time(NULL);
327 #ifdef ANIMATIONS
328 int y, s, w, h;
329 #endif /* ANIMATIONS */
332 if (!wwin->flags.shaded)
333 return;
335 wwin->flags.shaded=0;
336 wwin->flags.mapped=1;
337 XMapWindow(dpy, wwin->client_win);
339 #ifdef WMSOUND
340 wSoundPlay(WMSOUND_UNSHADE);
341 #endif
343 #ifdef ANIMATIONS
344 if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) {
345 /* do the shading animation */
346 h = wwin->frame->top_width + wwin->frame->bottom_width;
347 y = wwin->frame->top_width - wwin->client.height;
348 s = abs(y)/SHADE_STEPS;
349 if (s<1) s=1;
350 w = wwin->frame->core->width;
351 XMoveWindow(dpy, wwin->client_win, 0, y);
352 if (s>0) {
353 while (h < wwin->client.height + wwin->frame->top_width
354 + wwin->frame->bottom_width) {
355 XResizeWindow(dpy, wwin->frame->core->window, w, h);
356 XMoveWindow(dpy, wwin->client_win, 0, y);
357 XSync(dpy, 0);
358 if (SHADE_DELAY > 0)
359 wusleep(SHADE_DELAY*2000L/3);
360 h+=s;
361 y+=s;
363 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
364 break;
367 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
369 #endif /* ANIMATIONS */
372 wwin->flags.skip_next_animation = 0;
373 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
374 wwin->frame->top_width + wwin->client.height
375 + wwin->frame->bottom_width);
377 wClientSetState(wwin, NormalState, None);
379 /* if the window is focused, set the focus again as it was disabled during
380 * shading */
381 if (wwin->flags.focused)
382 wSetFocusTo(wwin->screen_ptr, wwin);
384 /* update window list to reflect unshaded state */
385 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
389 void
390 wMaximizeWindow(WWindow *wwin, int directions)
392 int new_width, new_height, new_x, new_y;
394 if (wwin->flags.shaded) {
395 wwin->flags.skip_next_animation = 1;
396 wUnshadeWindow(wwin);
398 wwin->flags.maximized = directions;
399 wwin->old_geometry.width = wwin->client.width;
400 wwin->old_geometry.height = wwin->client.height;
401 wwin->old_geometry.x = wwin->frame_x;
402 wwin->old_geometry.y = wwin->frame_y;
403 if (directions & MAX_HORIZONTAL) {
404 new_width = wwin->screen_ptr->scr_width-FRAME_BORDER_WIDTH*2;
406 new_x = 0;
407 if ((wPreferences.icon_yard & IY_VERT)
408 && wPreferences.no_window_over_icons) {
410 new_width -= wPreferences.icon_size;
411 if (!(wPreferences.icon_yard & IY_RIGHT))
412 new_x += wPreferences.icon_size;
415 if (wwin->screen_ptr->dock
416 && (!wwin->screen_ptr->dock->lowered
417 || wPreferences.no_window_over_dock)) {
419 new_width -= wPreferences.icon_size + DOCK_EXTRA_SPACE;
420 if (!wwin->screen_ptr->dock->on_right_side)
421 new_x += wPreferences.icon_size + DOCK_EXTRA_SPACE;
423 } else {
424 new_x = wwin->frame_x;
425 new_width = wwin->frame->core->width;
428 if (directions & MAX_VERTICAL) {
429 new_height = wwin->screen_ptr->scr_height-FRAME_BORDER_WIDTH*2;
430 new_y = 0;
431 if (!(wPreferences.icon_yard & IY_VERT)
432 && wPreferences.no_window_over_icons) {
434 new_height -= wPreferences.icon_size;
436 if (wPreferences.icon_yard & IY_TOP)
437 new_y += wPreferences.icon_size;
439 } else {
440 new_y = wwin->frame_y;
441 new_height = wwin->frame->core->height;
443 new_height -= wwin->frame->top_width+wwin->frame->bottom_width;
445 wWindowConstrainSize(wwin, &new_width, &new_height);
446 wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
448 #ifdef WMSOUND
449 wSoundPlay(WMSOUND_MAXIMIZE);
450 #endif
454 void
455 wUnmaximizeWindow(WWindow *wwin)
457 int restore_x, restore_y;
459 if (wwin->flags.shaded) {
460 wwin->flags.skip_next_animation = 1;
461 wUnshadeWindow(wwin);
463 restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ?
464 wwin->old_geometry.x : wwin->frame_x;
465 restore_y = (wwin->flags.maximized & MAX_VERTICAL) ?
466 wwin->old_geometry.y : wwin->frame_y;
467 wwin->flags.maximized = 0;
468 wWindowConfigure(wwin, restore_x, restore_y,
469 wwin->old_geometry.width, wwin->old_geometry.height);
471 #ifdef WMSOUND
472 wSoundPlay(WMSOUND_UNMAXIMIZE);
473 #endif
476 #ifdef ANIMATIONS
477 static void
478 animateResizeFlip(WScreen *scr, int x, int y, int w, int h,
479 int fx, int fy, int fw, int fh, int steps)
481 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
482 float cx, cy, cw, ch;
483 float xstep, ystep, wstep, hstep;
484 XPoint points[5];
485 float dx, dch, midy;
486 float angle, final_angle, delta;
488 xstep = (float)(fx-x)/steps;
489 ystep = (float)(fy-y)/steps;
490 wstep = (float)(fw-w)/steps;
491 hstep = (float)(fh-h)/steps;
493 cx = (float)x;
494 cy = (float)y;
495 cw = (float)w;
496 ch = (float)h;
498 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F;
499 delta = (float)(final_angle/FRAMES);
500 for (angle=0;; angle+=delta) {
501 if (angle > final_angle)
502 angle = final_angle;
504 dx = (cw/10) - ((cw/5) * sin(angle));
505 dch = (ch/2) * cos(angle);
506 midy = cy + (ch/2);
508 points[0].x = cx + dx; points[0].y = midy - dch;
509 points[1].x = cx + cw - dx; points[1].y = points[0].y;
510 points[2].x = cx + cw + dx; points[2].y = midy + dch;
511 points[3].x = cx - dx; points[3].y = points[2].y;
512 points[4].x = points[0].x; points[4].y = points[0].y;
514 XGrabServer(dpy);
515 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
516 XFlush(dpy);
517 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
518 wusleep(MINIATURIZE_ANIMATION_DELAY_F);
519 #endif
521 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
522 XUngrabServer(dpy);
523 cx+=xstep;
524 cy+=ystep;
525 cw+=wstep;
526 ch+=hstep;
527 if (angle >= final_angle)
528 break;
531 XFlush(dpy);
533 #undef FRAMES
536 static void
537 animateResizeTwist(WScreen *scr, int x, int y, int w, int h,
538 int fx, int fy, int fw, int fh, int steps)
540 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
541 float cx, cy, cw, ch;
542 float xstep, ystep, wstep, hstep;
543 XPoint points[5];
544 float angle, final_angle, a, d, delta;
546 x += w/2;
547 y += h/2;
548 fx += fw/2;
549 fy += fh/2;
551 xstep = (float)(fx-x)/steps;
552 ystep = (float)(fy-y)/steps;
553 wstep = (float)(fw-w)/steps;
554 hstep = (float)(fh-h)/steps;
556 cx = (float)x;
557 cy = (float)y;
558 cw = (float)w;
559 ch = (float)h;
561 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T;
562 delta = (float)(final_angle/FRAMES);
563 for (angle=0;; angle+=delta) {
564 if (angle > final_angle)
565 angle = final_angle;
567 a = atan(ch/cw);
568 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
570 points[0].x = cx+cos(angle-a)*d;
571 points[0].y = cy+sin(angle-a)*d;
572 points[1].x = cx+cos(angle+a)*d;
573 points[1].y = cy+sin(angle+a)*d;
574 points[2].x = cx+cos(angle-a+WM_PI)*d;
575 points[2].y = cy+sin(angle-a+WM_PI)*d;
576 points[3].x = cx+cos(angle+a+WM_PI)*d;
577 points[3].y = cy+sin(angle+a+WM_PI)*d;
578 points[4].x = cx+cos(angle-a)*d;
579 points[4].y = cy+sin(angle-a)*d;
580 XGrabServer(dpy);
581 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
582 XFlush(dpy);
583 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
584 wusleep(MINIATURIZE_ANIMATION_DELAY_T);
585 #endif
587 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
588 XUngrabServer(dpy);
589 cx+=xstep;
590 cy+=ystep;
591 cw+=wstep;
592 ch+=hstep;
593 if (angle >= final_angle)
594 break;
597 XFlush(dpy);
599 #undef FRAMES
602 static void
603 animateResizeZoom(WScreen *scr, int x, int y, int w, int h,
604 int fx, int fy, int fw, int fh, int steps)
606 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
607 float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
608 float xstep, ystep, wstep, hstep;
609 int i, j;
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 for (j=0; j<FRAMES; j++) {
617 cx[j] = (float)x;
618 cy[j] = (float)y;
619 cw[j] = (float)w;
620 ch[j] = (float)h;
622 XGrabServer(dpy);
623 for (i=0; i<steps; i++) {
624 for (j=0; j<FRAMES; j++) {
625 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
626 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
628 XFlush(dpy);
629 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
630 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
631 #endif
632 for (j=0; j<FRAMES; j++) {
633 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
634 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
635 if (j<FRAMES-1) {
636 cx[j]=cx[j+1];
637 cy[j]=cy[j+1];
638 cw[j]=cw[j+1];
639 ch[j]=ch[j+1];
640 } else {
641 cx[j]+=xstep;
642 cy[j]+=ystep;
643 cw[j]+=wstep;
644 ch[j]+=hstep;
649 for (j=0; j<FRAMES; j++) {
650 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
651 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
653 XFlush(dpy);
654 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
655 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
656 #endif
657 for (j=0; j<FRAMES; j++) {
658 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
659 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
662 XUngrabServer(dpy);
664 #undef FRAMES
667 static void
668 animateResize(WScreen *scr, int x, int y, int w, int h,
669 int fx, int fy, int fw, int fh, int hiding)
671 int style = wPreferences.iconification_style; /* Catch the value */
672 int steps, k;
674 if (style == WIS_NONE)
675 return;
677 if (style == WIS_RANDOM) {
678 style = rand()%3;
681 k = (hiding ? 2 : 3);
682 switch(style) {
683 case WIS_TWIST:
684 steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
685 if (steps>0)
686 animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
687 break;
688 case WIS_FLIP:
689 steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
690 if (steps>0)
691 animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
692 break;
693 case WIS_ZOOM:
694 default:
695 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
696 if (steps>0)
697 animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
698 break;
701 #endif /* ANIMATIONS */
704 static void
705 flushExpose()
707 XEvent tmpev;
709 while (XCheckTypedEvent(dpy, Expose, &tmpev))
710 WMHandleEvent(&tmpev);
711 XSync(dpy, 0);
714 static void
715 unmapTransientsFor(WWindow *wwin)
717 WWindow *tmp;
718 XWindowAttributes attribs;
721 tmp = wwin->screen_ptr->focused_window;
722 while (tmp) {
723 /* unmap the transients for this transient */
724 if (tmp!=wwin && tmp->transient_for == wwin->client_win
725 && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
726 || tmp->flags.shaded)) {
727 unmapTransientsFor(tmp);
728 XGetWindowAttributes(dpy, tmp->client_win, &attribs);
729 tmp->flags.miniaturized=1;
730 if (!tmp->flags.shaded) {
731 tmp->flags.mapped=0;
732 XSelectInput(dpy, tmp->client_win,
733 attribs.your_event_mask & ~StructureNotifyMask);
734 XUnmapWindow(dpy, tmp->client_win);
735 XSelectInput(dpy, tmp->client_win, attribs.your_event_mask);
737 XUnmapWindow(dpy, tmp->frame->core->window);
738 if (!tmp->flags.shaded)
739 wClientSetState(tmp, IconicState, None);
740 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
742 tmp = tmp->prev;
747 static void
748 mapTransientsFor(WWindow *wwin)
750 WWindow *tmp;
752 tmp = wwin->screen_ptr->focused_window;
753 while (tmp) {
754 /* recursively map the transients for this transient */
755 if (tmp!=wwin && tmp->transient_for == wwin->client_win
756 && /*!tmp->flags.mapped*/ tmp->flags.miniaturized
757 && tmp->icon==NULL) {
758 mapTransientsFor(tmp);
759 tmp->flags.miniaturized=0;
760 if (!tmp->flags.shaded) {
761 tmp->flags.mapped=1;
762 XMapWindow(dpy, tmp->client_win);
764 XMapWindow(dpy, tmp->frame->core->window);
765 tmp->flags.semi_focused = 0;
766 if (!tmp->flags.shaded)
767 wClientSetState(tmp, NormalState, None);
768 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
770 tmp = tmp->prev;
775 static void
776 setupIconGrabs(WIcon *icon)
778 /* setup passive grabs on the icon */
779 XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
780 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
781 XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
782 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
783 XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
784 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
785 XSync(dpy, 0);
789 static WWindow*
790 recursiveTransientFor(WWindow *wwin)
792 int i;
794 if (!wwin)
795 return None;
797 /* hackish way to detect transient_for cycle */
798 i = wwin->screen_ptr->window_count+1;
800 while (wwin && wwin->transient_for != None && i>0) {
801 wwin = wWindowFor(wwin->transient_for);
802 i--;
804 if (i==0 && wwin) {
805 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
806 wwin->frame->title);
807 return NULL;
810 return wwin;
814 static void
815 removeIconGrabs(WIcon *icon)
817 /* remove passive grabs on the icon */
818 XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
819 XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
820 XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);
821 XSync(dpy, 0);
825 void
826 wIconifyWindow(WWindow *wwin)
828 XWindowAttributes attribs;
829 int present;
832 if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
833 /* the window doesn't exist anymore */
834 return;
837 if (wwin->flags.miniaturized)
838 return;
840 if (wwin->transient_for!=None) {
841 WWindow *owner = wWindowFor(wwin->transient_for);
843 if (owner && owner->flags.miniaturized)
844 return;
847 present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
849 /* if the window is in another workspace, simplify process */
850 if (present) {
851 /* icon creation may take a while */
852 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
853 ButtonMotionMask|ButtonReleaseMask, GrabModeAsync,
854 GrabModeAsync, None, None, CurrentTime);
857 if (!wwin->flags.icon_moved) {
858 PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y);
860 wwin->icon = wIconCreate(wwin);
862 wwin->flags.miniaturized=1;
863 wwin->flags.mapped=0;
865 /* unmap transients */
867 unmapTransientsFor(wwin);
869 if (present) {
870 #ifdef WMSOUND
871 wSoundPlay(WMSOUND_ICONIFY);
872 #endif
874 XUngrabPointer(dpy, CurrentTime);
875 /* prevent window withdrawal when getting UnmapNotify */
876 XSelectInput(dpy, wwin->client_win,
877 attribs.your_event_mask & ~StructureNotifyMask);
878 XUnmapWindow(dpy, wwin->client_win);
879 XSelectInput(dpy, wwin->client_win, attribs.your_event_mask);
880 XUnmapWindow(dpy, wwin->frame->core->window);
881 /* let all Expose events arrive so that we can repaint
882 * something before the animation starts (and the server is grabbed) */
883 XSync(dpy, 0);
884 wClientSetState(wwin, IconicState, wwin->icon->icon_win);
885 flushExpose();
886 #ifdef ANIMATIONS
887 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
888 && !wPreferences.no_animations) {
889 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
890 wwin->frame->core->width, wwin->frame->core->height,
891 wwin->icon_x, wwin->icon_y,
892 wwin->icon->core->width, wwin->icon->core->height,
893 False);
895 #endif
898 wwin->flags.skip_next_animation = 0;
899 if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
900 wwin->window_flags.omnipresent || wPreferences.sticky_icons)
901 XMapWindow(dpy, wwin->icon->core->window);
902 AddToStackList(wwin->icon->core);
904 wLowerFrame(wwin->icon->core);
906 if (present) {
907 WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
908 setupIconGrabs(wwin->icon);
909 if ((wwin->flags.focused
910 || (owner && wwin->client_win == owner->client_win))
911 && wPreferences.focus_mode==WKF_CLICK) {
912 WWindow *tmp;
914 tmp = wwin->prev;
915 while (tmp) {
916 if (!tmp->window_flags.no_focusable
917 && !(tmp->flags.hidden||tmp->flags.miniaturized))
918 break;
919 tmp = tmp->prev;
921 wSetFocusTo(wwin->screen_ptr, tmp);
922 } else if (wPreferences.focus_mode!=WKF_CLICK) {
923 wSetFocusTo(wwin->screen_ptr, NULL);
926 #ifdef ANIMATIONS
927 if (!wwin->screen_ptr->flags.startup) {
928 Window clientwin = wwin->client_win;
930 XSync(dpy, 0);
931 processEvents(XPending(dpy));
933 /* the window can disappear while doing the processEvents() */
934 if (!wWindowFor(clientwin))
935 return;
937 #endif
941 if (wwin->flags.selected)
942 wIconSelect(wwin->icon);
944 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
950 void
951 wDeiconifyWindow(WWindow *wwin)
953 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
955 if (!wwin->flags.miniaturized)
956 return;
958 if (wwin->transient_for != None) {
959 WWindow *owner = recursiveTransientFor(wwin);
960 wDeiconifyWindow(owner);
961 wSetFocusTo(wwin->screen_ptr, wwin);
962 wRaiseFrame(wwin->frame->core);
963 return;
966 wwin->flags.miniaturized=0;
967 if (!wwin->flags.shaded)
968 wwin->flags.mapped=1;
970 if (wwin->icon->selected)
971 wIconSelect(wwin->icon);
973 XUnmapWindow(dpy, wwin->icon->core->window);
975 #ifdef WMSOUND
976 wSoundPlay(WMSOUND_DEICONIFY);
977 #endif
979 /* if the window is in another workspace, do it silently */
980 #ifdef ANIMATIONS
981 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
982 && !wwin->flags.skip_next_animation) {
983 animateResize(wwin->screen_ptr, wwin->icon_x, wwin->icon_y,
984 wwin->icon->core->width, wwin->icon->core->height,
985 wwin->frame_x, wwin->frame_y,
986 wwin->frame->core->width, wwin->frame->core->height,
987 False);
989 #endif /* ANIMATIONS */
990 wwin->flags.skip_next_animation = 0;
991 XGrabServer(dpy);
992 if (!wwin->flags.shaded) {
993 XMapWindow(dpy, wwin->client_win);
995 XMapWindow(dpy, wwin->frame->core->window);
996 wRaiseFrame(wwin->frame->core);
997 if (!wwin->flags.shaded) {
998 wClientSetState(wwin, NormalState, None);
1000 mapTransientsFor(wwin);
1001 RemoveFromStackList(wwin->icon->core);
1002 removeIconGrabs(wwin->icon);
1003 wIconDestroy(wwin->icon);
1004 wwin->icon = NULL;
1006 XUngrabServer(dpy);
1007 if (wPreferences.focus_mode==WKF_CLICK
1008 || wPreferences.focus_mode==WKF_SLOPPY)
1009 wSetFocusTo(wwin->screen_ptr, wwin);
1011 #ifdef ANIMATIONS
1012 if (!wwin->screen_ptr->flags.startup) {
1013 Window clientwin = wwin->client_win;
1015 XSync(dpy, 0);
1016 processEvents(XPending(dpy));
1018 if (!wWindowFor(clientwin))
1019 return;
1021 #endif
1023 if (wPreferences.auto_arrange_icons) {
1024 wArrangeIcons(wwin->screen_ptr, True);
1027 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1033 static void
1034 hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
1036 XWindowAttributes attribs;
1039 if (wwin->flags.miniaturized) {
1040 XUnmapWindow(dpy, wwin->icon->core->window);
1041 wwin->flags.hidden = 1;
1042 wwin->icon->mapped = 0;
1043 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1044 return;
1047 if (wwin->flags.inspector_open) {
1048 WWindow *pwin = wwin->inspector->frame;
1050 XGetWindowAttributes(dpy, pwin->client_win, &attribs);
1051 pwin->flags.hidden = 1;
1052 pwin->flags.mapped = 0;
1053 /* prevent window withdrawal when getting UnmapNotify */
1054 XSelectInput(dpy, pwin->client_win,
1055 attribs.your_event_mask & ~StructureNotifyMask);
1056 XUnmapWindow(dpy, pwin->client_win);
1057 XSelectInput(dpy, pwin->client_win, attribs.your_event_mask);
1059 XUnmapWindow(dpy, pwin->frame->core->window);
1060 wClientSetState(pwin, IconicState, icon->icon_win);
1063 XGetWindowAttributes(dpy, wwin->client_win, &attribs);
1065 wwin->flags.hidden = 1;
1066 wwin->flags.mapped = 0;
1068 /* prevent window withdrawal when getting UnmapNotify */
1069 XSelectInput(dpy, wwin->client_win,
1070 attribs.your_event_mask & ~StructureNotifyMask);
1071 XUnmapWindow(dpy, wwin->client_win);
1072 XSelectInput(dpy, wwin->client_win, attribs.your_event_mask);
1074 XUnmapWindow(dpy, wwin->frame->core->window);
1075 wClientSetState(wwin, IconicState, icon->icon_win);
1076 flushExpose();
1077 #ifdef WMSOUND
1078 wSoundPlay(WMSOUND_HIDE);
1079 #endif
1080 #ifdef ANIMATIONS
1081 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1082 !wwin->flags.skip_next_animation && animate) {
1083 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1084 wwin->frame->core->width, wwin->frame->core->height,
1085 icon_x, icon_y, icon->core->width, icon->core->height,
1086 True);
1088 #endif
1089 wwin->flags.skip_next_animation = 0;
1091 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1096 void
1097 wHideOtherApplications(WWindow *awin)
1099 WWindow *wwin;
1100 WApplication *tapp;
1101 #ifdef REDUCE_APPICONS
1102 char *tinstance, *tclass;
1103 unsigned int brokenwin = 0, match = 0;
1104 #endif
1106 if (!awin)
1107 return;
1108 wwin = awin->screen_ptr->focused_window;
1110 #ifdef REDUCE_APPICONS
1111 if (awin->wm_instance == NULL || awin->wm_class == NULL)
1112 brokenwin++;
1113 #endif
1115 while (wwin) {
1116 if (wwin!=awin
1117 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1118 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1119 && !wwin->flags.internal_window
1120 && (!wwin->flags.inspector_open || wwin->inspector->frame!=awin)
1121 && !wwin->window_flags.no_hide_others) {
1123 #ifdef REDUCE_APPICONS
1124 match = 0;
1125 if (!brokenwin) {
1126 if ((tinstance = wwin->wm_instance) == NULL)
1127 tinstance = "";
1128 if ((tclass = wwin->wm_class) == NULL)
1129 tclass = "";
1130 if ((strcmp(awin->wm_instance, tinstance) == 0) &&
1131 (strcmp(awin->wm_class, tclass) == 0) )
1132 match++;
1134 #endif
1136 if (wwin->main_window==None || wwin->window_flags.no_appicon) {
1137 if (!wwin->window_flags.no_miniaturizable) {
1138 wwin->flags.skip_next_animation = 1;
1139 wIconifyWindow(wwin);
1141 } else if (wwin->main_window!=None
1142 #ifndef REDUCE_APPICONS
1143 && awin->main_window != wwin->main_window) {
1144 #else
1145 && (awin->main_window != wwin->main_window && !match)) {
1146 #endif
1147 tapp = wApplicationOf(wwin->main_window);
1148 if (tapp) {
1149 tapp->flags.skip_next_animation = 1;
1150 wHideApplication(tapp);
1151 } else {
1152 if (!wwin->window_flags.no_miniaturizable) {
1153 wwin->flags.skip_next_animation = 1;
1154 wIconifyWindow(wwin);
1159 wwin = wwin->prev;
1162 wSetFocusTo(awin->screen_ptr, awin);
1168 void
1169 wHideApplication(WApplication *wapp)
1171 #ifdef REDUCE_APPICONS
1172 WApplication *tapp;
1173 char *tinstance, *tclass;
1174 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1175 #endif
1176 WScreen *scr;
1177 WWindow *wlist;
1178 int hadfocus;
1180 if (!wapp) {
1181 wwarning("trying to hide a non grouped window");
1182 return;
1184 if (!wapp->main_window_desc) {
1185 wwarning("group leader not found for window group");
1186 return;
1188 #ifdef REDUCE_APPICONS
1189 if ((wapp->main_window_desc->wm_instance == NULL) ||
1190 (wapp->main_window_desc->wm_class == NULL))
1191 nowmhints++;
1192 #endif
1193 scr = wapp->main_window_desc->screen_ptr;
1194 hadfocus = 0;
1195 wlist = scr->focused_window;
1196 if (!wlist)
1197 return;
1199 if (wlist->main_window == wapp->main_window)
1200 wapp->last_focused = wlist;
1201 else
1202 wapp->last_focused = NULL;
1203 while (wlist) {
1204 #ifdef REDUCE_APPICONS
1205 matchwmhints = matchworkspace = 0;
1206 if (!nowmhints) {
1207 tapp = wApplicationOf(wlist->main_window);
1208 tinstance = tclass = NULL;
1209 if (tapp) {
1210 if (tapp->main_window_desc) {
1211 tinstance = tapp->main_window_desc->wm_instance;
1212 tclass = tapp->main_window_desc->wm_class;
1215 if (tapp == NULL || tinstance == NULL || tclass == NULL) {
1216 /* Should never reach here */
1217 tinstance = "";
1218 tclass = "";
1220 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0) &&
1221 (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1222 matchwmhints++;
1224 if (wlist->frame) {
1225 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1226 matchworkspace++;
1228 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1229 matchworkspace) {
1230 #ifdef I_HATE_THIS
1232 #endif
1233 #else
1234 if (wlist->main_window == wapp->main_window) {
1235 #endif
1236 if (wlist->flags.focused) {
1237 hadfocus = 1;
1239 if (wapp->app_icon)
1240 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1241 wapp->app_icon->y_pos, wlist,
1242 !wapp->flags.skip_next_animation);
1244 wlist = wlist->prev;
1247 wapp->flags.skip_next_animation = 0;
1249 if (hadfocus) {
1250 if (wPreferences.focus_mode==WKF_CLICK) {
1251 wlist = scr->focused_window;
1252 while (wlist) {
1253 if (!wlist->window_flags.no_focusable && !wlist->flags.hidden
1254 && (wlist->flags.mapped || wlist->flags.shaded))
1255 break;
1256 wlist = wlist->prev;
1258 wSetFocusTo(scr, wlist);
1259 } else {
1260 wSetFocusTo(scr, NULL);
1264 wapp->flags.hidden = 1;
1266 if(wPreferences.auto_arrange_icons) {
1267 wArrangeIcons(scr, True);
1274 static void
1275 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1276 int bringToCurrentWS)
1278 if (bringToCurrentWS)
1279 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1281 wwin->flags.hidden=0;
1282 wwin->flags.mapped=1;
1284 #ifdef WMSOUND
1285 wSoundPlay(WMSOUND_UNHIDE);
1286 #endif
1287 #ifdef ANIMATIONS
1288 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1289 && animate) {
1290 animateResize(wwin->screen_ptr, icon_x, icon_y,
1291 icon->core->width, icon->core->height,
1292 wwin->frame_x, wwin->frame_y,
1293 wwin->frame->core->width, wwin->frame->core->height,
1294 True);
1296 #endif
1297 wwin->flags.skip_next_animation = 0;
1298 XMapWindow(dpy, wwin->client_win);
1299 XMapWindow(dpy, wwin->frame->core->window);
1300 wClientSetState(wwin, NormalState, None);
1301 wRaiseFrame(wwin->frame->core);
1302 if (wwin->flags.inspector_open) {
1303 WWindow *pwin = wwin->inspector->frame;
1305 pwin->flags.hidden = 0;
1306 pwin->flags.mapped = 1;
1307 XMapWindow(dpy, pwin->client_win);
1308 XMapWindow(dpy, pwin->frame->core->window);
1309 wClientSetState(pwin, NormalState, None);
1312 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1316 void
1317 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1319 WScreen *scr;
1320 WWindow *wlist, *next;
1321 WWindow *focused=NULL;
1322 #ifdef REDUCE_APPICONS
1323 char *tinstance, *tclass;
1324 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1325 #endif
1327 if (!wapp) {
1328 return;
1331 #ifdef REDUCE_APPICONS
1332 if ((wapp->main_window_desc->wm_class == NULL) ||
1333 (wapp->main_window_desc->wm_instance == NULL))
1334 nowmhints++;
1335 #endif
1337 scr = wapp->main_window_desc->screen_ptr;
1338 wlist = scr->focused_window;
1339 if (!wlist) return;
1340 /* goto beginning of list */
1341 while (wlist->prev)
1342 wlist = wlist->prev;
1344 while (wlist) {
1345 next = wlist->next;
1347 #ifndef REDUCE_APPICONS
1348 if (wlist->main_window == wapp->main_window) {
1349 #else
1350 matchwmhints = matchworkspace = 0;
1351 if (!nowmhints) {
1352 if ((tinstance = wlist->wm_instance) == NULL)
1353 tinstance = "";
1354 if ((tclass = wlist->wm_class) == NULL)
1355 tclass = "";
1356 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0)
1357 && (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1358 matchwmhints++;
1360 if (wlist->frame) {
1361 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1362 matchworkspace++;
1365 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1366 matchworkspace) {
1367 #endif
1368 if (wlist->flags.focused)
1369 focused = wlist;
1370 else if (!focused || !focused->flags.focused)
1371 focused = wlist;
1373 if (wlist->flags.miniaturized && wlist->icon) {
1374 if (bringToCurrentWS || wPreferences.sticky_icons
1375 || wlist->frame->workspace == scr->current_workspace) {
1376 if (!wlist->icon->mapped) {
1377 XMapWindow(dpy, wlist->icon->core->window);
1378 wlist->icon->mapped = 1;
1380 wlist->flags.hidden = 0;
1381 UpdateSwitchMenu(scr, wlist, ACTION_CHANGE_STATE);
1382 if (wlist->frame->workspace != scr->current_workspace)
1383 wWindowChangeWorkspace(wlist, scr->current_workspace);
1385 if (miniwindows) {
1386 wDeiconifyWindow(wlist);
1388 } else if (wlist->flags.hidden) {
1389 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1390 wapp->app_icon->y_pos, wlist,
1391 !wapp->flags.skip_next_animation,
1392 bringToCurrentWS);
1393 } else {
1394 if (bringToCurrentWS
1395 && wlist->frame->workspace != scr->current_workspace) {
1396 wWindowChangeWorkspace(wlist, scr->current_workspace);
1398 wRaiseFrame(wlist->frame->core);
1401 wlist = next;
1404 wapp->flags.skip_next_animation = 0;
1405 wapp->flags.hidden = 0;
1407 if (focused)
1408 wSetFocusTo(scr, focused);
1409 else if (wapp->last_focused && wapp->last_focused->flags.mapped)
1410 wSetFocusTo(scr, wapp->last_focused);
1411 wapp->last_focused = NULL;
1412 if (wPreferences.auto_arrange_icons) {
1413 wArrangeIcons(scr, True);
1419 void
1420 wShowAllWindows(WScreen *scr)
1422 WWindow *wwin, *old_foc;
1423 WApplication *wapp;
1425 old_foc = wwin = scr->focused_window;
1426 while (wwin) {
1427 if (!wwin->flags.internal_window &&
1428 (scr->current_workspace == wwin->frame->workspace
1429 || wwin->window_flags.omnipresent)) {
1430 if (wwin->flags.miniaturized) {
1431 wwin->flags.skip_next_animation = 1;
1432 wDeiconifyWindow(wwin);
1433 } else if (wwin->flags.hidden) {
1434 wapp = wApplicationOf(wwin->main_window);
1435 if (wapp) {
1436 wUnhideApplication(wapp, False, False);
1437 } else {
1438 wwin->flags.skip_next_animation = 1;
1439 wDeiconifyWindow(wwin);
1443 wwin = wwin->prev;
1445 wSetFocusTo(scr, old_foc);
1446 /*wRaiseFrame(old_foc->frame->core);*/
1450 void
1451 wRefreshDesktop(WScreen *scr)
1453 Window win;
1454 XSetWindowAttributes attr;
1456 attr.backing_store = NotUseful;
1457 attr.save_under = False;
1458 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1459 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1460 (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
1461 &attr);
1462 XMapRaised(dpy, win);
1463 XDestroyWindow(dpy, win);
1464 XFlush(dpy);
1468 void
1469 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1471 WWindow *wwin;
1472 WAppIcon *aicon;
1473 int pf; /* primary axis */
1474 int sf; /* secondary axis */
1475 int fullW;
1476 int fullH;
1477 int pi, si;
1478 int sx1, sx2, sy1, sy2; /* screen boundary */
1479 int sw, sh;
1480 int xo, yo;
1481 int xs, ys;
1482 int isize = wPreferences.icon_size;
1485 * Find out screen boundaries.
1487 sx1 = 0;
1488 sy1 = 0;
1489 sx2 = scr->scr_width;
1490 sy2 = scr->scr_height;
1491 if (scr->dock) {
1492 if (scr->dock->on_right_side)
1493 sx2 -= isize + DOCK_EXTRA_SPACE;
1494 else
1495 sx1 += isize + DOCK_EXTRA_SPACE;
1498 sw = isize * (scr->scr_width/isize);
1499 sh = isize * (scr->scr_height/isize);
1500 fullW = (sx2-sx1)/isize;
1501 fullH = (sy2-sy1)/isize;
1503 /* icon yard boundaries */
1504 if (wPreferences.icon_yard & IY_VERT) {
1505 pf = fullH;
1506 sf = fullW;
1507 } else {
1508 pf = fullW;
1509 sf = fullH;
1511 if (wPreferences.icon_yard & IY_RIGHT) {
1512 xo = sx2 - isize;
1513 xs = -1;
1514 } else {
1515 xo = sx1;
1516 xs = 1;
1518 if (wPreferences.icon_yard & IY_TOP) {
1519 yo = sy1;
1520 ys = 1;
1521 } else {
1522 yo = sy2 - isize;
1523 ys = -1;
1526 /* arrange icons putting the most recently focused window
1527 * as the last icon */
1528 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1529 : xo + xs*(pi*isize))
1530 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1531 : yo + ys*(si*isize))
1533 /* arrange application icons */
1534 aicon = scr->app_icon_list;
1535 /* reverse them to avoid unnecessarily sliding of icons */
1536 while (aicon && aicon->next)
1537 aicon = aicon->next;
1539 pi = 0;
1540 si = 0;
1541 while (aicon) {
1542 if (!aicon->docked) {
1543 if (aicon->x_pos != X || aicon->y_pos != Y) {
1544 #ifdef ANIMATIONS
1545 if (!wPreferences.no_animations) {
1546 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1547 X, Y);
1549 #endif /* ANIMATIONS */
1551 wAppIconMove(aicon, X, Y);
1552 pi++;
1554 /* we reversed the order so we use prev */
1555 aicon = aicon->prev;
1556 if (pi >= pf) {
1557 pi=0;
1558 si++;
1562 /* arrange miniwindows */
1564 wwin = scr->focused_window;
1565 /* reverse them to avoid unnecessarily shuffling */
1566 while (wwin && wwin->prev)
1567 wwin = wwin->prev;
1569 while (wwin) {
1570 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1571 (wwin->frame->workspace==scr->current_workspace ||
1572 wwin->window_flags.omnipresent ||
1573 wPreferences.sticky_icons)) {
1575 if (arrangeAll || !wwin->flags.icon_moved) {
1576 if (wwin->icon_x != X || wwin->icon_y != Y) {
1577 #ifdef ANIMATIONS
1578 if (wPreferences.no_animations) {
1579 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1580 } else {
1581 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1582 wwin->icon_y, X, Y);
1584 #else
1585 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1586 #endif /* ANIMATIONS */
1588 wwin->icon_x = X;
1589 wwin->icon_y = Y;
1590 wwin->flags.icon_moved = 0;
1591 pi++;
1594 /* we reversed the order, so we use next */
1595 wwin = wwin->next;
1596 if (pi >= pf) {
1597 pi=0;
1598 si++;
1604 void
1605 wSelectWindow(WWindow *wwin, Bool flag)
1607 WScreen *scr = wwin->screen_ptr;
1608 if (flag) {
1609 wwin->flags.selected = 1;
1610 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1611 scr->selected_windows = list_cons(wwin, scr->selected_windows);
1612 } else {
1613 wwin->flags.selected = 0;
1614 XSetWindowBorder(dpy, wwin->frame->core->window,
1615 scr->frame_border_pixel);
1616 scr->selected_windows = list_remove_elem(scr->selected_windows, wwin);
1621 void
1622 wMakeWindowVisible(WWindow *wwin)
1624 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1626 if (wwin->flags.shaded) {
1627 wUnshadeWindow(wwin);
1629 if (wwin->flags.hidden) {
1630 wUnhideApplication(wApplicationOf(wwin->main_window), False, False);
1631 } else if (wwin->flags.miniaturized) {
1632 wDeiconifyWindow(wwin);
1633 } else {
1634 wSetFocusTo(wwin->screen_ptr, wwin);
1635 wRaiseFrame(wwin->frame->core);