- Implemented a better logic to preserve the window's old geometry when
[wmaker-crm.git] / src / actions.c
blob5bd836239036e93a8cd3139d31c5c9ed293f3ab2
1 /* action.c- misc. window commands (miniaturize, hide etc.)
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * Copyright (c) 1998-2003 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"
50 #include "wsound.h"
51 #include "xinerama.h"
53 #ifdef GNOME_STUFF
54 # include "gnome.h"
55 #endif
56 #ifdef KWM_HINTS
57 # include "kwm.h"
58 #endif
62 /****** Global Variables ******/
63 extern Time LastTimestamp;
64 extern Time LastFocusChange;
66 extern Cursor wCursor[WCUR_LAST];
68 extern WPreferences wPreferences;
70 extern Atom _XA_WM_TAKE_FOCUS;
73 /******* Local Variables *******/
74 static struct {
75 int steps;
76 int delay;
77 } shadePars[5] = {
78 {SHADE_STEPS_UF, SHADE_DELAY_UF},
79 {SHADE_STEPS_F, SHADE_DELAY_F},
80 {SHADE_STEPS_M, SHADE_DELAY_M},
81 {SHADE_STEPS_S, SHADE_DELAY_S},
82 {SHADE_STEPS_US, SHADE_DELAY_US}};
84 #define SHADE_STEPS shadePars[(int)wPreferences.shade_speed].steps
85 #define SHADE_DELAY shadePars[(int)wPreferences.shade_speed].delay
88 static int ignoreTimestamp=0;
91 #ifdef ANIMATIONS
92 static void
93 processEvents(int event_count)
95 XEvent event;
98 * This is a hack. When animations are enabled, processing of
99 * events ocurred during a animation are delayed until it's end.
100 * Calls that consider the TimeStamp, like XSetInputFocus(), will
101 * fail because the TimeStamp is too old. Then, for example, if
102 * the user changes window focus while a miniaturize animation is
103 * in course, the window will not get focus properly after the end
104 * of the animation. This tries to workaround it by passing CurrentTime
105 * as the TimeStamp for XSetInputFocus() for all events ocurred during
106 * the animation.
108 ignoreTimestamp=1;
109 while (XPending(dpy) && event_count--) {
110 WMNextEvent(dpy, &event);
111 WMHandleEvent(&event);
113 ignoreTimestamp=0;
115 #endif /* ANIMATIONS */
120 *----------------------------------------------------------------------
121 * wSetFocusTo--
122 * Changes the window focus to the one passed as argument.
123 * If the window to focus is not already focused, it will be brought
124 * to the head of the list of windows. Previously focused window is
125 * unfocused.
127 * Side effects:
128 * Window list may be reordered and the window focus is changed.
130 *----------------------------------------------------------------------
132 void
133 wSetFocusTo(WScreen *scr, WWindow *wwin)
135 static WScreen *old_scr=NULL;
137 WWindow *old_focused;
138 WWindow *focused=scr->focused_window;
139 int timestamp=LastTimestamp;
140 WApplication *oapp=NULL, *napp=NULL;
141 int wasfocused;
143 if (!old_scr)
144 old_scr=scr;
145 old_focused=old_scr->focused_window;
147 LastFocusChange = timestamp;
150 * This is a hack, because XSetInputFocus() should have a proper
151 * timestamp instead of CurrentTime but it seems that some times
152 * clients will not receive focus properly that way.
153 if (ignoreTimestamp)
155 timestamp = CurrentTime;
157 if (old_focused)
158 oapp = wApplicationOf(old_focused->main_window);
160 if (wwin == NULL) {
161 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
162 if (old_focused) {
163 wWindowUnfocus(old_focused);
165 if (oapp) {
166 wAppMenuUnmap(oapp->menu);
167 #ifdef NEWAPPICON
168 wApplicationDeactivate(oapp);
169 #endif
172 WMPostNotificationName(WMNChangedFocus, NULL, (void*)True);
173 return;
174 } else if (old_scr != scr && old_focused) {
175 wWindowUnfocus(old_focused);
178 wasfocused = wwin->flags.focused;
179 napp = wApplicationOf(wwin->main_window);
181 /* remember last workspace where the app has been */
182 if (napp) {
183 /*napp->last_workspace = wwin->screen_ptr->current_workspace;*/
184 napp->last_workspace = wwin->frame->workspace;
187 if (wwin->flags.mapped && !WFLAGP(wwin, no_focusable)) {
188 /* install colormap if colormap mode is lock mode */
189 if (wPreferences.colormap_mode==WCM_CLICK)
190 wColormapInstallForWindow(scr, wwin);
192 /* set input focus */
193 switch (wwin->focus_mode) {
194 case WFM_NO_INPUT:
195 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
196 break;
198 case WFM_PASSIVE:
199 case WFM_LOCALLY_ACTIVE:
200 XSetInputFocus(dpy, wwin->client_win, RevertToParent, timestamp);
201 break;
203 case WFM_GLOBALLY_ACTIVE:
204 break;
206 XFlush(dpy);
207 if (wwin->protocols.TAKE_FOCUS) {
208 wClientSendProtocol(wwin, _XA_WM_TAKE_FOCUS, timestamp);
210 XSync(dpy, False);
211 } else {
212 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
214 if (WFLAGP(wwin, no_focusable))
215 return;
217 /* if this is not the focused window focus it */
218 if (focused!=wwin) {
219 /* change the focus window list order */
220 if (wwin->prev)
221 wwin->prev->next = wwin->next;
223 if (wwin->next)
224 wwin->next->prev = wwin->prev;
226 wwin->prev = focused;
227 focused->next = wwin;
228 wwin->next = NULL;
229 scr->focused_window = wwin;
231 if (oapp && oapp != napp) {
232 wAppMenuUnmap(oapp->menu);
233 #ifdef NEWAPPICON
234 wApplicationDeactivate(oapp);
235 #endif
239 wWindowFocus(wwin, focused);
241 if (napp && !wasfocused) {
242 #ifdef USER_MENU
243 wUserMenuRefreshInstances(napp->menu, wwin);
244 #endif /* USER_MENU */
246 if (wwin->flags.mapped)
247 wAppMenuMap(napp->menu, wwin);
248 #ifdef NEWAPPICON
249 wApplicationActivate(napp);
250 #endif
253 XFlush(dpy);
254 old_scr=scr;
258 void
259 wShadeWindow(WWindow *wwin)
261 time_t time0;
262 #ifdef ANIMATIONS
263 int y, s, w, h;
264 #endif
266 if (wwin->flags.shaded)
267 return;
269 time0 = time(NULL);
271 XLowerWindow(dpy, wwin->client_win);
273 wSoundPlay(WSOUND_SHADE);
275 #ifdef ANIMATIONS
276 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
277 && !wPreferences.no_animations) {
278 /* do the shading animation */
279 h = wwin->frame->core->height;
280 s = h/SHADE_STEPS;
281 if (s < 1) s=1;
282 w = wwin->frame->core->width;
283 y = wwin->frame->top_width;
284 while (h>wwin->frame->top_width+1) {
285 XMoveWindow(dpy, wwin->client_win, 0, y);
286 XResizeWindow(dpy, wwin->frame->core->window, w, h);
287 XFlush(dpy);
289 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
290 break;
292 if (SHADE_DELAY > 0) {
293 wusleep(SHADE_DELAY*1000L);
294 } else {
295 wusleep(10);
297 h-=s;
298 y-=s;
300 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
302 #endif /* ANIMATIONS */
304 wwin->flags.skip_next_animation = 0;
305 wwin->flags.shaded = 1;
306 wwin->flags.mapped = 0;
307 /* prevent window withdrawal when getting UnmapNotify */
308 XSelectInput(dpy, wwin->client_win,
309 wwin->event_mask & ~StructureNotifyMask);
310 XUnmapWindow(dpy, wwin->client_win);
311 XSelectInput(dpy, wwin->client_win, wwin->event_mask);
313 /* for the client it's just like iconification */
314 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
315 wwin->frame->top_width - 1);
317 wwin->client.y = wwin->frame_y - wwin->client.height
318 + wwin->frame->top_width;
319 wWindowSynthConfigureNotify(wwin);
322 wClientSetState(wwin, IconicState, None);
325 WMPostNotificationName(WMNChangedState, wwin, "shade");
327 #ifdef ANIMATIONS
328 if (!wwin->screen_ptr->flags.startup) {
329 /* Look at processEvents() for reason of this code. */
330 XSync(dpy, 0);
331 processEvents(XPending(dpy));
333 #endif
337 void
338 wUnshadeWindow(WWindow *wwin)
340 time_t time0;
341 #ifdef ANIMATIONS
342 int y, s, w, h;
343 #endif /* ANIMATIONS */
346 if (!wwin->flags.shaded)
347 return;
349 time0 = time(NULL);
351 wwin->flags.shaded = 0;
352 wwin->flags.mapped = 1;
353 XMapWindow(dpy, wwin->client_win);
355 wSoundPlay(WSOUND_UNSHADE);
357 #ifdef ANIMATIONS
358 if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) {
359 /* do the shading animation */
360 h = wwin->frame->top_width + wwin->frame->bottom_width;
361 y = wwin->frame->top_width - wwin->client.height;
362 s = abs(y)/SHADE_STEPS;
363 if (s<1) s=1;
364 w = wwin->frame->core->width;
365 XMoveWindow(dpy, wwin->client_win, 0, y);
366 if (s>0) {
367 while (h < wwin->client.height + wwin->frame->top_width
368 + wwin->frame->bottom_width) {
369 XResizeWindow(dpy, wwin->frame->core->window, w, h);
370 XMoveWindow(dpy, wwin->client_win, 0, y);
371 XFlush(dpy);
372 if (SHADE_DELAY > 0) {
373 wusleep(SHADE_DELAY*2000L/3);
374 } else {
375 wusleep(10);
377 h+=s;
378 y+=s;
380 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
381 break;
384 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
386 #endif /* ANIMATIONS */
388 wwin->flags.skip_next_animation = 0;
389 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
390 wwin->frame->top_width + wwin->client.height
391 + wwin->frame->bottom_width);
393 wwin->client.y = wwin->frame_y + wwin->frame->top_width;
394 wWindowSynthConfigureNotify(wwin);
397 wClientSetState(wwin, NormalState, None);
399 /* if the window is focused, set the focus again as it was disabled during
400 * shading */
401 if (wwin->flags.focused)
402 wSetFocusTo(wwin->screen_ptr, wwin);
404 WMPostNotificationName(WMNChangedState, wwin, "shade");
408 void
409 wMaximizeWindow(WWindow *wwin, int directions)
411 int new_width, new_height, new_x, new_y;
412 int changed_h, changed_v, shrink_h, shrink_v;
413 WArea usableArea, totalArea;
415 if (WFLAGP(wwin, no_resizable))
416 return;
418 usableArea = totalArea = (WArea){
419 0, 0,
420 wwin->screen_ptr->scr_width,
421 wwin->screen_ptr->scr_height
424 if (!(directions & MAX_IGNORE_XINERAMA)) {
425 WScreen *scr = wwin->screen_ptr;
426 int head;
428 if (directions & MAX_KEYBOARD)
429 head = wGetHeadForWindow(wwin);
430 else
431 head = wGetHeadForPointerLocation(scr);
433 usableArea = wGetUsableAreaForHead(scr, head, &totalArea, True);
436 if (WFLAGP(wwin, full_maximize)) {
437 usableArea = totalArea;
440 if (wwin->flags.shaded) {
441 wwin->flags.skip_next_animation = 1;
442 wUnshadeWindow(wwin);
444 /* Only save directions, not kbd or xinerama hints */
445 directions &= (MAX_HORIZONTAL|MAX_VERTICAL);
447 changed_h = ((wwin->flags.maximized ^ directions) & MAX_HORIZONTAL);
448 changed_v = ((wwin->flags.maximized ^ directions) & MAX_VERTICAL);
449 shrink_h = (changed_h && (directions & MAX_HORIZONTAL)==0);
450 shrink_v = (changed_v && (directions & MAX_VERTICAL)==0);
452 if (wwin->flags.maximized) {
453 /* if already maximized in some direction, we only update the
454 * appropriate old x, old y coordinates. This is necessary to
455 * allow succesive maximizations in different directions without
456 * the need to first do an un-maximize (to avoid flicker).
458 if (!(wwin->flags.maximized & MAX_HORIZONTAL)) {
459 wwin->old_geometry.x = wwin->frame_x;
461 if (!(wwin->flags.maximized & MAX_VERTICAL)) {
462 wwin->old_geometry.y = wwin->frame_y;
464 } else {
465 wwin->old_geometry.width = wwin->client.width;
466 wwin->old_geometry.height = wwin->client.height;
467 wwin->old_geometry.x = wwin->frame_x;
468 wwin->old_geometry.y = wwin->frame_y;
470 wwin->flags.maximized = directions;
472 #ifdef KWM_HINTS
473 wKWMUpdateClientGeometryRestore(wwin);
474 #endif
476 if (directions & MAX_HORIZONTAL) {
477 new_width = (usableArea.x2-usableArea.x1)-FRAME_BORDER_WIDTH*2;
478 new_x = usableArea.x1;
479 } else if (shrink_h) {
480 new_x = wwin->old_geometry.x;
481 new_width = wwin->old_geometry.width;
482 } else {
483 new_x = wwin->frame_x;
484 new_width = wwin->frame->core->width;
487 if (directions & MAX_VERTICAL) {
488 new_height = (usableArea.y2-usableArea.y1)-FRAME_BORDER_WIDTH*2;
489 new_y = usableArea.y1;
490 if (WFLAGP(wwin, full_maximize)) {
491 new_y -= wwin->frame->top_width;
492 new_height += wwin->frame->bottom_width - 1;
494 } else if (shrink_v) {
495 new_y = wwin->old_geometry.y;
496 new_height = wwin->old_geometry.height;
497 } else {
498 new_y = wwin->frame_y;
499 new_height = wwin->frame->core->height;
502 if (!WFLAGP(wwin, full_maximize)) {
503 new_height -= wwin->frame->top_width+wwin->frame->bottom_width;
506 wWindowConstrainSize(wwin, &new_width, &new_height);
508 wWindowCropSize(wwin, usableArea.x2-usableArea.x1,
509 usableArea.y2-usableArea.y1,
510 &new_width, &new_height);
512 wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
515 WMPostNotificationName(WMNChangedState, wwin, "maximize");
517 wSoundPlay(WSOUND_MAXIMIZE);
521 void
522 wUnmaximizeWindow(WWindow *wwin)
524 int restore_x, restore_y;
526 if (!wwin->flags.maximized)
527 return;
529 if (wwin->flags.shaded) {
530 wwin->flags.skip_next_animation = 1;
531 wUnshadeWindow(wwin);
533 restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ?
534 wwin->old_geometry.x : wwin->frame_x;
535 restore_y = (wwin->flags.maximized & MAX_VERTICAL) ?
536 wwin->old_geometry.y : wwin->frame_y;
537 wwin->flags.maximized = 0;
538 wWindowConfigure(wwin, restore_x, restore_y,
539 wwin->old_geometry.width, wwin->old_geometry.height);
541 WMPostNotificationName(WMNChangedState, wwin, "maximize");
543 wSoundPlay(WSOUND_UNMAXIMIZE);
546 #ifdef ANIMATIONS
547 static void
548 animateResizeFlip(WScreen *scr, int x, int y, int w, int h,
549 int fx, int fy, int fw, int fh, int steps)
551 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
552 float cx, cy, cw, ch;
553 float xstep, ystep, wstep, hstep;
554 XPoint points[5];
555 float dx, dch, midy;
556 float angle, final_angle, delta;
558 xstep = (float)(fx-x)/steps;
559 ystep = (float)(fy-y)/steps;
560 wstep = (float)(fw-w)/steps;
561 hstep = (float)(fh-h)/steps;
563 cx = (float)x;
564 cy = (float)y;
565 cw = (float)w;
566 ch = (float)h;
568 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F;
569 delta = (float)(final_angle/FRAMES);
570 for (angle=0;; angle+=delta) {
571 if (angle > final_angle)
572 angle = final_angle;
574 dx = (cw/10) - ((cw/5) * sin(angle));
575 dch = (ch/2) * cos(angle);
576 midy = cy + (ch/2);
578 points[0].x = cx + dx; points[0].y = midy - dch;
579 points[1].x = cx + cw - dx; points[1].y = points[0].y;
580 points[2].x = cx + cw + dx; points[2].y = midy + dch;
581 points[3].x = cx - dx; points[3].y = points[2].y;
582 points[4].x = points[0].x; points[4].y = points[0].y;
584 XGrabServer(dpy);
585 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
586 XFlush(dpy);
587 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
588 wusleep(MINIATURIZE_ANIMATION_DELAY_F);
589 #else
590 wusleep(10);
591 #endif
593 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
594 XUngrabServer(dpy);
595 cx+=xstep;
596 cy+=ystep;
597 cw+=wstep;
598 ch+=hstep;
599 if (angle >= final_angle)
600 break;
603 XFlush(dpy);
605 #undef FRAMES
608 static void
609 animateResizeTwist(WScreen *scr, int x, int y, int w, int h,
610 int fx, int fy, int fw, int fh, int steps)
612 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
613 float cx, cy, cw, ch;
614 float xstep, ystep, wstep, hstep;
615 XPoint points[5];
616 float angle, final_angle, a, d, delta;
618 x += w/2;
619 y += h/2;
620 fx += fw/2;
621 fy += fh/2;
623 xstep = (float)(fx-x)/steps;
624 ystep = (float)(fy-y)/steps;
625 wstep = (float)(fw-w)/steps;
626 hstep = (float)(fh-h)/steps;
628 cx = (float)x;
629 cy = (float)y;
630 cw = (float)w;
631 ch = (float)h;
633 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T;
634 delta = (float)(final_angle/FRAMES);
635 for (angle=0;; angle+=delta) {
636 if (angle > final_angle)
637 angle = final_angle;
639 a = atan(ch/cw);
640 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
642 points[0].x = cx+cos(angle-a)*d;
643 points[0].y = cy+sin(angle-a)*d;
644 points[1].x = cx+cos(angle+a)*d;
645 points[1].y = cy+sin(angle+a)*d;
646 points[2].x = cx+cos(angle-a+WM_PI)*d;
647 points[2].y = cy+sin(angle-a+WM_PI)*d;
648 points[3].x = cx+cos(angle+a+WM_PI)*d;
649 points[3].y = cy+sin(angle+a+WM_PI)*d;
650 points[4].x = cx+cos(angle-a)*d;
651 points[4].y = cy+sin(angle-a)*d;
652 XGrabServer(dpy);
653 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
654 XFlush(dpy);
655 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
656 wusleep(MINIATURIZE_ANIMATION_DELAY_T);
657 #else
658 wusleep(10);
659 #endif
661 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
662 XUngrabServer(dpy);
663 cx+=xstep;
664 cy+=ystep;
665 cw+=wstep;
666 ch+=hstep;
667 if (angle >= final_angle)
668 break;
671 XFlush(dpy);
673 #undef FRAMES
676 static void
677 animateResizeZoom(WScreen *scr, int x, int y, int w, int h,
678 int fx, int fy, int fw, int fh, int steps)
680 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
681 float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
682 float xstep, ystep, wstep, hstep;
683 int i, j;
685 xstep = (float)(fx-x)/steps;
686 ystep = (float)(fy-y)/steps;
687 wstep = (float)(fw-w)/steps;
688 hstep = (float)(fh-h)/steps;
690 for (j=0; j<FRAMES; j++) {
691 cx[j] = (float)x;
692 cy[j] = (float)y;
693 cw[j] = (float)w;
694 ch[j] = (float)h;
696 XGrabServer(dpy);
697 for (i=0; i<steps; i++) {
698 for (j=0; j<FRAMES; j++) {
699 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
700 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
702 XFlush(dpy);
703 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
704 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
705 #else
706 wusleep(10);
707 #endif
708 for (j=0; j<FRAMES; j++) {
709 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
710 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
711 if (j<FRAMES-1) {
712 cx[j]=cx[j+1];
713 cy[j]=cy[j+1];
714 cw[j]=cw[j+1];
715 ch[j]=ch[j+1];
716 } else {
717 cx[j]+=xstep;
718 cy[j]+=ystep;
719 cw[j]+=wstep;
720 ch[j]+=hstep;
725 for (j=0; j<FRAMES; j++) {
726 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
727 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
729 XFlush(dpy);
730 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
731 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
732 #else
733 wusleep(10);
734 #endif
735 for (j=0; j<FRAMES; j++) {
736 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
737 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
740 XUngrabServer(dpy);
742 #undef FRAMES
745 void
746 animateResize(WScreen *scr, int x, int y, int w, int h,
747 int fx, int fy, int fw, int fh, int hiding)
749 int style = wPreferences.iconification_style; /* Catch the value */
750 int steps, k;
752 if (style == WIS_NONE)
753 return;
755 if (style == WIS_RANDOM) {
756 style = rand()%3;
759 k = (hiding ? 2 : 3);
760 switch(style) {
761 case WIS_TWIST:
762 steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
763 if (steps>0)
764 animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
765 break;
766 case WIS_FLIP:
767 steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
768 if (steps>0)
769 animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
770 break;
771 case WIS_ZOOM:
772 default:
773 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
774 if (steps>0)
775 animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
776 break;
779 #endif /* ANIMATIONS */
782 static void
783 flushExpose()
785 XEvent tmpev;
787 while (XCheckTypedEvent(dpy, Expose, &tmpev))
788 WMHandleEvent(&tmpev);
789 XSync(dpy, 0);
792 static void
793 unmapTransientsFor(WWindow *wwin)
795 WWindow *tmp;
798 tmp = wwin->screen_ptr->focused_window;
799 while (tmp) {
800 /* unmap the transients for this transient */
801 if (tmp!=wwin && tmp->transient_for == wwin->client_win
802 && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
803 || tmp->flags.shaded)) {
804 unmapTransientsFor(tmp);
805 tmp->flags.miniaturized = 1;
806 if (!tmp->flags.shaded) {
807 wWindowUnmap(tmp);
808 } else {
809 XUnmapWindow(dpy, tmp->frame->core->window);
812 if (!tmp->flags.shaded)
814 wClientSetState(tmp, IconicState, None);
816 WMPostNotificationName(WMNChangedState, tmp, "iconify-transient");
818 tmp = tmp->prev;
823 static void
824 mapTransientsFor(WWindow *wwin)
826 WWindow *tmp;
828 tmp = wwin->screen_ptr->focused_window;
829 while (tmp) {
830 /* recursively map the transients for this transient */
831 if (tmp!=wwin && tmp->transient_for == wwin->client_win
832 && /*!tmp->flags.mapped*/ tmp->flags.miniaturized
833 && tmp->icon==NULL) {
834 mapTransientsFor(tmp);
835 tmp->flags.miniaturized = 0;
836 if (!tmp->flags.shaded) {
837 wWindowMap(tmp);
838 } else {
839 XMapWindow(dpy, tmp->frame->core->window);
841 tmp->flags.semi_focused = 0;
843 if (!tmp->flags.shaded)
845 wClientSetState(tmp, NormalState, None);
847 WMPostNotificationName(WMNChangedState, tmp, "iconify-transient");
849 tmp = tmp->prev;
853 #if 0
854 static void
855 setupIconGrabs(WIcon *icon)
857 /* setup passive grabs on the icon */
858 XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
859 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
860 XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
861 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
862 XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
863 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
864 XSync(dpy, 0);
866 #endif
868 static WWindow*
869 recursiveTransientFor(WWindow *wwin)
871 int i;
873 if (!wwin)
874 return None;
876 /* hackish way to detect transient_for cycle */
877 i = wwin->screen_ptr->window_count+1;
879 while (wwin && wwin->transient_for != None && i>0) {
880 wwin = wWindowFor(wwin->transient_for);
881 i--;
883 if (i==0 && wwin) {
884 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
885 wwin->frame->title);
886 return NULL;
889 return wwin;
892 #if 0
893 static void
894 removeIconGrabs(WIcon *icon)
896 /* remove passive grabs on the icon */
897 XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
898 XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
899 XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);
900 XSync(dpy, 0);
902 #endif
905 void
906 wIconifyWindow(WWindow *wwin)
908 XWindowAttributes attribs;
909 int present;
912 if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
913 /* the window doesn't exist anymore */
914 return;
917 if (wwin->flags.miniaturized) {
918 return;
921 if (wwin->transient_for!=None &&
922 wwin->transient_for!=wwin->screen_ptr->root_win) {
923 WWindow *owner = wWindowFor(wwin->transient_for);
925 if (owner && owner->flags.miniaturized)
926 return;
929 present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
931 /* if the window is in another workspace, simplify process */
932 if (present) {
933 /* icon creation may take a while */
934 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
935 ButtonMotionMask|ButtonReleaseMask, GrabModeAsync,
936 GrabModeAsync, None, None, CurrentTime);
939 if (!wPreferences.disable_miniwindows) {
940 if (!wwin->flags.icon_moved) {
941 PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y, wGetHeadForWindow(wwin));
943 wwin->icon = wIconCreate(wwin);
945 wwin->icon->mapped = 1;
948 wwin->flags.miniaturized = 1;
949 wwin->flags.mapped = 0;
951 /* unmap transients */
953 unmapTransientsFor(wwin);
955 if (present) {
956 wSoundPlay(WSOUND_ICONIFY);
958 XUngrabPointer(dpy, CurrentTime);
959 wWindowUnmap(wwin);
960 /* let all Expose events arrive so that we can repaint
961 * something before the animation starts (and the server is grabbed) */
962 XSync(dpy, 0);
964 if (wPreferences.disable_miniwindows)
965 wClientSetState(wwin, IconicState, None);
966 else
967 wClientSetState(wwin, IconicState, wwin->icon->icon_win);
969 flushExpose();
970 #ifdef ANIMATIONS
971 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
972 && !wPreferences.no_animations) {
973 int ix, iy, iw, ih;
975 if (!wPreferences.disable_miniwindows) {
976 ix = wwin->icon_x;
977 iy = wwin->icon_y;
978 iw = wwin->icon->core->width;
979 ih = wwin->icon->core->height;
980 } else {
981 #ifdef KWM_HINTS
982 WArea area;
984 if (wKWMGetIconGeometry(wwin, &area)) {
985 ix = area.x1;
986 iy = area.y1;
987 iw = area.x2 - ix;
988 ih = area.y2 - iy;
989 } else
990 #endif /* KWM_HINTS */
992 ix = 0;
993 iy = 0;
994 iw = wwin->screen_ptr->scr_width;
995 ih = wwin->screen_ptr->scr_height;
998 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
999 wwin->frame->core->width, wwin->frame->core->height,
1000 ix, iy, iw, ih, False);
1002 #endif
1005 wwin->flags.skip_next_animation = 0;
1007 if (!wPreferences.disable_miniwindows) {
1009 if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
1010 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)
1012 XMapWindow(dpy, wwin->icon->core->window);
1014 AddToStackList(wwin->icon->core);
1016 wLowerFrame(wwin->icon->core);
1019 if (present) {
1020 WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
1023 * It doesn't seem to be working and causes button event hangup
1024 * when deiconifying a transient window.
1025 setupIconGrabs(wwin->icon);
1027 if ((wwin->flags.focused
1028 || (owner && wwin->client_win == owner->client_win))
1029 && wPreferences.focus_mode==WKF_CLICK) {
1030 WWindow *tmp;
1032 tmp = wwin->prev;
1033 while (tmp) {
1034 if (!WFLAGP(tmp, no_focusable)
1035 && !(tmp->flags.hidden||tmp->flags.miniaturized)
1036 && (wwin->frame->workspace == tmp->frame->workspace))
1037 break;
1038 tmp = tmp->prev;
1040 wSetFocusTo(wwin->screen_ptr, tmp);
1041 } else if (wPreferences.focus_mode!=WKF_CLICK) {
1042 wSetFocusTo(wwin->screen_ptr, NULL);
1045 #ifdef ANIMATIONS
1046 if (!wwin->screen_ptr->flags.startup) {
1047 Window clientwin = wwin->client_win;
1049 XSync(dpy, 0);
1050 processEvents(XPending(dpy));
1052 /* the window can disappear while doing the processEvents() */
1053 if (!wWindowFor(clientwin))
1054 return;
1056 #endif
1060 if (wwin->flags.selected && !wPreferences.disable_miniwindows)
1061 wIconSelect(wwin->icon);
1063 WMPostNotificationName(WMNChangedState, wwin, "iconify");
1069 void
1070 wDeiconifyWindow(WWindow *wwin)
1072 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1074 if (!wwin->flags.miniaturized)
1075 return;
1077 if (wwin->transient_for != None
1078 && wwin->transient_for != wwin->screen_ptr->root_win) {
1079 WWindow *owner = recursiveTransientFor(wwin);
1081 if (owner && owner->flags.miniaturized) {
1082 wDeiconifyWindow(owner);
1083 wSetFocusTo(wwin->screen_ptr, wwin);
1084 wRaiseFrame(wwin->frame->core);
1085 return;
1089 wwin->flags.miniaturized = 0;
1090 if (!wwin->flags.shaded)
1091 wwin->flags.mapped = 1;
1093 if (!wPreferences.disable_miniwindows && wwin->icon != NULL) {
1094 if (wwin->icon->selected)
1095 wIconSelect(wwin->icon);
1097 XUnmapWindow(dpy, wwin->icon->core->window);
1100 wSoundPlay(WSOUND_DEICONIFY);
1102 /* if the window is in another workspace, do it silently */
1103 #ifdef ANIMATIONS
1104 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1105 && !wwin->flags.skip_next_animation && wwin->icon != NULL) {
1106 int ix, iy, iw, ih;
1108 if (!wPreferences.disable_miniwindows) {
1109 ix = wwin->icon_x;
1110 iy = wwin->icon_y;
1111 iw = wwin->icon->core->width;
1112 ih = wwin->icon->core->height;
1113 } else {
1114 #ifdef KWM_HINTS
1115 WArea area;
1117 if (wKWMGetIconGeometry(wwin, &area)) {
1118 ix = area.x1;
1119 iy = area.y1;
1120 iw = area.x2 - ix;
1121 ih = area.y2 - iy;
1122 } else
1123 #endif /* KWM_HINTS */
1125 ix = 0;
1126 iy = 0;
1127 iw = wwin->screen_ptr->scr_width;
1128 ih = wwin->screen_ptr->scr_height;
1131 animateResize(wwin->screen_ptr, ix, iy, iw, ih,
1132 wwin->frame_x, wwin->frame_y,
1133 wwin->frame->core->width, wwin->frame->core->height,
1134 False);
1136 #endif /* ANIMATIONS */
1137 wwin->flags.skip_next_animation = 0;
1138 XGrabServer(dpy);
1139 if (!wwin->flags.shaded) {
1140 XMapWindow(dpy, wwin->client_win);
1142 XMapWindow(dpy, wwin->frame->core->window);
1143 wRaiseFrame(wwin->frame->core);
1144 if (!wwin->flags.shaded) {
1145 wClientSetState(wwin, NormalState, None);
1147 mapTransientsFor(wwin);
1149 if (!wPreferences.disable_miniwindows && wwin->icon != NULL) {
1150 RemoveFromStackList(wwin->icon->core);
1151 /* removeIconGrabs(wwin->icon);*/
1152 wIconDestroy(wwin->icon);
1153 wwin->icon = NULL;
1155 XUngrabServer(dpy);
1157 wSetFocusTo(wwin->screen_ptr, wwin);
1159 #ifdef ANIMATIONS
1160 if (!wwin->screen_ptr->flags.startup) {
1161 Window clientwin = wwin->client_win;
1163 XSync(dpy, 0);
1164 processEvents(XPending(dpy));
1166 if (!wWindowFor(clientwin))
1167 return;
1169 #endif
1171 if (wPreferences.auto_arrange_icons) {
1172 wArrangeIcons(wwin->screen_ptr, True);
1175 WMPostNotificationName(WMNChangedState, wwin, "iconify");
1177 /* In case we were shaded and iconified, also unshade */
1178 wUnshadeWindow(wwin);
1183 static void
1184 hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
1186 if (wwin->flags.miniaturized) {
1187 if (wwin->icon) {
1188 XUnmapWindow(dpy, wwin->icon->core->window);
1189 wwin->icon->mapped = 0;
1191 wwin->flags.hidden = 1;
1193 WMPostNotificationName(WMNChangedState, wwin, "hide");
1194 return;
1197 if (wwin->flags.inspector_open) {
1198 wHideInspectorForWindow(wwin);
1201 wwin->flags.hidden = 1;
1202 wWindowUnmap(wwin);
1204 wClientSetState(wwin, IconicState, icon->icon_win);
1205 flushExpose();
1206 wSoundPlay(WSOUND_HIDE);
1207 #ifdef ANIMATIONS
1208 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1209 !wwin->flags.skip_next_animation && animate) {
1210 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1211 wwin->frame->core->width, wwin->frame->core->height,
1212 icon_x, icon_y, icon->core->width, icon->core->height,
1213 True);
1215 #endif
1216 wwin->flags.skip_next_animation = 0;
1218 WMPostNotificationName(WMNChangedState, wwin, "hide");
1223 void
1224 wHideOtherApplications(WWindow *awin)
1226 WWindow *wwin;
1227 WApplication *tapp;
1229 if (!awin)
1230 return;
1231 wwin = awin->screen_ptr->focused_window;
1234 while (wwin) {
1235 if (wwin!=awin
1236 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1237 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1238 && !wwin->flags.internal_window
1239 && wGetWindowOfInspectorForWindow(wwin) != awin
1240 && !WFLAGP(wwin, no_hide_others)) {
1242 if (wwin->main_window==None || WFLAGP(wwin, no_appicon)) {
1243 if (!WFLAGP(wwin, no_miniaturizable)) {
1244 wwin->flags.skip_next_animation = 1;
1245 wIconifyWindow(wwin);
1247 } else if (wwin->main_window!=None
1248 && awin->main_window != wwin->main_window) {
1249 tapp = wApplicationOf(wwin->main_window);
1250 if (tapp) {
1251 tapp->flags.skip_next_animation = 1;
1252 wHideApplication(tapp);
1253 } else {
1254 if (!WFLAGP(wwin, no_miniaturizable)) {
1255 wwin->flags.skip_next_animation = 1;
1256 wIconifyWindow(wwin);
1261 wwin = wwin->prev;
1264 wSetFocusTo(awin->screen_ptr, awin);
1270 void
1271 wHideApplication(WApplication *wapp)
1273 WScreen *scr;
1274 WWindow *wlist;
1275 int hadfocus;
1277 if (!wapp) {
1278 wwarning("trying to hide a non grouped window");
1279 return;
1281 if (!wapp->main_window_desc) {
1282 wwarning("group leader not found for window group");
1283 return;
1285 scr = wapp->main_window_desc->screen_ptr;
1286 hadfocus = 0;
1287 wlist = scr->focused_window;
1288 if (!wlist)
1289 return;
1291 if (wlist->main_window == wapp->main_window)
1292 wapp->last_focused = wlist;
1293 else
1294 wapp->last_focused = NULL;
1295 while (wlist) {
1296 if (wlist->main_window == wapp->main_window) {
1297 if (wlist->flags.focused) {
1298 hadfocus = 1;
1300 if (wapp->app_icon)
1301 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1302 wapp->app_icon->y_pos, wlist,
1303 !wapp->flags.skip_next_animation);
1305 wlist = wlist->prev;
1308 wapp->flags.skip_next_animation = 0;
1310 if (hadfocus) {
1311 if (wPreferences.focus_mode==WKF_CLICK) {
1312 wlist = scr->focused_window;
1313 while (wlist) {
1314 if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden
1315 && (wlist->flags.mapped || wlist->flags.shaded))
1316 break;
1317 wlist = wlist->prev;
1319 wSetFocusTo(scr, wlist);
1320 } else {
1321 wSetFocusTo(scr, NULL);
1325 wapp->flags.hidden = 1;
1327 if(wPreferences.auto_arrange_icons) {
1328 wArrangeIcons(scr, True);
1330 #ifdef HIDDENDOT
1331 if (wapp->app_icon)
1332 wAppIconPaint(wapp->app_icon);
1333 #endif
1339 static void
1340 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1341 int bringToCurrentWS)
1343 if (bringToCurrentWS)
1344 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1346 wwin->flags.hidden=0;
1348 wSoundPlay(WSOUND_UNHIDE);
1349 #ifdef ANIMATIONS
1350 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1351 && animate) {
1352 animateResize(wwin->screen_ptr, icon_x, icon_y,
1353 icon->core->width, icon->core->height,
1354 wwin->frame_x, wwin->frame_y,
1355 wwin->frame->core->width, wwin->frame->core->height,
1356 True);
1358 #endif
1359 wwin->flags.skip_next_animation = 0;
1360 if (wwin->screen_ptr->current_workspace == wwin->frame->workspace) {
1361 XMapWindow(dpy, wwin->client_win);
1362 XMapWindow(dpy, wwin->frame->core->window);
1363 wClientSetState(wwin, NormalState, None);
1364 wwin->flags.mapped=1;
1365 wRaiseFrame(wwin->frame->core);
1367 if (wwin->flags.inspector_open) {
1368 wUnhideInspectorForWindow(wwin);
1371 WMPostNotificationName(WMNChangedState, wwin, "hide");
1375 void
1376 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1378 WScreen *scr;
1379 WWindow *wlist, *next;
1380 WWindow *focused=NULL;
1381 Bool shouldArrangeIcons = False;
1383 if (!wapp)
1384 return;
1386 scr = wapp->main_window_desc->screen_ptr;
1387 wlist = scr->focused_window;
1388 if (!wlist)
1389 return;
1391 /* goto beginning of list */
1392 while (wlist->prev)
1393 wlist = wlist->prev;
1395 while (wlist) {
1396 next = wlist->next;
1398 if (wlist->main_window == wapp->main_window) {
1399 if (wlist->flags.focused)
1400 focused = wlist;
1401 else if (!focused || !focused->flags.focused)
1402 focused = wlist;
1404 if (wlist->flags.miniaturized) {
1405 if (bringToCurrentWS || wPreferences.sticky_icons ||
1406 wlist->frame->workspace == scr->current_workspace) {
1407 if (wlist->icon && !wlist->icon->mapped) {
1408 XMapWindow(dpy, wlist->icon->core->window);
1409 wlist->icon->mapped = 1;
1412 if (bringToCurrentWS)
1413 wWindowChangeWorkspace(wlist, scr->current_workspace);
1414 wlist->flags.hidden = 0;
1415 if (miniwindows &&
1416 wlist->frame->workspace == scr->current_workspace) {
1417 wDeiconifyWindow(wlist);
1419 shouldArrangeIcons = True;
1420 WMPostNotificationName(WMNChangedState, wlist, "hide");
1421 } else if (wlist->flags.shaded) {
1422 if (bringToCurrentWS)
1423 wWindowChangeWorkspace(wlist, scr->current_workspace);
1424 wlist->flags.hidden = 0;
1425 if (wlist->frame->workspace == scr->current_workspace) {
1426 XMapWindow(dpy, wlist->frame->core->window);
1427 if (miniwindows) {
1428 wUnshadeWindow(wlist);
1429 wRaiseFrame(wlist->frame->core);
1432 WMPostNotificationName(WMNChangedState, wlist, "hide");
1433 } else if (wlist->flags.hidden) {
1434 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1435 wapp->app_icon->y_pos, wlist,
1436 !wapp->flags.skip_next_animation,
1437 bringToCurrentWS);
1438 } else {
1439 if (bringToCurrentWS
1440 && wlist->frame->workspace != scr->current_workspace) {
1441 wWindowChangeWorkspace(wlist, scr->current_workspace);
1443 wRaiseFrame(wlist->frame->core);
1446 wlist = next;
1449 wapp->flags.skip_next_animation = 0;
1450 wapp->flags.hidden = 0;
1452 if (wapp->last_focused && wapp->last_focused->flags.mapped) {
1453 wRaiseFrame(wapp->last_focused->frame->core);
1454 wSetFocusTo(scr, wapp->last_focused);
1455 } else if (focused) {
1456 wSetFocusTo(scr, focused);
1458 wapp->last_focused = NULL;
1459 if (shouldArrangeIcons || wPreferences.auto_arrange_icons) {
1460 wArrangeIcons(scr, True);
1462 #ifdef HIDDENDOT
1463 wAppIconPaint(wapp->app_icon);
1464 #endif
1469 void
1470 wShowAllWindows(WScreen *scr)
1472 WWindow *wwin, *old_foc;
1473 WApplication *wapp;
1475 old_foc = wwin = scr->focused_window;
1476 while (wwin) {
1477 if (!wwin->flags.internal_window &&
1478 (scr->current_workspace == wwin->frame->workspace
1479 || IS_OMNIPRESENT(wwin))) {
1480 if (wwin->flags.miniaturized) {
1481 wwin->flags.skip_next_animation = 1;
1482 wDeiconifyWindow(wwin);
1483 } else if (wwin->flags.hidden) {
1484 wapp = wApplicationOf(wwin->main_window);
1485 if (wapp) {
1486 wUnhideApplication(wapp, False, False);
1487 } else {
1488 wwin->flags.skip_next_animation = 1;
1489 wDeiconifyWindow(wwin);
1493 wwin = wwin->prev;
1495 wSetFocusTo(scr, old_foc);
1496 /*wRaiseFrame(old_foc->frame->core);*/
1500 void
1501 wRefreshDesktop(WScreen *scr)
1503 Window win;
1504 XSetWindowAttributes attr;
1506 attr.backing_store = NotUseful;
1507 attr.save_under = False;
1508 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1509 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1510 (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
1511 &attr);
1512 XMapRaised(dpy, win);
1513 XDestroyWindow(dpy, win);
1514 XFlush(dpy);
1518 void
1519 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1521 WWindow *wwin;
1522 WAppIcon *aicon;
1524 int head;
1525 const int heads = wXineramaHeads(scr);
1527 struct {
1528 int pf; /* primary axis */
1529 int sf; /* secondary axis */
1530 int fullW;
1531 int fullH;
1532 int pi, si;
1533 int sx1, sx2, sy1, sy2; /* screen boundary */
1534 int sw, sh;
1535 int xo, yo;
1536 int xs, ys;
1537 } vars[heads];
1539 int isize = wPreferences.icon_size;
1541 for (head = 0; head < heads; ++head) {
1542 #if 0
1543 WMRect rect = wGetRectForHead(scr, head);
1544 #else
1545 WArea area = wGetUsableAreaForHead(scr, head, NULL, False);
1546 WMRect rect = (WMRect){ area.x1, area.y1, area.x2-area.x1, area.y2-area.y1 };
1547 #endif
1549 vars[head].pi = vars[head].si = 0;
1550 vars[head].sx1 = rect.pos.x;
1551 vars[head].sy1 = rect.pos.y;
1552 vars[head].sw = rect.size.width;
1553 vars[head].sh = rect.size.height;
1554 vars[head].sx2 = vars[head].sx1 + vars[head].sw;
1555 vars[head].sy2 = vars[head].sy1 + vars[head].sh;
1557 #if 0
1558 if (scr->dock) {
1559 if (scr->dock->on_right_side)
1560 vars[head].sx2 -= isize + DOCK_EXTRA_SPACE;
1561 else
1562 vars[head].sx1 += isize + DOCK_EXTRA_SPACE;
1564 #endif
1566 vars[head].sw = isize * (vars[head].sw/isize);
1567 vars[head].sh = isize * (vars[head].sh/isize);
1568 vars[head].fullW = (vars[head].sx2-vars[head].sx1)/isize;
1569 vars[head].fullH = (vars[head].sy2-vars[head].sy1)/isize;
1571 /* icon yard boundaries */
1572 if (wPreferences.icon_yard & IY_VERT) {
1573 vars[head].pf = vars[head].fullH;
1574 vars[head].sf = vars[head].fullW;
1575 } else {
1576 vars[head].pf = vars[head].fullW;
1577 vars[head].sf = vars[head].fullH;
1579 if (wPreferences.icon_yard & IY_RIGHT) {
1580 vars[head].xo = vars[head].sx2 - isize;
1581 vars[head].xs = -1;
1582 } else {
1583 vars[head].xo = vars[head].sx1;
1584 vars[head].xs = 1;
1586 if (wPreferences.icon_yard & IY_TOP) {
1587 vars[head].yo = vars[head].sy1;
1588 vars[head].ys = 1;
1589 } else {
1590 vars[head].yo = vars[head].sy2 - isize;
1591 vars[head].ys = -1;
1595 #define X ((wPreferences.icon_yard & IY_VERT) \
1596 ? vars[head].xo + vars[head].xs*(vars[head].si*isize) \
1597 : vars[head].xo + vars[head].xs*(vars[head].pi*isize))
1599 #define Y ((wPreferences.icon_yard & IY_VERT) \
1600 ? vars[head].yo + vars[head].ys*(vars[head].pi*isize) \
1601 : vars[head].yo + vars[head].ys*(vars[head].si*isize))
1604 /* arrange application icons */
1605 aicon = scr->app_icon_list;
1606 /* reverse them to avoid unnecessarily sliding of icons */
1607 while (aicon && aicon->next)
1608 aicon = aicon->next;
1610 while (aicon) {
1611 if (!aicon->docked) {
1612 /* XXX: can: icon == NULL ? */
1613 /* The intention here is to place the AppIcon on the head that contains most of the applications _main_ window. */
1614 /* printf( "appicon: %x %x\n", aicon->icon->core->window, aicon->main_window); */
1615 head = wGetHeadForWindow(aicon->icon->owner);
1617 if (aicon->x_pos != X || aicon->y_pos != Y) {
1618 #ifdef ANIMATIONS
1619 if (!wPreferences.no_animations) {
1620 SlideWindow(aicon->icon->core->window,
1621 aicon->x_pos, aicon->y_pos, X, Y);
1623 #endif /* ANIMATIONS */
1625 wAppIconMove(aicon, X, Y);
1626 vars[head].pi++;
1627 if (vars[head].pi >= vars[head].pf) {
1628 vars[head].pi = 0;
1629 vars[head].si++;
1632 aicon = aicon->prev;
1635 /* arrange miniwindows */
1636 wwin = scr->focused_window;
1637 /* reverse them to avoid unnecessarily shuffling */
1638 while (wwin && wwin->prev)
1639 wwin = wwin->prev;
1641 while (wwin) {
1642 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1643 (wwin->frame->workspace==scr->current_workspace ||
1644 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1646 head = wGetHeadForWindow(wwin);
1648 if (arrangeAll || !wwin->flags.icon_moved) {
1649 if (wwin->icon_x != X || wwin->icon_y != Y) {
1650 #ifdef ANIMATIONS
1651 if (wPreferences.no_animations) {
1652 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1653 } else {
1654 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1655 wwin->icon_y, X, Y);
1657 #else
1658 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1659 #endif /* ANIMATIONS */
1661 wwin->icon_x = X;
1662 wwin->icon_y = Y;
1664 vars[head].pi++;
1665 if (vars[head].pi >= vars[head].pf) {
1666 vars[head].pi = 0;
1667 vars[head].si++;
1671 if (arrangeAll) {
1672 wwin->flags.icon_moved = 0;
1674 /* we reversed the order, so we use next */
1675 wwin = wwin->next;
1679 #if 0
1680 void
1681 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1683 WWindow *wwin;
1684 WAppIcon *aicon;
1685 int pf; /* primary axis */
1686 int sf; /* secondary axis */
1687 int fullW;
1688 int fullH;
1689 int pi, si;
1690 int sx1, sx2, sy1, sy2; /* screen boundary */
1691 int sw, sh;
1692 int xo, yo;
1693 int xs, ys;
1694 int isize = wPreferences.icon_size;
1697 * Find out screen boundaries.
1701 * Allows each head to have miniwindows
1703 WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
1705 sx1 = rect.pos.x;
1706 sy1 = rect.pos.y;
1707 sw = rect.size.width;
1708 sh = rect.size.height;
1709 sx2 = sx1 + sw;
1710 sy2 = sy1 + sh;
1711 if (scr->dock) {
1712 if (scr->dock->on_right_side)
1713 sx2 -= isize + DOCK_EXTRA_SPACE;
1714 else
1715 sx1 += isize + DOCK_EXTRA_SPACE;
1718 #if 0
1719 sw = isize * (scr->scr_width/isize);
1720 sh = isize * (scr->scr_height/isize);
1721 #else
1722 sw = isize * (sw/isize);
1723 sh = isize * (sh/isize);
1724 #endif
1725 fullW = (sx2-sx1)/isize;
1726 fullH = (sy2-sy1)/isize;
1728 /* icon yard boundaries */
1729 if (wPreferences.icon_yard & IY_VERT) {
1730 pf = fullH;
1731 sf = fullW;
1732 } else {
1733 pf = fullW;
1734 sf = fullH;
1736 if (wPreferences.icon_yard & IY_RIGHT) {
1737 xo = sx2 - isize;
1738 xs = -1;
1739 } else {
1740 xo = sx1;
1741 xs = 1;
1743 if (wPreferences.icon_yard & IY_TOP) {
1744 yo = sy1;
1745 ys = 1;
1746 } else {
1747 yo = sy2 - isize;
1748 ys = -1;
1751 /* arrange icons putting the most recently focused window
1752 * as the last icon */
1753 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1754 : xo + xs*(pi*isize))
1755 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1756 : yo + ys*(si*isize))
1758 /* arrange application icons */
1759 aicon = scr->app_icon_list;
1760 /* reverse them to avoid unnecessarily sliding of icons */
1761 while (aicon && aicon->next)
1762 aicon = aicon->next;
1764 pi = 0;
1765 si = 0;
1766 while (aicon) {
1767 if (!aicon->docked) {
1768 if (aicon->x_pos != X || aicon->y_pos != Y) {
1769 #ifdef ANIMATIONS
1770 if (!wPreferences.no_animations) {
1771 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1772 X, Y);
1774 #endif /* ANIMATIONS */
1776 wAppIconMove(aicon, X, Y);
1777 pi++;
1779 /* we reversed the order so we use prev */
1780 aicon = aicon->prev;
1781 if (pi >= pf) {
1782 pi=0;
1783 si++;
1787 /* arrange miniwindows */
1789 wwin = scr->focused_window;
1790 /* reverse them to avoid unnecessarily shuffling */
1791 while (wwin && wwin->prev)
1792 wwin = wwin->prev;
1794 while (wwin) {
1795 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1796 (wwin->frame->workspace==scr->current_workspace ||
1797 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1799 if (arrangeAll || !wwin->flags.icon_moved) {
1800 if (wwin->icon_x != X || wwin->icon_y != Y) {
1801 #ifdef ANIMATIONS
1802 if (wPreferences.no_animations) {
1803 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1804 } else {
1805 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1806 wwin->icon_y, X, Y);
1808 #else
1809 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1810 #endif /* ANIMATIONS */
1812 wwin->icon_x = X;
1813 wwin->icon_y = Y;
1814 pi++;
1817 if (arrangeAll) {
1818 wwin->flags.icon_moved = 0;
1820 /* we reversed the order, so we use next */
1821 wwin = wwin->next;
1822 if (pi >= pf) {
1823 pi=0;
1824 si++;
1828 #endif
1830 void
1831 wSelectWindow(WWindow *wwin, Bool flag)
1833 WScreen *scr = wwin->screen_ptr;
1835 if (flag) {
1836 wwin->flags.selected = 1;
1837 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1839 if (WFLAGP(wwin, no_border)) {
1840 XSetWindowBorderWidth(dpy, wwin->frame->core->window,
1841 FRAME_BORDER_WIDTH);
1844 if (!scr->selected_windows)
1845 scr->selected_windows = WMCreateArray(4);
1846 WMAddToArray(scr->selected_windows, wwin);
1847 } else {
1848 wwin->flags.selected = 0;
1849 XSetWindowBorder(dpy, wwin->frame->core->window,
1850 scr->frame_border_pixel);
1852 if (WFLAGP(wwin, no_border)) {
1853 XSetWindowBorderWidth(dpy, wwin->frame->core->window, 0);
1856 if (scr->selected_windows) {
1857 WMRemoveFromArray(scr->selected_windows, wwin);
1863 void
1864 wMakeWindowVisible(WWindow *wwin)
1866 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
1867 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1869 if (wwin->flags.shaded) {
1870 wUnshadeWindow(wwin);
1872 if (wwin->flags.hidden) {
1873 WApplication *app;
1875 app = wApplicationOf(wwin->main_window);
1876 if (app) {
1877 /* trick to get focus to this window */
1878 app->last_focused = wwin;
1879 wUnhideApplication(app, False, False);
1882 if (wwin->flags.miniaturized) {
1883 wDeiconifyWindow(wwin);
1884 } else {
1885 if (!WFLAGP(wwin, no_focusable))
1886 wSetFocusTo(wwin->screen_ptr, wwin);
1887 wRaiseFrame(wwin->frame->core);