This update includes the 0.20.3pre3 code
[wmaker-crm.git] / src / actions.c
blobe6ac05014983811a767d8e3dd5bce592ff14dc81
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_under_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 k = (hiding ? 2 : 3);
678 switch(style) {
679 case WIS_TWIST:
680 steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
681 if (steps>0)
682 animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
683 break;
684 case WIS_FLIP:
685 steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
686 if (steps>0)
687 animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
688 break;
689 case WIS_ZOOM:
690 default:
691 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
692 if (steps>0)
693 animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
694 break;
697 #endif /* ANIMATIONS */
700 static void
701 flushExpose()
703 XEvent tmpev;
705 while (XCheckTypedEvent(dpy, Expose, &tmpev))
706 WMHandleEvent(&tmpev);
707 XSync(dpy, 0);
710 static void
711 unmapTransientsFor(WWindow *wwin)
713 WWindow *tmp;
714 XWindowAttributes attribs;
717 tmp = wwin->screen_ptr->focused_window;
718 while (tmp) {
719 /* unmap the transients for this transient */
720 if (tmp!=wwin && tmp->transient_for == wwin->client_win
721 && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
722 || tmp->flags.shaded)) {
723 unmapTransientsFor(tmp);
724 XGetWindowAttributes(dpy, tmp->client_win, &attribs);
725 tmp->flags.miniaturized=1;
726 if (!tmp->flags.shaded) {
727 tmp->flags.mapped=0;
728 XSelectInput(dpy, tmp->client_win,
729 attribs.your_event_mask & ~StructureNotifyMask);
730 XUnmapWindow(dpy, tmp->client_win);
731 XSelectInput(dpy, tmp->client_win, attribs.your_event_mask);
733 XUnmapWindow(dpy, tmp->frame->core->window);
734 if (!tmp->flags.shaded)
735 wClientSetState(tmp, IconicState, None);
736 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
738 tmp = tmp->prev;
743 static void
744 mapTransientsFor(WWindow *wwin)
746 WWindow *tmp;
748 tmp = wwin->screen_ptr->focused_window;
749 while (tmp) {
750 /* recursively map the transients for this transient */
751 if (tmp!=wwin && tmp->transient_for == wwin->client_win
752 && /*!tmp->flags.mapped*/ tmp->flags.miniaturized
753 && tmp->icon==NULL) {
754 mapTransientsFor(tmp);
755 tmp->flags.miniaturized=0;
756 if (!tmp->flags.shaded) {
757 tmp->flags.mapped=1;
758 XMapWindow(dpy, tmp->client_win);
760 XMapWindow(dpy, tmp->frame->core->window);
761 tmp->flags.semi_focused = 0;
762 if (!tmp->flags.shaded)
763 wClientSetState(tmp, NormalState, None);
764 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
766 tmp = tmp->prev;
771 static void
772 setupIconGrabs(WIcon *icon)
774 /* setup passive grabs on the icon */
775 XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
776 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
777 XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
778 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
779 XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
780 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
781 XSync(dpy, 0);
785 static WWindow*
786 recursiveTransientFor(WWindow *wwin)
788 int i;
790 if (!wwin)
791 return None;
793 /* hackish way to detect transient_for cycle */
794 i = wwin->screen_ptr->window_count+1;
796 while (wwin && wwin->transient_for != None && i>0) {
797 wwin = wWindowFor(wwin->transient_for);
798 i--;
800 if (i==0 && wwin) {
801 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
802 wwin->frame->title);
803 return NULL;
806 return wwin;
810 static void
811 removeIconGrabs(WIcon *icon)
813 /* remove passive grabs on the icon */
814 XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
815 XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
816 XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);
817 XSync(dpy, 0);
821 void
822 wIconifyWindow(WWindow *wwin)
824 XWindowAttributes attribs;
825 int present;
828 if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
829 /* the window doesn't exist anymore */
830 return;
833 if (wwin->flags.miniaturized)
834 return;
836 if (wwin->transient_for!=None) {
837 WWindow *owner = wWindowFor(wwin->transient_for);
839 if (owner && owner->flags.miniaturized)
840 return;
843 present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
845 /* if the window is in another workspace, simplify process */
846 if (present) {
847 /* icon creation may take a while */
848 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
849 ButtonMotionMask|ButtonReleaseMask, GrabModeAsync,
850 GrabModeAsync, None, None, CurrentTime);
853 if (!wwin->flags.icon_moved) {
854 PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y);
856 wwin->icon = wIconCreate(wwin);
858 wwin->flags.miniaturized=1;
859 wwin->flags.mapped=0;
861 /* unmap transients */
863 unmapTransientsFor(wwin);
865 if (present) {
866 #ifdef WMSOUND
867 wSoundPlay(WMSOUND_ICONIFY);
868 #endif
870 XUngrabPointer(dpy, CurrentTime);
871 /* prevent window withdrawal when getting UnmapNotify */
872 XSelectInput(dpy, wwin->client_win,
873 attribs.your_event_mask & ~StructureNotifyMask);
874 XUnmapWindow(dpy, wwin->client_win);
875 XSelectInput(dpy, wwin->client_win, attribs.your_event_mask);
876 XUnmapWindow(dpy, wwin->frame->core->window);
877 /* let all Expose events arrive so that we can repaint
878 * something before the animation starts (and the server is grabbed) */
879 XSync(dpy, 0);
880 wClientSetState(wwin, IconicState, wwin->icon->icon_win);
881 flushExpose();
882 #ifdef ANIMATIONS
883 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
884 && !wPreferences.no_animations) {
885 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
886 wwin->frame->core->width, wwin->frame->core->height,
887 wwin->icon_x, wwin->icon_y,
888 wwin->icon->core->width, wwin->icon->core->height,
889 False);
891 #endif
894 wwin->flags.skip_next_animation = 0;
895 if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
896 wwin->window_flags.omnipresent || wPreferences.sticky_icons)
897 XMapWindow(dpy, wwin->icon->core->window);
898 AddToStackList(wwin->icon->core);
900 wLowerFrame(wwin->icon->core);
902 if (present) {
903 WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
904 setupIconGrabs(wwin->icon);
905 if ((wwin->flags.focused
906 || (owner && wwin->client_win == owner->client_win))
907 && wPreferences.focus_mode==WKF_CLICK) {
908 WWindow *tmp;
910 tmp = wwin->prev;
911 while (tmp) {
912 if (!tmp->window_flags.no_focusable
913 && !(tmp->flags.hidden||tmp->flags.miniaturized))
914 break;
915 tmp = tmp->prev;
917 wSetFocusTo(wwin->screen_ptr, tmp);
918 } else if (wPreferences.focus_mode!=WKF_CLICK) {
919 wSetFocusTo(wwin->screen_ptr, NULL);
922 #ifdef ANIMATIONS
923 if (!wwin->screen_ptr->flags.startup) {
924 Window clientwin = wwin->client_win;
926 XSync(dpy, 0);
927 processEvents(XPending(dpy));
929 /* the window can disappear while doing the processEvents() */
930 if (!wWindowFor(clientwin))
931 return;
933 #endif
937 if (wwin->flags.selected)
938 wIconSelect(wwin->icon);
940 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
946 void
947 wDeiconifyWindow(WWindow *wwin)
949 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
951 if (!wwin->flags.miniaturized)
952 return;
954 if (wwin->transient_for != None) {
955 WWindow *owner = recursiveTransientFor(wwin);
956 wDeiconifyWindow(owner);
957 wSetFocusTo(wwin->screen_ptr, wwin);
958 wRaiseFrame(wwin->frame->core);
959 return;
962 wwin->flags.miniaturized=0;
963 if (!wwin->flags.shaded)
964 wwin->flags.mapped=1;
966 if (wwin->icon->selected)
967 wIconSelect(wwin->icon);
969 XUnmapWindow(dpy, wwin->icon->core->window);
971 #ifdef WMSOUND
972 wSoundPlay(WMSOUND_DEICONIFY);
973 #endif
975 /* if the window is in another workspace, do it silently */
976 #ifdef ANIMATIONS
977 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
978 && !wwin->flags.skip_next_animation) {
979 animateResize(wwin->screen_ptr, wwin->icon_x, wwin->icon_y,
980 wwin->icon->core->width, wwin->icon->core->height,
981 wwin->frame_x, wwin->frame_y,
982 wwin->frame->core->width, wwin->frame->core->height,
983 False);
985 #endif /* ANIMATIONS */
986 wwin->flags.skip_next_animation = 0;
987 XGrabServer(dpy);
988 if (!wwin->flags.shaded) {
989 XMapWindow(dpy, wwin->client_win);
991 XMapWindow(dpy, wwin->frame->core->window);
992 wRaiseFrame(wwin->frame->core);
993 if (!wwin->flags.shaded) {
994 wClientSetState(wwin, NormalState, None);
996 mapTransientsFor(wwin);
997 RemoveFromStackList(wwin->icon->core);
998 removeIconGrabs(wwin->icon);
999 wIconDestroy(wwin->icon);
1000 wwin->icon = NULL;
1002 XUngrabServer(dpy);
1003 if (wPreferences.focus_mode==WKF_CLICK
1004 || wPreferences.focus_mode==WKF_SLOPPY)
1005 wSetFocusTo(wwin->screen_ptr, wwin);
1007 #ifdef ANIMATIONS
1008 if (!wwin->screen_ptr->flags.startup) {
1009 Window clientwin = wwin->client_win;
1011 XSync(dpy, 0);
1012 processEvents(XPending(dpy));
1014 if (!wWindowFor(clientwin))
1015 return;
1017 #endif
1019 if (wPreferences.auto_arrange_icons) {
1020 wArrangeIcons(wwin->screen_ptr, True);
1023 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1029 static void
1030 hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
1032 XWindowAttributes attribs;
1035 if (wwin->flags.miniaturized) {
1036 XUnmapWindow(dpy, wwin->icon->core->window);
1037 wwin->flags.hidden = 1;
1038 wwin->icon->mapped = 0;
1039 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1040 return;
1043 if (wwin->flags.inspector_open) {
1044 WWindow *pwin = wwin->inspector->frame;
1046 XGetWindowAttributes(dpy, pwin->client_win, &attribs);
1047 pwin->flags.hidden = 1;
1048 pwin->flags.mapped = 0;
1049 /* prevent window withdrawal when getting UnmapNotify */
1050 XSelectInput(dpy, pwin->client_win,
1051 attribs.your_event_mask & ~StructureNotifyMask);
1052 XUnmapWindow(dpy, pwin->client_win);
1053 XSelectInput(dpy, pwin->client_win, attribs.your_event_mask);
1055 XUnmapWindow(dpy, pwin->frame->core->window);
1056 wClientSetState(pwin, IconicState, icon->icon_win);
1059 XGetWindowAttributes(dpy, wwin->client_win, &attribs);
1061 wwin->flags.hidden = 1;
1062 wwin->flags.mapped = 0;
1064 /* prevent window withdrawal when getting UnmapNotify */
1065 XSelectInput(dpy, wwin->client_win,
1066 attribs.your_event_mask & ~StructureNotifyMask);
1067 XUnmapWindow(dpy, wwin->client_win);
1068 XSelectInput(dpy, wwin->client_win, attribs.your_event_mask);
1070 XUnmapWindow(dpy, wwin->frame->core->window);
1071 wClientSetState(wwin, IconicState, icon->icon_win);
1072 flushExpose();
1073 #ifdef WMSOUND
1074 wSoundPlay(WMSOUND_HIDE);
1075 #endif
1076 #ifdef ANIMATIONS
1077 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1078 !wwin->flags.skip_next_animation && animate) {
1079 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1080 wwin->frame->core->width, wwin->frame->core->height,
1081 icon_x, icon_y, icon->core->width, icon->core->height,
1082 True);
1084 #endif
1085 wwin->flags.skip_next_animation = 0;
1087 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1092 void
1093 wHideOtherApplications(WWindow *awin)
1095 WWindow *wwin;
1096 WApplication *tapp;
1097 #ifdef REDUCE_APPICONS
1098 char *tinstance, *tclass;
1099 unsigned int brokenwin = 0, match = 0;
1100 #endif
1102 if (!awin)
1103 return;
1104 wwin = awin->screen_ptr->focused_window;
1106 #ifdef REDUCE_APPICONS
1107 if (awin->wm_instance == NULL || awin->wm_class == NULL)
1108 brokenwin++;
1109 #endif
1111 while (wwin) {
1112 if (wwin!=awin
1113 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1114 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1115 && !wwin->flags.internal_window
1116 && (!wwin->flags.inspector_open || wwin->inspector->frame!=awin)
1117 && !wwin->window_flags.no_hide_others) {
1119 #ifdef REDUCE_APPICONS
1120 match = 0;
1121 if (!brokenwin) {
1122 if ((tinstance = wwin->wm_instance) == NULL)
1123 tinstance = "";
1124 if ((tclass = wwin->wm_class) == NULL)
1125 tclass = "";
1126 if ((strcmp(awin->wm_instance, tinstance) == 0) &&
1127 (strcmp(awin->wm_class, tclass) == 0) )
1128 match++;
1130 #endif
1132 if (wwin->main_window==None || wwin->window_flags.no_appicon) {
1133 if (!wwin->window_flags.no_miniaturizable) {
1134 wwin->flags.skip_next_animation = 1;
1135 wIconifyWindow(wwin);
1137 } else if (wwin->main_window!=None
1138 #ifndef REDUCE_APPICONS
1139 && awin->main_window != wwin->main_window) {
1140 #else
1141 && (awin->main_window != wwin->main_window && !match)) {
1142 #endif
1143 tapp = wApplicationOf(wwin->main_window);
1144 if (tapp) {
1145 tapp->flags.skip_next_animation = 1;
1146 wHideApplication(tapp);
1147 } else {
1148 if (!wwin->window_flags.no_miniaturizable) {
1149 wwin->flags.skip_next_animation = 1;
1150 wIconifyWindow(wwin);
1155 wwin = wwin->prev;
1158 wSetFocusTo(awin->screen_ptr, awin);
1164 void
1165 wHideApplication(WApplication *wapp)
1167 #ifdef REDUCE_APPICONS
1168 WApplication *tapp;
1169 char *tinstance, *tclass;
1170 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1171 #endif
1172 WScreen *scr;
1173 WWindow *wlist;
1174 int hadfocus;
1176 if (!wapp) {
1177 wwarning("trying to hide a non grouped window");
1178 return;
1180 if (!wapp->main_window_desc) {
1181 wwarning("group leader not found for window group");
1182 return;
1184 #ifdef REDUCE_APPICONS
1185 if ((wapp->main_window_desc->wm_instance == NULL) ||
1186 (wapp->main_window_desc->wm_class == NULL))
1187 nowmhints++;
1188 #endif
1189 scr = wapp->main_window_desc->screen_ptr;
1190 hadfocus = 0;
1191 wlist = scr->focused_window;
1192 if (!wlist)
1193 return;
1195 if (wlist->main_window == wapp->main_window)
1196 wapp->last_focused = wlist;
1197 else
1198 wapp->last_focused = NULL;
1199 while (wlist) {
1200 #ifdef REDUCE_APPICONS
1201 matchwmhints = matchworkspace = 0;
1202 if (!nowmhints) {
1203 tapp = wApplicationOf(wlist->main_window);
1204 tinstance = tclass = NULL;
1205 if (tapp) {
1206 if (tapp->main_window_desc) {
1207 tinstance = tapp->main_window_desc->wm_instance;
1208 tclass = tapp->main_window_desc->wm_class;
1211 if (tapp == NULL || tinstance == NULL || tclass == NULL) {
1212 /* Should never reach here */
1213 tinstance = "";
1214 tclass = "";
1216 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0) &&
1217 (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1218 matchwmhints++;
1220 if (wlist->frame) {
1221 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1222 matchworkspace++;
1224 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1225 matchworkspace) {
1226 #ifdef I_HATE_THIS
1228 #endif
1229 #else
1230 if (wlist->main_window == wapp->main_window) {
1231 #endif
1232 if (wlist->flags.focused) {
1233 hadfocus = 1;
1235 if (wapp->app_icon)
1236 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1237 wapp->app_icon->y_pos, wlist,
1238 !wapp->flags.skip_next_animation);
1240 wlist = wlist->prev;
1243 wapp->flags.skip_next_animation = 0;
1245 if (hadfocus) {
1246 if (wPreferences.focus_mode==WKF_CLICK) {
1247 wlist = scr->focused_window;
1248 while (wlist) {
1249 if (!wlist->window_flags.no_focusable && !wlist->flags.hidden
1250 && (wlist->flags.mapped || wlist->flags.shaded))
1251 break;
1252 wlist = wlist->prev;
1254 wSetFocusTo(scr, wlist);
1255 } else {
1256 wSetFocusTo(scr, NULL);
1260 wapp->flags.hidden = 1;
1262 if(wPreferences.auto_arrange_icons) {
1263 wArrangeIcons(scr, True);
1270 static void
1271 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1272 int bringToCurrentWS)
1274 if (bringToCurrentWS)
1275 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1277 wwin->flags.hidden=0;
1278 wwin->flags.mapped=1;
1280 #ifdef WMSOUND
1281 wSoundPlay(WMSOUND_UNHIDE);
1282 #endif
1283 #ifdef ANIMATIONS
1284 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1285 && animate) {
1286 animateResize(wwin->screen_ptr, icon_x, icon_y,
1287 icon->core->width, icon->core->height,
1288 wwin->frame_x, wwin->frame_y,
1289 wwin->frame->core->width, wwin->frame->core->height,
1290 True);
1292 #endif
1293 wwin->flags.skip_next_animation = 0;
1294 XMapWindow(dpy, wwin->client_win);
1295 XMapWindow(dpy, wwin->frame->core->window);
1296 wClientSetState(wwin, NormalState, None);
1297 wRaiseFrame(wwin->frame->core);
1298 if (wwin->flags.inspector_open) {
1299 WWindow *pwin = wwin->inspector->frame;
1301 pwin->flags.hidden = 0;
1302 pwin->flags.mapped = 1;
1303 XMapWindow(dpy, pwin->client_win);
1304 XMapWindow(dpy, pwin->frame->core->window);
1305 wClientSetState(pwin, NormalState, None);
1308 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1312 void
1313 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1315 WScreen *scr;
1316 WWindow *wlist, *next;
1317 WWindow *focused=NULL;
1318 #ifdef REDUCE_APPICONS
1319 char *tinstance, *tclass;
1320 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1321 #endif
1323 if (!wapp) {
1324 return;
1327 #ifdef REDUCE_APPICONS
1328 if ((wapp->main_window_desc->wm_class == NULL) ||
1329 (wapp->main_window_desc->wm_instance == NULL))
1330 nowmhints++;
1331 #endif
1333 scr = wapp->main_window_desc->screen_ptr;
1334 wlist = scr->focused_window;
1335 if (!wlist) return;
1336 /* goto beginning of list */
1337 while (wlist->prev)
1338 wlist = wlist->prev;
1340 while (wlist) {
1341 next = wlist->next;
1343 #ifndef REDUCE_APPICONS
1344 if (wlist->main_window == wapp->main_window) {
1345 #else
1346 matchwmhints = matchworkspace = 0;
1347 if (!nowmhints) {
1348 if ((tinstance = wlist->wm_instance) == NULL)
1349 tinstance = "";
1350 if ((tclass = wlist->wm_class) == NULL)
1351 tclass = "";
1352 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0)
1353 && (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1354 matchwmhints++;
1356 if (wlist->frame) {
1357 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1358 matchworkspace++;
1361 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1362 matchworkspace) {
1363 #endif
1364 if (wlist->flags.focused)
1365 focused = wlist;
1366 else if (!focused || !focused->flags.focused)
1367 focused = wlist;
1369 if (wlist->flags.miniaturized && wlist->icon) {
1370 if (bringToCurrentWS || wPreferences.sticky_icons
1371 || wlist->frame->workspace == scr->current_workspace) {
1372 if (!wlist->icon->mapped) {
1373 XMapWindow(dpy, wlist->icon->core->window);
1374 wlist->icon->mapped = 1;
1376 wlist->flags.hidden = 0;
1377 UpdateSwitchMenu(scr, wlist, ACTION_CHANGE_STATE);
1378 if (wlist->frame->workspace != scr->current_workspace)
1379 wWindowChangeWorkspace(wlist, scr->current_workspace);
1381 if (miniwindows) {
1382 wDeiconifyWindow(wlist);
1384 } else if (wlist->flags.hidden) {
1385 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1386 wapp->app_icon->y_pos, wlist,
1387 !wapp->flags.skip_next_animation,
1388 bringToCurrentWS);
1389 } else {
1390 if (bringToCurrentWS
1391 && wlist->frame->workspace != scr->current_workspace) {
1392 wWindowChangeWorkspace(wlist, scr->current_workspace);
1394 wRaiseFrame(wlist->frame->core);
1397 wlist = next;
1400 wapp->flags.skip_next_animation = 0;
1401 wapp->flags.hidden = 0;
1403 if (focused)
1404 wSetFocusTo(scr, focused);
1405 else if (wapp->last_focused && wapp->last_focused->flags.mapped)
1406 wSetFocusTo(scr, wapp->last_focused);
1407 wapp->last_focused = NULL;
1408 if (wPreferences.auto_arrange_icons) {
1409 wArrangeIcons(scr, True);
1415 void
1416 wShowAllWindows(WScreen *scr)
1418 WWindow *wwin, *old_foc;
1419 WApplication *wapp;
1421 old_foc = wwin = scr->focused_window;
1422 while (wwin) {
1423 if (!wwin->flags.internal_window &&
1424 (scr->current_workspace == wwin->frame->workspace
1425 || wwin->window_flags.omnipresent)) {
1426 if (wwin->flags.miniaturized) {
1427 wwin->flags.skip_next_animation = 1;
1428 wDeiconifyWindow(wwin);
1429 } else if (wwin->flags.hidden) {
1430 wapp = wApplicationOf(wwin->main_window);
1431 if (wapp) {
1432 wUnhideApplication(wapp, False, False);
1433 } else {
1434 wwin->flags.skip_next_animation = 1;
1435 wDeiconifyWindow(wwin);
1439 wwin = wwin->prev;
1441 wSetFocusTo(scr, old_foc);
1442 /*wRaiseFrame(old_foc->frame->core);*/
1446 void
1447 wRefreshDesktop(WScreen *scr)
1449 Window win;
1450 XSetWindowAttributes attr;
1452 attr.backing_store = NotUseful;
1453 attr.save_under = False;
1454 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1455 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1456 (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
1457 &attr);
1458 XMapRaised(dpy, win);
1459 XDestroyWindow(dpy, win);
1460 XFlush(dpy);
1464 void
1465 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1467 WWindow *wwin;
1468 WAppIcon *aicon;
1469 int pf; /* primary axis */
1470 int sf; /* secondary axis */
1471 int fullW;
1472 int fullH;
1473 int pi, si;
1474 int sx1, sx2, sy1, sy2; /* screen boundary */
1475 int sw, sh;
1476 int xo, yo;
1477 int xs, ys;
1478 int isize = wPreferences.icon_size;
1481 * Find out screen boundaries.
1483 sx1 = 0;
1484 sy1 = 0;
1485 sx2 = scr->scr_width;
1486 sy2 = scr->scr_height;
1487 if (scr->dock) {
1488 if (scr->dock->on_right_side)
1489 sx2 -= isize + DOCK_EXTRA_SPACE;
1490 else
1491 sx1 += isize + DOCK_EXTRA_SPACE;
1494 sw = isize * (scr->scr_width/isize);
1495 sh = isize * (scr->scr_height/isize);
1496 fullW = (sx2-sx1)/isize;
1497 fullH = (sy2-sy1)/isize;
1499 /* icon yard boundaries */
1500 if (wPreferences.icon_yard & IY_VERT) {
1501 pf = fullH;
1502 sf = fullW;
1503 } else {
1504 pf = fullW;
1505 sf = fullH;
1507 if (wPreferences.icon_yard & IY_RIGHT) {
1508 xo = sx2 - isize;
1509 xs = -1;
1510 } else {
1511 xo = sx1;
1512 xs = 1;
1514 if (wPreferences.icon_yard & IY_TOP) {
1515 yo = sy1;
1516 ys = 1;
1517 } else {
1518 yo = sy2 - isize;
1519 ys = -1;
1522 /* arrange icons putting the most recently focused window
1523 * as the last icon */
1524 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1525 : xo + xs*(pi*isize))
1526 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1527 : yo + ys*(si*isize))
1529 /* arrange application icons */
1530 aicon = scr->app_icon_list;
1531 /* reverse them to avoid unnecessarily sliding of icons */
1532 while (aicon && aicon->next)
1533 aicon = aicon->next;
1535 pi = 0;
1536 si = 0;
1537 while (aicon) {
1538 if (!aicon->docked) {
1539 if (aicon->x_pos != X || aicon->y_pos != Y) {
1540 #ifdef ANIMATIONS
1541 if (!wPreferences.no_animations) {
1542 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1543 X, Y);
1545 #endif /* ANIMATIONS */
1547 wAppIconMove(aicon, X, Y);
1548 pi++;
1550 /* we reversed the order so we use prev */
1551 aicon = aicon->prev;
1552 if (pi >= pf) {
1553 pi=0;
1554 si++;
1558 /* arrange miniwindows */
1560 wwin = scr->focused_window;
1561 /* reverse them to avoid unnecessarily shuffling */
1562 while (wwin && wwin->prev)
1563 wwin = wwin->prev;
1565 while (wwin) {
1566 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1567 (wwin->frame->workspace==scr->current_workspace ||
1568 wwin->window_flags.omnipresent ||
1569 wPreferences.sticky_icons)) {
1571 if (arrangeAll || !wwin->flags.icon_moved) {
1572 if (wwin->icon_x != X || wwin->icon_y != Y) {
1573 #ifdef ANIMATIONS
1574 if (wPreferences.no_animations) {
1575 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1576 } else {
1577 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1578 wwin->icon_y, X, Y);
1580 #else
1581 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1582 #endif /* ANIMATIONS */
1584 wwin->icon_x = X;
1585 wwin->icon_y = Y;
1586 wwin->flags.icon_moved = 0;
1587 pi++;
1590 /* we reversed the order, so we use next */
1591 wwin = wwin->next;
1592 if (pi >= pf) {
1593 pi=0;
1594 si++;
1600 void
1601 wSelectWindow(WWindow *wwin, Bool flag)
1603 WScreen *scr = wwin->screen_ptr;
1604 if (flag) {
1605 wwin->flags.selected = 1;
1606 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1607 scr->selected_windows = list_cons(wwin, scr->selected_windows);
1608 } else {
1609 wwin->flags.selected = 0;
1610 XSetWindowBorder(dpy, wwin->frame->core->window,
1611 scr->frame_border_pixel);
1612 scr->selected_windows = list_remove_elem(scr->selected_windows, wwin);
1617 void
1618 wMakeWindowVisible(WWindow *wwin)
1620 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1622 if (wwin->flags.shaded) {
1623 wUnshadeWindow(wwin);
1625 if (wwin->flags.hidden) {
1626 wUnhideApplication(wApplicationOf(wwin->main_window), False, False);
1627 } else if (wwin->flags.miniaturized) {
1628 wDeiconifyWindow(wwin);
1629 } else {
1630 wSetFocusTo(wwin->screen_ptr, wwin);
1631 wRaiseFrame(wwin->frame->core);