update before moving to xft2
[wmaker-crm.git] / src / actions.c
blob47f428813ae9070b069435db61b0aba0eea1ba47
1 /* action.c- misc. window commands (miniaturize, hide etc.)
3 * Window Maker window manager
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * Copyright (c) 1998-2003 Dan Pascu
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;
148 * Safeguard: make sure the timestamp is monotonically increasing
149 * (very unlikely that this will be needed, still a safeguard)
151 if (timestamp <= LastFocusChange)
152 timestamp = LastFocusChange + 1;
154 LastFocusChange = timestamp;
157 * This is a hack, because XSetInputFocus() should have a proper
158 * timestamp instead of CurrentTime but it seems that some times
159 * clients will not receive focus properly that way.
161 if (ignoreTimestamp)
162 timestamp = CurrentTime;
164 if (old_focused)
165 oapp = wApplicationOf(old_focused->main_window);
167 if (wwin == NULL) {
168 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
169 if (old_focused) {
170 wWindowUnfocus(old_focused);
172 if (oapp) {
173 wAppMenuUnmap(oapp->menu);
174 #ifdef NEWAPPICON
175 wApplicationDeactivate(oapp);
176 #endif
179 WMPostNotificationName(WMNChangedFocus, NULL, (void*)True);
180 return;
181 } else if (old_scr != scr && old_focused) {
182 wWindowUnfocus(old_focused);
185 wasfocused = wwin->flags.focused;
186 napp = wApplicationOf(wwin->main_window);
188 /* remember last workspace where the app has been */
189 if (napp) {
190 /*napp->last_workspace = wwin->screen_ptr->current_workspace;*/
191 napp->last_workspace = wwin->frame->workspace;
194 if (wwin->flags.mapped && !WFLAGP(wwin, no_focusable)) {
195 /* install colormap if colormap mode is lock mode */
196 if (wPreferences.colormap_mode==WCM_CLICK)
197 wColormapInstallForWindow(scr, wwin);
199 /* set input focus */
200 switch (wwin->focus_mode) {
201 case WFM_NO_INPUT:
202 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
203 break;
205 case WFM_PASSIVE:
206 case WFM_LOCALLY_ACTIVE:
207 XSetInputFocus(dpy, wwin->client_win, RevertToParent, timestamp);
208 break;
210 case WFM_GLOBALLY_ACTIVE:
211 break;
213 XFlush(dpy);
214 if (wwin->protocols.TAKE_FOCUS) {
215 wClientSendProtocol(wwin, _XA_WM_TAKE_FOCUS, timestamp);
217 XSync(dpy, False);
218 } else {
219 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
221 if (WFLAGP(wwin, no_focusable))
222 return;
224 /* if this is not the focused window focus it */
225 if (focused!=wwin) {
226 /* change the focus window list order */
227 if (wwin->prev)
228 wwin->prev->next = wwin->next;
230 if (wwin->next)
231 wwin->next->prev = wwin->prev;
233 wwin->prev = focused;
234 focused->next = wwin;
235 wwin->next = NULL;
236 scr->focused_window = wwin;
238 if (oapp && oapp != napp) {
239 wAppMenuUnmap(oapp->menu);
240 #ifdef NEWAPPICON
241 wApplicationDeactivate(oapp);
242 #endif
246 wWindowFocus(wwin, focused);
248 if (napp && !wasfocused) {
249 #ifdef USER_MENU
250 wUserMenuRefreshInstances(napp->menu, wwin);
251 #endif /* USER_MENU */
253 if (wwin->flags.mapped)
254 wAppMenuMap(napp->menu, wwin);
255 #ifdef NEWAPPICON
256 wApplicationActivate(napp);
257 #endif
260 XFlush(dpy);
261 old_scr=scr;
265 void
266 wShadeWindow(WWindow *wwin)
268 time_t time0;
269 #ifdef ANIMATIONS
270 int y, s, w, h;
271 #endif
273 if (wwin->flags.shaded)
274 return;
276 time0 = time(NULL);
278 XLowerWindow(dpy, wwin->client_win);
280 wSoundPlay(WSOUND_SHADE);
282 #ifdef ANIMATIONS
283 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
284 && !wPreferences.no_animations) {
285 /* do the shading animation */
286 h = wwin->frame->core->height;
287 s = h/SHADE_STEPS;
288 if (s < 1) s=1;
289 w = wwin->frame->core->width;
290 y = wwin->frame->top_width;
291 while (h>wwin->frame->top_width+1) {
292 XMoveWindow(dpy, wwin->client_win, 0, y);
293 XResizeWindow(dpy, wwin->frame->core->window, w, h);
294 XFlush(dpy);
296 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
297 break;
299 if (SHADE_DELAY > 0) {
300 wusleep(SHADE_DELAY*1000L);
301 } else {
302 wusleep(10);
304 h-=s;
305 y-=s;
307 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
309 #endif /* ANIMATIONS */
311 wwin->flags.skip_next_animation = 0;
312 wwin->flags.shaded = 1;
313 wwin->flags.mapped = 0;
314 /* prevent window withdrawal when getting UnmapNotify */
315 XSelectInput(dpy, wwin->client_win,
316 wwin->event_mask & ~StructureNotifyMask);
317 XUnmapWindow(dpy, wwin->client_win);
318 XSelectInput(dpy, wwin->client_win, wwin->event_mask);
320 /* for the client it's just like iconification */
321 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
322 wwin->frame->top_width - 1);
324 wwin->client.y = wwin->frame_y - wwin->client.height
325 + wwin->frame->top_width;
326 wWindowSynthConfigureNotify(wwin);
329 wClientSetState(wwin, IconicState, None);
332 WMPostNotificationName(WMNChangedState, wwin, "shade");
334 #ifdef ANIMATIONS
335 if (!wwin->screen_ptr->flags.startup) {
336 /* Look at processEvents() for reason of this code. */
337 XSync(dpy, 0);
338 processEvents(XPending(dpy));
340 #endif
344 void
345 wUnshadeWindow(WWindow *wwin)
347 time_t time0;
348 #ifdef ANIMATIONS
349 int y, s, w, h;
350 #endif /* ANIMATIONS */
353 if (!wwin->flags.shaded)
354 return;
356 time0 = time(NULL);
358 wwin->flags.shaded = 0;
359 wwin->flags.mapped = 1;
360 XMapWindow(dpy, wwin->client_win);
362 wSoundPlay(WSOUND_UNSHADE);
364 #ifdef ANIMATIONS
365 if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) {
366 /* do the shading animation */
367 h = wwin->frame->top_width + wwin->frame->bottom_width;
368 y = wwin->frame->top_width - wwin->client.height;
369 s = abs(y)/SHADE_STEPS;
370 if (s<1) s=1;
371 w = wwin->frame->core->width;
372 XMoveWindow(dpy, wwin->client_win, 0, y);
373 if (s>0) {
374 while (h < wwin->client.height + wwin->frame->top_width
375 + wwin->frame->bottom_width) {
376 XResizeWindow(dpy, wwin->frame->core->window, w, h);
377 XMoveWindow(dpy, wwin->client_win, 0, y);
378 XFlush(dpy);
379 if (SHADE_DELAY > 0) {
380 wusleep(SHADE_DELAY*2000L/3);
381 } else {
382 wusleep(10);
384 h+=s;
385 y+=s;
387 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
388 break;
391 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
393 #endif /* ANIMATIONS */
395 wwin->flags.skip_next_animation = 0;
396 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
397 wwin->frame->top_width + wwin->client.height
398 + wwin->frame->bottom_width);
400 wwin->client.y = wwin->frame_y + wwin->frame->top_width;
401 wWindowSynthConfigureNotify(wwin);
404 wClientSetState(wwin, NormalState, None);
406 /* if the window is focused, set the focus again as it was disabled during
407 * shading */
408 if (wwin->flags.focused)
409 wSetFocusTo(wwin->screen_ptr, wwin);
411 WMPostNotificationName(WMNChangedState, wwin, "shade");
415 void
416 wMaximizeWindow(WWindow *wwin, int directions)
418 int new_width, new_height, new_x, new_y;
419 int changed_h, changed_v, shrink_h, shrink_v;
420 WArea usableArea, totalArea;
422 if (WFLAGP(wwin, no_resizable))
423 return;
425 totalArea.x1 = 0;
426 totalArea.y1 = 0;
427 totalArea.x2 = wwin->screen_ptr->scr_width;
428 totalArea.y2 = wwin->screen_ptr->scr_height;
429 usableArea = totalArea;
431 if (!(directions & MAX_IGNORE_XINERAMA)) {
432 WScreen *scr = wwin->screen_ptr;
433 int head;
435 if (directions & MAX_KEYBOARD)
436 head = wGetHeadForWindow(wwin);
437 else
438 head = wGetHeadForPointerLocation(scr);
440 usableArea = wGetUsableAreaForHead(scr, head, &totalArea, True);
443 if (WFLAGP(wwin, full_maximize)) {
444 usableArea = totalArea;
447 if (wwin->flags.shaded) {
448 wwin->flags.skip_next_animation = 1;
449 wUnshadeWindow(wwin);
451 /* Only save directions, not kbd or xinerama hints */
452 directions &= (MAX_HORIZONTAL|MAX_VERTICAL);
454 changed_h = ((wwin->flags.maximized ^ directions) & MAX_HORIZONTAL);
455 changed_v = ((wwin->flags.maximized ^ directions) & MAX_VERTICAL);
456 shrink_h = (changed_h && (directions & MAX_HORIZONTAL)==0);
457 shrink_v = (changed_v && (directions & MAX_VERTICAL)==0);
459 if (wwin->flags.maximized) {
460 /* if already maximized in some direction, we only update the
461 * appropriate old x, old y coordinates. This is necessary to
462 * allow succesive maximizations in different directions without
463 * the need to first do an un-maximize (to avoid flicker).
465 if (!(wwin->flags.maximized & MAX_HORIZONTAL)) {
466 wwin->old_geometry.x = wwin->frame_x;
468 if (!(wwin->flags.maximized & MAX_VERTICAL)) {
469 wwin->old_geometry.y = wwin->frame_y;
471 } else {
472 wwin->old_geometry.width = wwin->client.width;
473 wwin->old_geometry.height = wwin->client.height;
474 wwin->old_geometry.x = wwin->frame_x;
475 wwin->old_geometry.y = wwin->frame_y;
477 wwin->flags.maximized = directions;
479 #ifdef KWM_HINTS
480 wKWMUpdateClientGeometryRestore(wwin);
481 #endif
483 if (directions & MAX_HORIZONTAL) {
484 new_width = (usableArea.x2-usableArea.x1)-FRAME_BORDER_WIDTH*2;
485 new_x = usableArea.x1;
486 } else if (shrink_h) {
487 new_x = wwin->old_geometry.x;
488 new_width = wwin->old_geometry.width;
489 } else {
490 new_x = wwin->frame_x;
491 new_width = wwin->frame->core->width;
494 if (directions & MAX_VERTICAL) {
495 new_height = (usableArea.y2-usableArea.y1)-FRAME_BORDER_WIDTH*2;
496 new_y = usableArea.y1;
497 if (WFLAGP(wwin, full_maximize)) {
498 new_y -= wwin->frame->top_width;
499 new_height += wwin->frame->bottom_width - 1;
501 } else if (shrink_v) {
502 new_y = wwin->old_geometry.y;
503 new_height = wwin->old_geometry.height;
504 } else {
505 new_y = wwin->frame_y;
506 new_height = wwin->frame->core->height;
509 if (!WFLAGP(wwin, full_maximize)) {
510 new_height -= wwin->frame->top_width+wwin->frame->bottom_width;
513 wWindowConstrainSize(wwin, &new_width, &new_height);
515 wWindowCropSize(wwin, usableArea.x2-usableArea.x1,
516 usableArea.y2-usableArea.y1,
517 &new_width, &new_height);
519 wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
522 WMPostNotificationName(WMNChangedState, wwin, "maximize");
524 wSoundPlay(WSOUND_MAXIMIZE);
528 void
529 wUnmaximizeWindow(WWindow *wwin)
531 int restore_x, restore_y;
533 if (!wwin->flags.maximized)
534 return;
536 if (wwin->flags.shaded) {
537 wwin->flags.skip_next_animation = 1;
538 wUnshadeWindow(wwin);
540 restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ?
541 wwin->old_geometry.x : wwin->frame_x;
542 restore_y = (wwin->flags.maximized & MAX_VERTICAL) ?
543 wwin->old_geometry.y : wwin->frame_y;
544 wwin->flags.maximized = 0;
545 wWindowConfigure(wwin, restore_x, restore_y,
546 wwin->old_geometry.width, wwin->old_geometry.height);
548 WMPostNotificationName(WMNChangedState, wwin, "maximize");
550 wSoundPlay(WSOUND_UNMAXIMIZE);
553 #ifdef ANIMATIONS
554 static void
555 animateResizeFlip(WScreen *scr, int x, int y, int w, int h,
556 int fx, int fy, int fw, int fh, int steps)
558 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
559 float cx, cy, cw, ch;
560 float xstep, ystep, wstep, hstep;
561 XPoint points[5];
562 float dx, dch, midy;
563 float angle, final_angle, delta;
565 xstep = (float)(fx-x)/steps;
566 ystep = (float)(fy-y)/steps;
567 wstep = (float)(fw-w)/steps;
568 hstep = (float)(fh-h)/steps;
570 cx = (float)x;
571 cy = (float)y;
572 cw = (float)w;
573 ch = (float)h;
575 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F;
576 delta = (float)(final_angle/FRAMES);
577 for (angle=0;; angle+=delta) {
578 if (angle > final_angle)
579 angle = final_angle;
581 dx = (cw/10) - ((cw/5) * sin(angle));
582 dch = (ch/2) * cos(angle);
583 midy = cy + (ch/2);
585 points[0].x = cx + dx; points[0].y = midy - dch;
586 points[1].x = cx + cw - dx; points[1].y = points[0].y;
587 points[2].x = cx + cw + dx; points[2].y = midy + dch;
588 points[3].x = cx - dx; points[3].y = points[2].y;
589 points[4].x = points[0].x; points[4].y = points[0].y;
591 XGrabServer(dpy);
592 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
593 XFlush(dpy);
594 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
595 wusleep(MINIATURIZE_ANIMATION_DELAY_F);
596 #else
597 wusleep(10);
598 #endif
600 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
601 XUngrabServer(dpy);
602 cx+=xstep;
603 cy+=ystep;
604 cw+=wstep;
605 ch+=hstep;
606 if (angle >= final_angle)
607 break;
610 XFlush(dpy);
612 #undef FRAMES
615 static void
616 animateResizeTwist(WScreen *scr, int x, int y, int w, int h,
617 int fx, int fy, int fw, int fh, int steps)
619 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
620 float cx, cy, cw, ch;
621 float xstep, ystep, wstep, hstep;
622 XPoint points[5];
623 float angle, final_angle, a, d, delta;
625 x += w/2;
626 y += h/2;
627 fx += fw/2;
628 fy += fh/2;
630 xstep = (float)(fx-x)/steps;
631 ystep = (float)(fy-y)/steps;
632 wstep = (float)(fw-w)/steps;
633 hstep = (float)(fh-h)/steps;
635 cx = (float)x;
636 cy = (float)y;
637 cw = (float)w;
638 ch = (float)h;
640 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T;
641 delta = (float)(final_angle/FRAMES);
642 for (angle=0;; angle+=delta) {
643 if (angle > final_angle)
644 angle = final_angle;
646 a = atan(ch/cw);
647 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
649 points[0].x = cx+cos(angle-a)*d;
650 points[0].y = cy+sin(angle-a)*d;
651 points[1].x = cx+cos(angle+a)*d;
652 points[1].y = cy+sin(angle+a)*d;
653 points[2].x = cx+cos(angle-a+WM_PI)*d;
654 points[2].y = cy+sin(angle-a+WM_PI)*d;
655 points[3].x = cx+cos(angle+a+WM_PI)*d;
656 points[3].y = cy+sin(angle+a+WM_PI)*d;
657 points[4].x = cx+cos(angle-a)*d;
658 points[4].y = cy+sin(angle-a)*d;
659 XGrabServer(dpy);
660 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
661 XFlush(dpy);
662 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
663 wusleep(MINIATURIZE_ANIMATION_DELAY_T);
664 #else
665 wusleep(10);
666 #endif
668 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
669 XUngrabServer(dpy);
670 cx+=xstep;
671 cy+=ystep;
672 cw+=wstep;
673 ch+=hstep;
674 if (angle >= final_angle)
675 break;
678 XFlush(dpy);
680 #undef FRAMES
683 static void
684 animateResizeZoom(WScreen *scr, int x, int y, int w, int h,
685 int fx, int fy, int fw, int fh, int steps)
687 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
688 float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
689 float xstep, ystep, wstep, hstep;
690 int i, j;
692 xstep = (float)(fx-x)/steps;
693 ystep = (float)(fy-y)/steps;
694 wstep = (float)(fw-w)/steps;
695 hstep = (float)(fh-h)/steps;
697 for (j=0; j<FRAMES; j++) {
698 cx[j] = (float)x;
699 cy[j] = (float)y;
700 cw[j] = (float)w;
701 ch[j] = (float)h;
703 XGrabServer(dpy);
704 for (i=0; i<steps; i++) {
705 for (j=0; j<FRAMES; j++) {
706 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
707 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
709 XFlush(dpy);
710 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
711 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
712 #else
713 wusleep(10);
714 #endif
715 for (j=0; j<FRAMES; j++) {
716 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
717 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
718 if (j<FRAMES-1) {
719 cx[j]=cx[j+1];
720 cy[j]=cy[j+1];
721 cw[j]=cw[j+1];
722 ch[j]=ch[j+1];
723 } else {
724 cx[j]+=xstep;
725 cy[j]+=ystep;
726 cw[j]+=wstep;
727 ch[j]+=hstep;
732 for (j=0; j<FRAMES; j++) {
733 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
734 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
736 XFlush(dpy);
737 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
738 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
739 #else
740 wusleep(10);
741 #endif
742 for (j=0; j<FRAMES; j++) {
743 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
744 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
747 XUngrabServer(dpy);
749 #undef FRAMES
752 void
753 animateResize(WScreen *scr, int x, int y, int w, int h,
754 int fx, int fy, int fw, int fh, int hiding)
756 int style = wPreferences.iconification_style; /* Catch the value */
757 int steps, k;
759 if (style == WIS_NONE)
760 return;
762 if (style == WIS_RANDOM) {
763 style = rand()%3;
766 k = (hiding ? 2 : 3);
767 switch(style) {
768 case WIS_TWIST:
769 steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
770 if (steps>0)
771 animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
772 break;
773 case WIS_FLIP:
774 steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
775 if (steps>0)
776 animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
777 break;
778 case WIS_ZOOM:
779 default:
780 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
781 if (steps>0)
782 animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
783 break;
786 #endif /* ANIMATIONS */
789 static void
790 flushExpose()
792 XEvent tmpev;
794 while (XCheckTypedEvent(dpy, Expose, &tmpev))
795 WMHandleEvent(&tmpev);
796 XSync(dpy, 0);
799 static void
800 unmapTransientsFor(WWindow *wwin)
802 WWindow *tmp;
805 tmp = wwin->screen_ptr->focused_window;
806 while (tmp) {
807 /* unmap the transients for this transient */
808 if (tmp!=wwin && tmp->transient_for == wwin->client_win
809 && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
810 || tmp->flags.shaded)) {
811 unmapTransientsFor(tmp);
812 tmp->flags.miniaturized = 1;
813 if (!tmp->flags.shaded) {
814 wWindowUnmap(tmp);
815 } else {
816 XUnmapWindow(dpy, tmp->frame->core->window);
819 if (!tmp->flags.shaded)
821 wClientSetState(tmp, IconicState, None);
823 WMPostNotificationName(WMNChangedState, tmp, "iconify-transient");
825 tmp = tmp->prev;
830 static void
831 mapTransientsFor(WWindow *wwin)
833 WWindow *tmp;
835 tmp = wwin->screen_ptr->focused_window;
836 while (tmp) {
837 /* recursively map the transients for this transient */
838 if (tmp!=wwin && tmp->transient_for == wwin->client_win
839 && /*!tmp->flags.mapped*/ tmp->flags.miniaturized
840 && tmp->icon==NULL) {
841 mapTransientsFor(tmp);
842 tmp->flags.miniaturized = 0;
843 if (!tmp->flags.shaded) {
844 wWindowMap(tmp);
845 } else {
846 XMapWindow(dpy, tmp->frame->core->window);
848 tmp->flags.semi_focused = 0;
850 if (!tmp->flags.shaded)
852 wClientSetState(tmp, NormalState, None);
854 WMPostNotificationName(WMNChangedState, tmp, "iconify-transient");
856 tmp = tmp->prev;
860 #if 0
861 static void
862 setupIconGrabs(WIcon *icon)
864 /* setup passive grabs on the icon */
865 XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
866 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
867 XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
868 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
869 XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
870 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
871 XSync(dpy, 0);
873 #endif
875 static WWindow*
876 recursiveTransientFor(WWindow *wwin)
878 int i;
880 if (!wwin)
881 return None;
883 /* hackish way to detect transient_for cycle */
884 i = wwin->screen_ptr->window_count+1;
886 while (wwin && wwin->transient_for != None && i>0) {
887 wwin = wWindowFor(wwin->transient_for);
888 i--;
890 if (i==0 && wwin) {
891 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
892 wwin->frame->title);
893 return NULL;
896 return wwin;
899 #if 0
900 static void
901 removeIconGrabs(WIcon *icon)
903 /* remove passive grabs on the icon */
904 XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
905 XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
906 XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);
907 XSync(dpy, 0);
909 #endif
912 void
913 wIconifyWindow(WWindow *wwin)
915 XWindowAttributes attribs;
916 int present;
919 if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
920 /* the window doesn't exist anymore */
921 return;
924 if (wwin->flags.miniaturized) {
925 return;
928 if (wwin->transient_for!=None &&
929 wwin->transient_for!=wwin->screen_ptr->root_win) {
930 WWindow *owner = wWindowFor(wwin->transient_for);
932 if (owner && owner->flags.miniaturized)
933 return;
936 present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
938 /* if the window is in another workspace, simplify process */
939 if (present) {
940 /* icon creation may take a while */
941 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
942 ButtonMotionMask|ButtonReleaseMask, GrabModeAsync,
943 GrabModeAsync, None, None, CurrentTime);
946 if (!wPreferences.disable_miniwindows) {
947 if (!wwin->flags.icon_moved) {
948 PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y, wGetHeadForWindow(wwin));
950 wwin->icon = wIconCreate(wwin);
952 wwin->icon->mapped = 1;
955 wwin->flags.miniaturized = 1;
956 wwin->flags.mapped = 0;
958 /* unmap transients */
960 unmapTransientsFor(wwin);
962 if (present) {
963 wSoundPlay(WSOUND_ICONIFY);
965 XUngrabPointer(dpy, CurrentTime);
966 wWindowUnmap(wwin);
967 /* let all Expose events arrive so that we can repaint
968 * something before the animation starts (and the server is grabbed) */
969 XSync(dpy, 0);
971 if (wPreferences.disable_miniwindows)
972 wClientSetState(wwin, IconicState, None);
973 else
974 wClientSetState(wwin, IconicState, wwin->icon->icon_win);
976 flushExpose();
977 #ifdef ANIMATIONS
978 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
979 && !wPreferences.no_animations) {
980 int ix, iy, iw, ih;
982 if (!wPreferences.disable_miniwindows) {
983 ix = wwin->icon_x;
984 iy = wwin->icon_y;
985 iw = wwin->icon->core->width;
986 ih = wwin->icon->core->height;
987 } else {
988 #ifdef KWM_HINTS
989 WArea area;
991 if (wKWMGetIconGeometry(wwin, &area)) {
992 ix = area.x1;
993 iy = area.y1;
994 iw = area.x2 - ix;
995 ih = area.y2 - iy;
996 } else
997 #endif /* KWM_HINTS */
999 ix = 0;
1000 iy = 0;
1001 iw = wwin->screen_ptr->scr_width;
1002 ih = wwin->screen_ptr->scr_height;
1005 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1006 wwin->frame->core->width, wwin->frame->core->height,
1007 ix, iy, iw, ih, False);
1009 #endif
1012 wwin->flags.skip_next_animation = 0;
1014 if (!wPreferences.disable_miniwindows) {
1016 if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
1017 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)
1019 XMapWindow(dpy, wwin->icon->core->window);
1021 AddToStackList(wwin->icon->core);
1023 wLowerFrame(wwin->icon->core);
1026 if (present) {
1027 WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
1030 * It doesn't seem to be working and causes button event hangup
1031 * when deiconifying a transient window.
1032 setupIconGrabs(wwin->icon);
1034 if ((wwin->flags.focused
1035 || (owner && wwin->client_win == owner->client_win))
1036 && wPreferences.focus_mode==WKF_CLICK) {
1037 WWindow *tmp;
1039 tmp = wwin->prev;
1040 while (tmp) {
1041 if (!WFLAGP(tmp, no_focusable)
1042 && !(tmp->flags.hidden||tmp->flags.miniaturized)
1043 && (wwin->frame->workspace == tmp->frame->workspace))
1044 break;
1045 tmp = tmp->prev;
1047 wSetFocusTo(wwin->screen_ptr, tmp);
1048 } else if (wPreferences.focus_mode!=WKF_CLICK) {
1049 wSetFocusTo(wwin->screen_ptr, NULL);
1052 #ifdef ANIMATIONS
1053 if (!wwin->screen_ptr->flags.startup) {
1054 Window clientwin = wwin->client_win;
1056 XSync(dpy, 0);
1057 processEvents(XPending(dpy));
1059 /* the window can disappear while doing the processEvents() */
1060 if (!wWindowFor(clientwin))
1061 return;
1063 #endif
1067 if (wwin->flags.selected && !wPreferences.disable_miniwindows)
1068 wIconSelect(wwin->icon);
1070 WMPostNotificationName(WMNChangedState, wwin, "iconify");
1076 void
1077 wDeiconifyWindow(WWindow *wwin)
1079 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1081 if (!wwin->flags.miniaturized)
1082 return;
1084 if (wwin->transient_for != None
1085 && wwin->transient_for != wwin->screen_ptr->root_win) {
1086 WWindow *owner = recursiveTransientFor(wwin);
1088 if (owner && owner->flags.miniaturized) {
1089 wDeiconifyWindow(owner);
1090 wSetFocusTo(wwin->screen_ptr, wwin);
1091 wRaiseFrame(wwin->frame->core);
1092 return;
1096 wwin->flags.miniaturized = 0;
1097 if (!wwin->flags.shaded)
1098 wwin->flags.mapped = 1;
1100 if (!wPreferences.disable_miniwindows && wwin->icon != NULL) {
1101 if (wwin->icon->selected)
1102 wIconSelect(wwin->icon);
1104 XUnmapWindow(dpy, wwin->icon->core->window);
1107 wSoundPlay(WSOUND_DEICONIFY);
1109 /* if the window is in another workspace, do it silently */
1110 #ifdef ANIMATIONS
1111 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1112 && !wwin->flags.skip_next_animation && wwin->icon != NULL) {
1113 int ix, iy, iw, ih;
1115 if (!wPreferences.disable_miniwindows) {
1116 ix = wwin->icon_x;
1117 iy = wwin->icon_y;
1118 iw = wwin->icon->core->width;
1119 ih = wwin->icon->core->height;
1120 } else {
1121 #ifdef KWM_HINTS
1122 WArea area;
1124 if (wKWMGetIconGeometry(wwin, &area)) {
1125 ix = area.x1;
1126 iy = area.y1;
1127 iw = area.x2 - ix;
1128 ih = area.y2 - iy;
1129 } else
1130 #endif /* KWM_HINTS */
1132 ix = 0;
1133 iy = 0;
1134 iw = wwin->screen_ptr->scr_width;
1135 ih = wwin->screen_ptr->scr_height;
1138 animateResize(wwin->screen_ptr, ix, iy, iw, ih,
1139 wwin->frame_x, wwin->frame_y,
1140 wwin->frame->core->width, wwin->frame->core->height,
1141 False);
1143 #endif /* ANIMATIONS */
1144 wwin->flags.skip_next_animation = 0;
1145 XGrabServer(dpy);
1146 if (!wwin->flags.shaded) {
1147 XMapWindow(dpy, wwin->client_win);
1149 XMapWindow(dpy, wwin->frame->core->window);
1150 wRaiseFrame(wwin->frame->core);
1151 if (!wwin->flags.shaded) {
1152 wClientSetState(wwin, NormalState, None);
1154 mapTransientsFor(wwin);
1156 if (!wPreferences.disable_miniwindows && wwin->icon != NULL) {
1157 RemoveFromStackList(wwin->icon->core);
1158 /* removeIconGrabs(wwin->icon);*/
1159 wIconDestroy(wwin->icon);
1160 wwin->icon = NULL;
1162 XUngrabServer(dpy);
1164 wSetFocusTo(wwin->screen_ptr, wwin);
1166 #ifdef ANIMATIONS
1167 if (!wwin->screen_ptr->flags.startup) {
1168 Window clientwin = wwin->client_win;
1170 XSync(dpy, 0);
1171 processEvents(XPending(dpy));
1173 if (!wWindowFor(clientwin))
1174 return;
1176 #endif
1178 if (wPreferences.auto_arrange_icons) {
1179 wArrangeIcons(wwin->screen_ptr, True);
1182 WMPostNotificationName(WMNChangedState, wwin, "iconify");
1184 /* In case we were shaded and iconified, also unshade */
1185 wUnshadeWindow(wwin);
1190 static void
1191 hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
1193 if (wwin->flags.miniaturized) {
1194 if (wwin->icon) {
1195 XUnmapWindow(dpy, wwin->icon->core->window);
1196 wwin->icon->mapped = 0;
1198 wwin->flags.hidden = 1;
1200 WMPostNotificationName(WMNChangedState, wwin, "hide");
1201 return;
1204 if (wwin->flags.inspector_open) {
1205 wHideInspectorForWindow(wwin);
1208 wwin->flags.hidden = 1;
1209 wWindowUnmap(wwin);
1211 wClientSetState(wwin, IconicState, icon->icon_win);
1212 flushExpose();
1213 wSoundPlay(WSOUND_HIDE);
1214 #ifdef ANIMATIONS
1215 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1216 !wwin->flags.skip_next_animation && animate) {
1217 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1218 wwin->frame->core->width, wwin->frame->core->height,
1219 icon_x, icon_y, icon->core->width, icon->core->height,
1220 True);
1222 #endif
1223 wwin->flags.skip_next_animation = 0;
1225 WMPostNotificationName(WMNChangedState, wwin, "hide");
1230 void
1231 wHideOtherApplications(WWindow *awin)
1233 WWindow *wwin;
1234 WApplication *tapp;
1236 if (!awin)
1237 return;
1238 wwin = awin->screen_ptr->focused_window;
1241 while (wwin) {
1242 if (wwin!=awin
1243 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1244 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1245 && !wwin->flags.internal_window
1246 && wGetWindowOfInspectorForWindow(wwin) != awin
1247 && !WFLAGP(wwin, no_hide_others)) {
1249 if (wwin->main_window==None || WFLAGP(wwin, no_appicon)) {
1250 if (!WFLAGP(wwin, no_miniaturizable)) {
1251 wwin->flags.skip_next_animation = 1;
1252 wIconifyWindow(wwin);
1254 } else if (wwin->main_window!=None
1255 && awin->main_window != wwin->main_window) {
1256 tapp = wApplicationOf(wwin->main_window);
1257 if (tapp) {
1258 tapp->flags.skip_next_animation = 1;
1259 wHideApplication(tapp);
1260 } else {
1261 if (!WFLAGP(wwin, no_miniaturizable)) {
1262 wwin->flags.skip_next_animation = 1;
1263 wIconifyWindow(wwin);
1268 wwin = wwin->prev;
1271 wSetFocusTo(awin->screen_ptr, awin);
1277 void
1278 wHideApplication(WApplication *wapp)
1280 WScreen *scr;
1281 WWindow *wlist;
1282 int hadfocus;
1284 if (!wapp) {
1285 wwarning("trying to hide a non grouped window");
1286 return;
1288 if (!wapp->main_window_desc) {
1289 wwarning("group leader not found for window group");
1290 return;
1292 scr = wapp->main_window_desc->screen_ptr;
1293 hadfocus = 0;
1294 wlist = scr->focused_window;
1295 if (!wlist)
1296 return;
1298 if (wlist->main_window == wapp->main_window)
1299 wapp->last_focused = wlist;
1300 else
1301 wapp->last_focused = NULL;
1302 while (wlist) {
1303 if (wlist->main_window == wapp->main_window) {
1304 if (wlist->flags.focused) {
1305 hadfocus = 1;
1307 if (wapp->app_icon)
1308 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1309 wapp->app_icon->y_pos, wlist,
1310 !wapp->flags.skip_next_animation);
1312 wlist = wlist->prev;
1315 wapp->flags.skip_next_animation = 0;
1317 if (hadfocus) {
1318 if (wPreferences.focus_mode==WKF_CLICK) {
1319 wlist = scr->focused_window;
1320 while (wlist) {
1321 if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden
1322 && (wlist->flags.mapped || wlist->flags.shaded))
1323 break;
1324 wlist = wlist->prev;
1326 wSetFocusTo(scr, wlist);
1327 } else {
1328 wSetFocusTo(scr, NULL);
1332 wapp->flags.hidden = 1;
1334 if(wPreferences.auto_arrange_icons) {
1335 wArrangeIcons(scr, True);
1337 #ifdef HIDDENDOT
1338 if (wapp->app_icon)
1339 wAppIconPaint(wapp->app_icon);
1340 #endif
1346 static void
1347 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1348 int bringToCurrentWS)
1350 if (bringToCurrentWS)
1351 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1353 wwin->flags.hidden=0;
1355 wSoundPlay(WSOUND_UNHIDE);
1356 #ifdef ANIMATIONS
1357 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1358 && animate) {
1359 animateResize(wwin->screen_ptr, icon_x, icon_y,
1360 icon->core->width, icon->core->height,
1361 wwin->frame_x, wwin->frame_y,
1362 wwin->frame->core->width, wwin->frame->core->height,
1363 True);
1365 #endif
1366 wwin->flags.skip_next_animation = 0;
1367 if (wwin->screen_ptr->current_workspace == wwin->frame->workspace) {
1368 XMapWindow(dpy, wwin->client_win);
1369 XMapWindow(dpy, wwin->frame->core->window);
1370 wClientSetState(wwin, NormalState, None);
1371 wwin->flags.mapped=1;
1372 wRaiseFrame(wwin->frame->core);
1374 if (wwin->flags.inspector_open) {
1375 wUnhideInspectorForWindow(wwin);
1378 WMPostNotificationName(WMNChangedState, wwin, "hide");
1382 void
1383 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1385 WScreen *scr;
1386 WWindow *wlist, *next;
1387 WWindow *focused=NULL;
1388 Bool shouldArrangeIcons = False;
1390 if (!wapp)
1391 return;
1393 scr = wapp->main_window_desc->screen_ptr;
1394 wlist = scr->focused_window;
1395 if (!wlist)
1396 return;
1398 /* goto beginning of list */
1399 while (wlist->prev)
1400 wlist = wlist->prev;
1402 while (wlist) {
1403 next = wlist->next;
1405 if (wlist->main_window == wapp->main_window) {
1406 if (wlist->flags.focused)
1407 focused = wlist;
1408 else if (!focused || !focused->flags.focused)
1409 focused = wlist;
1411 if (wlist->flags.miniaturized) {
1412 if (bringToCurrentWS || wPreferences.sticky_icons ||
1413 wlist->frame->workspace == scr->current_workspace) {
1414 if (wlist->icon && !wlist->icon->mapped) {
1415 XMapWindow(dpy, wlist->icon->core->window);
1416 wlist->icon->mapped = 1;
1419 if (bringToCurrentWS)
1420 wWindowChangeWorkspace(wlist, scr->current_workspace);
1421 wlist->flags.hidden = 0;
1422 if (miniwindows &&
1423 wlist->frame->workspace == scr->current_workspace) {
1424 wDeiconifyWindow(wlist);
1426 shouldArrangeIcons = True;
1427 WMPostNotificationName(WMNChangedState, wlist, "hide");
1428 } else if (wlist->flags.shaded) {
1429 if (bringToCurrentWS)
1430 wWindowChangeWorkspace(wlist, scr->current_workspace);
1431 wlist->flags.hidden = 0;
1432 if (wlist->frame->workspace == scr->current_workspace) {
1433 XMapWindow(dpy, wlist->frame->core->window);
1434 if (miniwindows) {
1435 wUnshadeWindow(wlist);
1436 wRaiseFrame(wlist->frame->core);
1439 WMPostNotificationName(WMNChangedState, wlist, "hide");
1440 } else if (wlist->flags.hidden) {
1441 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1442 wapp->app_icon->y_pos, wlist,
1443 !wapp->flags.skip_next_animation,
1444 bringToCurrentWS);
1445 } else {
1446 if (bringToCurrentWS
1447 && wlist->frame->workspace != scr->current_workspace) {
1448 wWindowChangeWorkspace(wlist, scr->current_workspace);
1450 wRaiseFrame(wlist->frame->core);
1453 wlist = next;
1456 wapp->flags.skip_next_animation = 0;
1457 wapp->flags.hidden = 0;
1459 if (wapp->last_focused && wapp->last_focused->flags.mapped) {
1460 wRaiseFrame(wapp->last_focused->frame->core);
1461 wSetFocusTo(scr, wapp->last_focused);
1462 } else if (focused) {
1463 wSetFocusTo(scr, focused);
1465 wapp->last_focused = NULL;
1466 if (shouldArrangeIcons || wPreferences.auto_arrange_icons) {
1467 wArrangeIcons(scr, True);
1469 #ifdef HIDDENDOT
1470 wAppIconPaint(wapp->app_icon);
1471 #endif
1476 void
1477 wShowAllWindows(WScreen *scr)
1479 WWindow *wwin, *old_foc;
1480 WApplication *wapp;
1482 old_foc = wwin = scr->focused_window;
1483 while (wwin) {
1484 if (!wwin->flags.internal_window &&
1485 (scr->current_workspace == wwin->frame->workspace
1486 || IS_OMNIPRESENT(wwin))) {
1487 if (wwin->flags.miniaturized) {
1488 wwin->flags.skip_next_animation = 1;
1489 wDeiconifyWindow(wwin);
1490 } else if (wwin->flags.hidden) {
1491 wapp = wApplicationOf(wwin->main_window);
1492 if (wapp) {
1493 wUnhideApplication(wapp, False, False);
1494 } else {
1495 wwin->flags.skip_next_animation = 1;
1496 wDeiconifyWindow(wwin);
1500 wwin = wwin->prev;
1502 wSetFocusTo(scr, old_foc);
1503 /*wRaiseFrame(old_foc->frame->core);*/
1507 void
1508 wRefreshDesktop(WScreen *scr)
1510 Window win;
1511 XSetWindowAttributes attr;
1513 attr.backing_store = NotUseful;
1514 attr.save_under = False;
1515 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1516 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1517 (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
1518 &attr);
1519 XMapRaised(dpy, win);
1520 XDestroyWindow(dpy, win);
1521 XFlush(dpy);
1525 void
1526 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1528 WWindow *wwin;
1529 WAppIcon *aicon;
1531 int head;
1532 const int heads = wXineramaHeads(scr);
1534 struct HeadVars {
1535 int pf; /* primary axis */
1536 int sf; /* secondary axis */
1537 int fullW;
1538 int fullH;
1539 int pi, si;
1540 int sx1, sx2, sy1, sy2; /* screen boundary */
1541 int sw, sh;
1542 int xo, yo;
1543 int xs, ys;
1544 } *vars;
1546 int isize = wPreferences.icon_size;
1548 vars = (struct HeadVars*)wmalloc(sizeof(struct HeadVars)*heads);
1550 for (head = 0; head < heads; ++head) {
1551 #if 0
1552 WMRect rect = wGetRectForHead(scr, head);
1553 #else
1554 WArea area = wGetUsableAreaForHead(scr, head, NULL, False);
1555 WMRect rect = wmkrect(area.x1, area.y1, area.x2-area.x1, area.y2-area.y1);
1556 #endif
1558 vars[head].pi = vars[head].si = 0;
1559 vars[head].sx1 = rect.pos.x;
1560 vars[head].sy1 = rect.pos.y;
1561 vars[head].sw = rect.size.width;
1562 vars[head].sh = rect.size.height;
1563 vars[head].sx2 = vars[head].sx1 + vars[head].sw;
1564 vars[head].sy2 = vars[head].sy1 + vars[head].sh;
1566 #if 0
1567 if (scr->dock) {
1568 if (scr->dock->on_right_side)
1569 vars[head].sx2 -= isize + DOCK_EXTRA_SPACE;
1570 else
1571 vars[head].sx1 += isize + DOCK_EXTRA_SPACE;
1573 #endif
1575 vars[head].sw = isize * (vars[head].sw/isize);
1576 vars[head].sh = isize * (vars[head].sh/isize);
1577 vars[head].fullW = (vars[head].sx2-vars[head].sx1)/isize;
1578 vars[head].fullH = (vars[head].sy2-vars[head].sy1)/isize;
1580 /* icon yard boundaries */
1581 if (wPreferences.icon_yard & IY_VERT) {
1582 vars[head].pf = vars[head].fullH;
1583 vars[head].sf = vars[head].fullW;
1584 } else {
1585 vars[head].pf = vars[head].fullW;
1586 vars[head].sf = vars[head].fullH;
1588 if (wPreferences.icon_yard & IY_RIGHT) {
1589 vars[head].xo = vars[head].sx2 - isize;
1590 vars[head].xs = -1;
1591 } else {
1592 vars[head].xo = vars[head].sx1;
1593 vars[head].xs = 1;
1595 if (wPreferences.icon_yard & IY_TOP) {
1596 vars[head].yo = vars[head].sy1;
1597 vars[head].ys = 1;
1598 } else {
1599 vars[head].yo = vars[head].sy2 - isize;
1600 vars[head].ys = -1;
1604 #define X ((wPreferences.icon_yard & IY_VERT) \
1605 ? vars[head].xo + vars[head].xs*(vars[head].si*isize) \
1606 : vars[head].xo + vars[head].xs*(vars[head].pi*isize))
1608 #define Y ((wPreferences.icon_yard & IY_VERT) \
1609 ? vars[head].yo + vars[head].ys*(vars[head].pi*isize) \
1610 : vars[head].yo + vars[head].ys*(vars[head].si*isize))
1613 /* arrange application icons */
1614 aicon = scr->app_icon_list;
1615 /* reverse them to avoid unnecessarily sliding of icons */
1616 while (aicon && aicon->next)
1617 aicon = aicon->next;
1619 while (aicon) {
1620 if (!aicon->docked) {
1621 /* XXX: can: icon == NULL ? */
1622 /* The intention here is to place the AppIcon on the head that contains most of the applications _main_ window. */
1623 /* printf("appicon: %x %x\n", aicon->icon->core->window, aicon->main_window); */
1624 head = wGetHeadForWindow(aicon->icon->owner);
1626 if (aicon->x_pos != X || aicon->y_pos != Y) {
1627 #ifdef ANIMATIONS
1628 if (!wPreferences.no_animations) {
1629 SlideWindow(aicon->icon->core->window,
1630 aicon->x_pos, aicon->y_pos, X, Y);
1632 #endif /* ANIMATIONS */
1634 wAppIconMove(aicon, X, Y);
1635 vars[head].pi++;
1636 if (vars[head].pi >= vars[head].pf) {
1637 vars[head].pi = 0;
1638 vars[head].si++;
1641 aicon = aicon->prev;
1644 /* arrange miniwindows */
1645 wwin = scr->focused_window;
1646 /* reverse them to avoid unnecessarily shuffling */
1647 while (wwin && wwin->prev)
1648 wwin = wwin->prev;
1650 while (wwin) {
1651 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1652 (wwin->frame->workspace==scr->current_workspace ||
1653 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1655 head = wGetHeadForWindow(wwin);
1657 if (arrangeAll || !wwin->flags.icon_moved) {
1658 if (wwin->icon_x != X || wwin->icon_y != Y) {
1659 #ifdef ANIMATIONS
1660 if (wPreferences.no_animations) {
1661 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1662 } else {
1663 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1664 wwin->icon_y, X, Y);
1666 #else
1667 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1668 #endif /* ANIMATIONS */
1670 wwin->icon_x = X;
1671 wwin->icon_y = Y;
1673 vars[head].pi++;
1674 if (vars[head].pi >= vars[head].pf) {
1675 vars[head].pi = 0;
1676 vars[head].si++;
1680 if (arrangeAll) {
1681 wwin->flags.icon_moved = 0;
1683 /* we reversed the order, so we use next */
1684 wwin = wwin->next;
1687 wfree(vars);
1690 #if 0
1691 void
1692 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1694 WWindow *wwin;
1695 WAppIcon *aicon;
1696 int pf; /* primary axis */
1697 int sf; /* secondary axis */
1698 int fullW;
1699 int fullH;
1700 int pi, si;
1701 int sx1, sx2, sy1, sy2; /* screen boundary */
1702 int sw, sh;
1703 int xo, yo;
1704 int xs, ys;
1705 int isize = wPreferences.icon_size;
1708 * Find out screen boundaries.
1712 * Allows each head to have miniwindows
1714 WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
1716 sx1 = rect.pos.x;
1717 sy1 = rect.pos.y;
1718 sw = rect.size.width;
1719 sh = rect.size.height;
1720 sx2 = sx1 + sw;
1721 sy2 = sy1 + sh;
1722 if (scr->dock) {
1723 if (scr->dock->on_right_side)
1724 sx2 -= isize + DOCK_EXTRA_SPACE;
1725 else
1726 sx1 += isize + DOCK_EXTRA_SPACE;
1729 #if 0
1730 sw = isize * (scr->scr_width/isize);
1731 sh = isize * (scr->scr_height/isize);
1732 #else
1733 sw = isize * (sw/isize);
1734 sh = isize * (sh/isize);
1735 #endif
1736 fullW = (sx2-sx1)/isize;
1737 fullH = (sy2-sy1)/isize;
1739 /* icon yard boundaries */
1740 if (wPreferences.icon_yard & IY_VERT) {
1741 pf = fullH;
1742 sf = fullW;
1743 } else {
1744 pf = fullW;
1745 sf = fullH;
1747 if (wPreferences.icon_yard & IY_RIGHT) {
1748 xo = sx2 - isize;
1749 xs = -1;
1750 } else {
1751 xo = sx1;
1752 xs = 1;
1754 if (wPreferences.icon_yard & IY_TOP) {
1755 yo = sy1;
1756 ys = 1;
1757 } else {
1758 yo = sy2 - isize;
1759 ys = -1;
1762 /* arrange icons putting the most recently focused window
1763 * as the last icon */
1764 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1765 : xo + xs*(pi*isize))
1766 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1767 : yo + ys*(si*isize))
1769 /* arrange application icons */
1770 aicon = scr->app_icon_list;
1771 /* reverse them to avoid unnecessarily sliding of icons */
1772 while (aicon && aicon->next)
1773 aicon = aicon->next;
1775 pi = 0;
1776 si = 0;
1777 while (aicon) {
1778 if (!aicon->docked) {
1779 if (aicon->x_pos != X || aicon->y_pos != Y) {
1780 #ifdef ANIMATIONS
1781 if (!wPreferences.no_animations) {
1782 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1783 X, Y);
1785 #endif /* ANIMATIONS */
1787 wAppIconMove(aicon, X, Y);
1788 pi++;
1790 /* we reversed the order so we use prev */
1791 aicon = aicon->prev;
1792 if (pi >= pf) {
1793 pi=0;
1794 si++;
1798 /* arrange miniwindows */
1800 wwin = scr->focused_window;
1801 /* reverse them to avoid unnecessarily shuffling */
1802 while (wwin && wwin->prev)
1803 wwin = wwin->prev;
1805 while (wwin) {
1806 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1807 (wwin->frame->workspace==scr->current_workspace ||
1808 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1810 if (arrangeAll || !wwin->flags.icon_moved) {
1811 if (wwin->icon_x != X || wwin->icon_y != Y) {
1812 #ifdef ANIMATIONS
1813 if (wPreferences.no_animations) {
1814 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1815 } else {
1816 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1817 wwin->icon_y, X, Y);
1819 #else
1820 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1821 #endif /* ANIMATIONS */
1823 wwin->icon_x = X;
1824 wwin->icon_y = Y;
1825 pi++;
1828 if (arrangeAll) {
1829 wwin->flags.icon_moved = 0;
1831 /* we reversed the order, so we use next */
1832 wwin = wwin->next;
1833 if (pi >= pf) {
1834 pi=0;
1835 si++;
1839 #endif
1841 void
1842 wSelectWindow(WWindow *wwin, Bool flag)
1844 WScreen *scr = wwin->screen_ptr;
1846 if (flag) {
1847 wwin->flags.selected = 1;
1848 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1850 if (WFLAGP(wwin, no_border)) {
1851 XSetWindowBorderWidth(dpy, wwin->frame->core->window,
1852 FRAME_BORDER_WIDTH);
1855 if (!scr->selected_windows)
1856 scr->selected_windows = WMCreateArray(4);
1857 WMAddToArray(scr->selected_windows, wwin);
1858 } else {
1859 wwin->flags.selected = 0;
1860 XSetWindowBorder(dpy, wwin->frame->core->window,
1861 scr->frame_border_pixel);
1863 if (WFLAGP(wwin, no_border)) {
1864 XSetWindowBorderWidth(dpy, wwin->frame->core->window, 0);
1867 if (scr->selected_windows) {
1868 WMRemoveFromArray(scr->selected_windows, wwin);
1874 void
1875 wMakeWindowVisible(WWindow *wwin)
1877 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
1878 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1880 if (wwin->flags.shaded) {
1881 wUnshadeWindow(wwin);
1883 if (wwin->flags.hidden) {
1884 WApplication *app;
1886 app = wApplicationOf(wwin->main_window);
1887 if (app) {
1888 /* trick to get focus to this window */
1889 app->last_focused = wwin;
1890 wUnhideApplication(app, False, False);
1893 if (wwin->flags.miniaturized) {
1894 wDeiconifyWindow(wwin);
1895 } else {
1896 if (!WFLAGP(wwin, no_focusable))
1897 wSetFocusTo(wwin->screen_ptr, wwin);
1898 wRaiseFrame(wwin->frame->core);