changed indentation to use spaces only
[wmaker-crm.git] / src / actions.c
blobe424802453384ab6cdf42d20be817e564f863326
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;
72 extern void ProcessPendingEvents();
75 /******* Local Variables *******/
76 static struct {
77 int steps;
78 int delay;
79 } shadePars[5] = {
80 {SHADE_STEPS_UF, SHADE_DELAY_UF},
81 {SHADE_STEPS_F, SHADE_DELAY_F},
82 {SHADE_STEPS_M, SHADE_DELAY_M},
83 {SHADE_STEPS_S, SHADE_DELAY_S},
84 {SHADE_STEPS_US, SHADE_DELAY_US}};
86 #define SHADE_STEPS shadePars[(int)wPreferences.shade_speed].steps
87 #define SHADE_DELAY shadePars[(int)wPreferences.shade_speed].delay
91 *----------------------------------------------------------------------
92 * wSetFocusTo--
93 * Changes the window focus to the one passed as argument.
94 * If the window to focus is not already focused, it will be brought
95 * to the head of the list of windows. Previously focused window is
96 * unfocused.
98 * Side effects:
99 * Window list may be reordered and the window focus is changed.
101 *----------------------------------------------------------------------
103 void
104 wSetFocusTo(WScreen *scr, WWindow *wwin)
106 static WScreen *old_scr=NULL;
108 WWindow *old_focused;
109 WWindow *focused=scr->focused_window;
110 int timestamp=LastTimestamp;
111 WApplication *oapp=NULL, *napp=NULL;
112 int wasfocused;
114 if (scr->flags.ignore_focus_events || LastFocusChange > timestamp)
115 return;
117 if (!old_scr)
118 old_scr=scr;
119 old_focused=old_scr->focused_window;
121 LastFocusChange = timestamp;
123 if (old_focused)
124 oapp = wApplicationOf(old_focused->main_window);
126 if (wwin == NULL) {
127 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
128 if (old_focused) {
129 wWindowUnfocus(old_focused);
131 if (oapp) {
132 wAppMenuUnmap(oapp->menu);
133 #ifdef NEWAPPICON
134 wApplicationDeactivate(oapp);
135 #endif
138 WMPostNotificationName(WMNChangedFocus, NULL, (void*)True);
139 return;
140 } else if (old_scr != scr && old_focused) {
141 wWindowUnfocus(old_focused);
144 wasfocused = wwin->flags.focused;
145 napp = wApplicationOf(wwin->main_window);
147 /* remember last workspace where the app has been */
148 if (napp) {
149 /*napp->last_workspace = wwin->screen_ptr->current_workspace;*/
150 napp->last_workspace = wwin->frame->workspace;
153 if (wwin->flags.mapped && !WFLAGP(wwin, no_focusable)) {
154 /* install colormap if colormap mode is lock mode */
155 if (wPreferences.colormap_mode==WCM_CLICK)
156 wColormapInstallForWindow(scr, wwin);
158 /* set input focus */
159 switch (wwin->focus_mode) {
160 case WFM_NO_INPUT:
161 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
162 break;
164 case WFM_PASSIVE:
165 case WFM_LOCALLY_ACTIVE:
166 XSetInputFocus(dpy, wwin->client_win, RevertToParent, CurrentTime);
167 break;
169 case WFM_GLOBALLY_ACTIVE:
170 break;
172 XFlush(dpy);
173 if (wwin->protocols.TAKE_FOCUS) {
174 wClientSendProtocol(wwin, _XA_WM_TAKE_FOCUS, timestamp);
176 XSync(dpy, False);
177 } else {
178 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
180 if (WFLAGP(wwin, no_focusable))
181 return;
183 /* if this is not the focused window focus it */
184 if (focused!=wwin) {
185 /* change the focus window list order */
186 if (wwin->prev)
187 wwin->prev->next = wwin->next;
189 if (wwin->next)
190 wwin->next->prev = wwin->prev;
192 wwin->prev = focused;
193 focused->next = wwin;
194 wwin->next = NULL;
195 scr->focused_window = wwin;
197 if (oapp && oapp != napp) {
198 wAppMenuUnmap(oapp->menu);
199 #ifdef NEWAPPICON
200 wApplicationDeactivate(oapp);
201 #endif
205 wWindowFocus(wwin, focused);
207 if (napp && !wasfocused) {
208 #ifdef USER_MENU
209 wUserMenuRefreshInstances(napp->menu, wwin);
210 #endif /* USER_MENU */
212 if (wwin->flags.mapped)
213 wAppMenuMap(napp->menu, wwin);
214 #ifdef NEWAPPICON
215 wApplicationActivate(napp);
216 #endif
219 XFlush(dpy);
220 old_scr=scr;
224 void
225 wShadeWindow(WWindow *wwin)
227 time_t time0;
228 #ifdef ANIMATIONS
229 int y, s, w, h;
230 #endif
232 if (wwin->flags.shaded)
233 return;
235 time0 = time(NULL);
237 XLowerWindow(dpy, wwin->client_win);
239 wSoundPlay(WSOUND_SHADE);
241 #ifdef ANIMATIONS
242 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
243 && !wPreferences.no_animations) {
244 /* do the shading animation */
245 h = wwin->frame->core->height;
246 s = h/SHADE_STEPS;
247 if (s < 1) s=1;
248 w = wwin->frame->core->width;
249 y = wwin->frame->top_width;
250 while (h>wwin->frame->top_width+1) {
251 XMoveWindow(dpy, wwin->client_win, 0, y);
252 XResizeWindow(dpy, wwin->frame->core->window, w, h);
253 XFlush(dpy);
255 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
256 break;
258 if (SHADE_DELAY > 0) {
259 wusleep(SHADE_DELAY*1000L);
260 } else {
261 wusleep(10);
263 h-=s;
264 y-=s;
266 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
268 #endif /* ANIMATIONS */
270 wwin->flags.skip_next_animation = 0;
271 wwin->flags.shaded = 1;
272 wwin->flags.mapped = 0;
273 /* prevent window withdrawal when getting UnmapNotify */
274 XSelectInput(dpy, wwin->client_win,
275 wwin->event_mask & ~StructureNotifyMask);
276 XUnmapWindow(dpy, wwin->client_win);
277 XSelectInput(dpy, wwin->client_win, wwin->event_mask);
279 /* for the client it's just like iconification */
280 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
281 wwin->frame->top_width - 1);
283 wwin->client.y = wwin->frame_y - wwin->client.height
284 + wwin->frame->top_width;
285 wWindowSynthConfigureNotify(wwin);
288 wClientSetState(wwin, IconicState, None);
291 WMPostNotificationName(WMNChangedState, wwin, "shade");
293 #ifdef ANIMATIONS
294 if (!wwin->screen_ptr->flags.startup) {
295 /* Catch up with events not processed while animation was running */
296 ProcessPendingEvents();
298 #endif
302 void
303 wUnshadeWindow(WWindow *wwin)
305 time_t time0;
306 #ifdef ANIMATIONS
307 int y, s, w, h;
308 #endif /* ANIMATIONS */
311 if (!wwin->flags.shaded)
312 return;
314 time0 = time(NULL);
316 wwin->flags.shaded = 0;
317 wwin->flags.mapped = 1;
318 XMapWindow(dpy, wwin->client_win);
320 wSoundPlay(WSOUND_UNSHADE);
322 #ifdef ANIMATIONS
323 if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) {
324 /* do the shading animation */
325 h = wwin->frame->top_width + wwin->frame->bottom_width;
326 y = wwin->frame->top_width - wwin->client.height;
327 s = abs(y)/SHADE_STEPS;
328 if (s<1) s=1;
329 w = wwin->frame->core->width;
330 XMoveWindow(dpy, wwin->client_win, 0, y);
331 if (s>0) {
332 while (h < wwin->client.height + wwin->frame->top_width
333 + wwin->frame->bottom_width) {
334 XResizeWindow(dpy, wwin->frame->core->window, w, h);
335 XMoveWindow(dpy, wwin->client_win, 0, y);
336 XFlush(dpy);
337 if (SHADE_DELAY > 0) {
338 wusleep(SHADE_DELAY*2000L/3);
339 } else {
340 wusleep(10);
342 h+=s;
343 y+=s;
345 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
346 break;
349 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
351 #endif /* ANIMATIONS */
353 wwin->flags.skip_next_animation = 0;
354 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
355 wwin->frame->top_width + wwin->client.height
356 + wwin->frame->bottom_width);
358 wwin->client.y = wwin->frame_y + wwin->frame->top_width;
359 wWindowSynthConfigureNotify(wwin);
362 wClientSetState(wwin, NormalState, None);
364 /* if the window is focused, set the focus again as it was disabled during
365 * shading */
366 if (wwin->flags.focused)
367 wSetFocusTo(wwin->screen_ptr, wwin);
369 WMPostNotificationName(WMNChangedState, wwin, "shade");
373 void
374 wMaximizeWindow(WWindow *wwin, int directions)
376 int new_width, new_height, new_x, new_y;
377 int changed_h, changed_v, shrink_h, shrink_v;
378 WArea usableArea, totalArea;
380 if (!IS_RESIZABLE(wwin))
381 return;
383 totalArea.x1 = 0;
384 totalArea.y1 = 0;
385 totalArea.x2 = wwin->screen_ptr->scr_width;
386 totalArea.y2 = wwin->screen_ptr->scr_height;
387 usableArea = totalArea;
389 if (!(directions & MAX_IGNORE_XINERAMA)) {
390 WScreen *scr = wwin->screen_ptr;
391 int head;
393 if (directions & MAX_KEYBOARD)
394 head = wGetHeadForWindow(wwin);
395 else
396 head = wGetHeadForPointerLocation(scr);
398 usableArea = wGetUsableAreaForHead(scr, head, &totalArea, True);
401 if (WFLAGP(wwin, full_maximize)) {
402 usableArea = totalArea;
405 if (wwin->flags.shaded) {
406 wwin->flags.skip_next_animation = 1;
407 wUnshadeWindow(wwin);
409 /* Only save directions, not kbd or xinerama hints */
410 directions &= (MAX_HORIZONTAL|MAX_VERTICAL);
412 changed_h = ((wwin->flags.maximized ^ directions) & MAX_HORIZONTAL);
413 changed_v = ((wwin->flags.maximized ^ directions) & MAX_VERTICAL);
414 shrink_h = (changed_h && (directions & MAX_HORIZONTAL)==0);
415 shrink_v = (changed_v && (directions & MAX_VERTICAL)==0);
417 if (wwin->flags.maximized) {
418 /* if already maximized in some direction, we only update the
419 * appropriate old x, old y coordinates. This is necessary to
420 * allow succesive maximizations in different directions without
421 * the need to first do an un-maximize (to avoid flicker).
423 if (!(wwin->flags.maximized & MAX_HORIZONTAL)) {
424 wwin->old_geometry.x = wwin->frame_x;
426 if (!(wwin->flags.maximized & MAX_VERTICAL)) {
427 wwin->old_geometry.y = wwin->frame_y;
429 } else {
430 wwin->old_geometry.width = wwin->client.width;
431 wwin->old_geometry.height = wwin->client.height;
432 wwin->old_geometry.x = wwin->frame_x;
433 wwin->old_geometry.y = wwin->frame_y;
435 wwin->flags.maximized = directions;
437 #ifdef KWM_HINTS
438 wKWMUpdateClientGeometryRestore(wwin);
439 #endif
441 if (directions & MAX_HORIZONTAL) {
442 new_width = (usableArea.x2-usableArea.x1)-FRAME_BORDER_WIDTH*2;
443 new_x = usableArea.x1;
444 } else if (shrink_h) {
445 new_x = wwin->old_geometry.x;
446 new_width = wwin->old_geometry.width;
447 } else {
448 new_x = wwin->frame_x;
449 new_width = wwin->frame->core->width;
452 if (directions & MAX_VERTICAL) {
453 new_height = (usableArea.y2-usableArea.y1)-FRAME_BORDER_WIDTH*2;
454 new_y = usableArea.y1;
455 if (WFLAGP(wwin, full_maximize)) {
456 new_y -= wwin->frame->top_width;
457 new_height += wwin->frame->bottom_width - 1;
459 } else if (shrink_v) {
460 new_y = wwin->old_geometry.y;
461 new_height = wwin->old_geometry.height;
462 } else {
463 new_y = wwin->frame_y;
464 new_height = wwin->frame->core->height;
467 if (!WFLAGP(wwin, full_maximize)) {
468 new_height -= wwin->frame->top_width+wwin->frame->bottom_width;
471 wWindowConstrainSize(wwin, &new_width, &new_height);
473 wWindowCropSize(wwin, usableArea.x2-usableArea.x1,
474 usableArea.y2-usableArea.y1,
475 &new_width, &new_height);
477 wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
480 WMPostNotificationName(WMNChangedState, wwin, "maximize");
482 wSoundPlay(WSOUND_MAXIMIZE);
486 void
487 wUnmaximizeWindow(WWindow *wwin)
489 int restore_x, restore_y;
491 if (!wwin->flags.maximized)
492 return;
494 if (wwin->flags.shaded) {
495 wwin->flags.skip_next_animation = 1;
496 wUnshadeWindow(wwin);
498 restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ?
499 wwin->old_geometry.x : wwin->frame_x;
500 restore_y = (wwin->flags.maximized & MAX_VERTICAL) ?
501 wwin->old_geometry.y : wwin->frame_y;
502 wwin->flags.maximized = 0;
503 wWindowConfigure(wwin, restore_x, restore_y,
504 wwin->old_geometry.width, wwin->old_geometry.height);
506 WMPostNotificationName(WMNChangedState, wwin, "maximize");
508 wSoundPlay(WSOUND_UNMAXIMIZE);
512 void
513 wFullscreenWindow(WWindow *wwin)
515 int head;
516 WMRect rect;
518 if (wwin->flags.fullscreen)
519 return;
521 wwin->flags.fullscreen = True;
523 wWindowConfigureBorders(wwin);
525 ChangeStackingLevel(wwin->frame->core, WMFullscreenLevel);
527 wwin->bfs_geometry.x = wwin->frame_x;
528 wwin->bfs_geometry.y = wwin->frame_y;
529 wwin->bfs_geometry.width = wwin->frame->core->width;
530 wwin->bfs_geometry.height = wwin->frame->core->height;
532 head = wGetHeadForWindow(wwin);
533 rect = wGetRectForHead(wwin->screen_ptr, head);
534 wWindowConfigure(wwin, rect.pos.x, rect.pos.y,
535 rect.size.width, rect.size.height);
537 WMPostNotificationName(WMNChangedState, wwin, "fullscreen");
541 void
542 wUnfullscreenWindow(WWindow *wwin)
544 if (!wwin->flags.fullscreen)
545 return;
547 wwin->flags.fullscreen = False;
549 if (wwin->frame->core->stacking->window_level == WMFullscreenLevel) {
550 if (WFLAGP(wwin, sunken)) {
551 ChangeStackingLevel(wwin->frame->core, WMSunkenLevel);
552 } else if (WFLAGP(wwin, floating)) {
553 ChangeStackingLevel(wwin->frame->core, WMFloatingLevel);
554 } else {
555 ChangeStackingLevel(wwin->frame->core, WMNormalLevel);
559 wWindowConfigure(wwin, wwin->bfs_geometry.x, wwin->bfs_geometry.y,
560 wwin->bfs_geometry.width, wwin->bfs_geometry.height);
562 wWindowConfigureBorders(wwin);
563 // seems unnecessary, but also harmless (doesn't generate flicker) -Dan
564 wFrameWindowPaint(wwin->frame);
566 WMPostNotificationName(WMNChangedState, wwin, "fullscreen");
570 #ifdef ANIMATIONS
571 static void
572 animateResizeFlip(WScreen *scr, int x, int y, int w, int h,
573 int fx, int fy, int fw, int fh, int steps)
575 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
576 float cx, cy, cw, ch;
577 float xstep, ystep, wstep, hstep;
578 XPoint points[5];
579 float dx, dch, midy;
580 float angle, final_angle, delta;
582 xstep = (float)(fx-x)/steps;
583 ystep = (float)(fy-y)/steps;
584 wstep = (float)(fw-w)/steps;
585 hstep = (float)(fh-h)/steps;
587 cx = (float)x;
588 cy = (float)y;
589 cw = (float)w;
590 ch = (float)h;
592 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F;
593 delta = (float)(final_angle/FRAMES);
594 for (angle=0;; angle+=delta) {
595 if (angle > final_angle)
596 angle = final_angle;
598 dx = (cw/10) - ((cw/5) * sin(angle));
599 dch = (ch/2) * cos(angle);
600 midy = cy + (ch/2);
602 points[0].x = cx + dx; points[0].y = midy - dch;
603 points[1].x = cx + cw - dx; points[1].y = points[0].y;
604 points[2].x = cx + cw + dx; points[2].y = midy + dch;
605 points[3].x = cx - dx; points[3].y = points[2].y;
606 points[4].x = points[0].x; points[4].y = points[0].y;
608 XGrabServer(dpy);
609 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
610 XFlush(dpy);
611 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
612 wusleep(MINIATURIZE_ANIMATION_DELAY_F);
613 #else
614 wusleep(10);
615 #endif
617 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
618 XUngrabServer(dpy);
619 cx+=xstep;
620 cy+=ystep;
621 cw+=wstep;
622 ch+=hstep;
623 if (angle >= final_angle)
624 break;
627 XFlush(dpy);
629 #undef FRAMES
632 static void
633 animateResizeTwist(WScreen *scr, int x, int y, int w, int h,
634 int fx, int fy, int fw, int fh, int steps)
636 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
637 float cx, cy, cw, ch;
638 float xstep, ystep, wstep, hstep;
639 XPoint points[5];
640 float angle, final_angle, a, d, delta;
642 x += w/2;
643 y += h/2;
644 fx += fw/2;
645 fy += fh/2;
647 xstep = (float)(fx-x)/steps;
648 ystep = (float)(fy-y)/steps;
649 wstep = (float)(fw-w)/steps;
650 hstep = (float)(fh-h)/steps;
652 cx = (float)x;
653 cy = (float)y;
654 cw = (float)w;
655 ch = (float)h;
657 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T;
658 delta = (float)(final_angle/FRAMES);
659 for (angle=0;; angle+=delta) {
660 if (angle > final_angle)
661 angle = final_angle;
663 a = atan(ch/cw);
664 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
666 points[0].x = cx+cos(angle-a)*d;
667 points[0].y = cy+sin(angle-a)*d;
668 points[1].x = cx+cos(angle+a)*d;
669 points[1].y = cy+sin(angle+a)*d;
670 points[2].x = cx+cos(angle-a+WM_PI)*d;
671 points[2].y = cy+sin(angle-a+WM_PI)*d;
672 points[3].x = cx+cos(angle+a+WM_PI)*d;
673 points[3].y = cy+sin(angle+a+WM_PI)*d;
674 points[4].x = cx+cos(angle-a)*d;
675 points[4].y = cy+sin(angle-a)*d;
676 XGrabServer(dpy);
677 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
678 XFlush(dpy);
679 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
680 wusleep(MINIATURIZE_ANIMATION_DELAY_T);
681 #else
682 wusleep(10);
683 #endif
685 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
686 XUngrabServer(dpy);
687 cx+=xstep;
688 cy+=ystep;
689 cw+=wstep;
690 ch+=hstep;
691 if (angle >= final_angle)
692 break;
695 XFlush(dpy);
697 #undef FRAMES
700 static void
701 animateResizeZoom(WScreen *scr, int x, int y, int w, int h,
702 int fx, int fy, int fw, int fh, int steps)
704 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
705 float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
706 float xstep, ystep, wstep, hstep;
707 int i, j;
709 xstep = (float)(fx-x)/steps;
710 ystep = (float)(fy-y)/steps;
711 wstep = (float)(fw-w)/steps;
712 hstep = (float)(fh-h)/steps;
714 for (j=0; j<FRAMES; j++) {
715 cx[j] = (float)x;
716 cy[j] = (float)y;
717 cw[j] = (float)w;
718 ch[j] = (float)h;
720 XGrabServer(dpy);
721 for (i=0; i<steps; i++) {
722 for (j=0; j<FRAMES; j++) {
723 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
724 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
726 XFlush(dpy);
727 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
728 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
729 #else
730 wusleep(10);
731 #endif
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]);
735 if (j<FRAMES-1) {
736 cx[j]=cx[j+1];
737 cy[j]=cy[j+1];
738 cw[j]=cw[j+1];
739 ch[j]=ch[j+1];
740 } else {
741 cx[j]+=xstep;
742 cy[j]+=ystep;
743 cw[j]+=wstep;
744 ch[j]+=hstep;
749 for (j=0; j<FRAMES; j++) {
750 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
751 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
753 XFlush(dpy);
754 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
755 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
756 #else
757 wusleep(10);
758 #endif
759 for (j=0; j<FRAMES; j++) {
760 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
761 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
764 XUngrabServer(dpy);
766 #undef FRAMES
769 void
770 animateResize(WScreen *scr, int x, int y, int w, int h,
771 int fx, int fy, int fw, int fh, int hiding)
773 int style = wPreferences.iconification_style; /* Catch the value */
774 int steps, k;
776 if (style == WIS_NONE)
777 return;
779 if (style == WIS_RANDOM) {
780 style = rand()%3;
783 k = (hiding ? 2 : 3);
784 switch(style) {
785 case WIS_TWIST:
786 steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
787 if (steps>0)
788 animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
789 break;
790 case WIS_FLIP:
791 steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
792 if (steps>0)
793 animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
794 break;
795 case WIS_ZOOM:
796 default:
797 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
798 if (steps>0)
799 animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
800 break;
803 #endif /* ANIMATIONS */
806 static void
807 flushExpose()
809 XEvent tmpev;
811 while (XCheckTypedEvent(dpy, Expose, &tmpev))
812 WMHandleEvent(&tmpev);
813 XSync(dpy, 0);
816 static void
817 unmapTransientsFor(WWindow *wwin)
819 WWindow *tmp;
822 tmp = wwin->screen_ptr->focused_window;
823 while (tmp) {
824 /* unmap the transients for this transient */
825 if (tmp!=wwin && tmp->transient_for == wwin->client_win
826 && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
827 || tmp->flags.shaded)) {
828 unmapTransientsFor(tmp);
829 tmp->flags.miniaturized = 1;
830 if (!tmp->flags.shaded) {
831 wWindowUnmap(tmp);
832 } else {
833 XUnmapWindow(dpy, tmp->frame->core->window);
836 if (!tmp->flags.shaded)
838 wClientSetState(tmp, IconicState, None);
840 WMPostNotificationName(WMNChangedState, tmp, "iconify-transient");
842 tmp = tmp->prev;
847 static void
848 mapTransientsFor(WWindow *wwin)
850 WWindow *tmp;
852 tmp = wwin->screen_ptr->focused_window;
853 while (tmp) {
854 /* recursively map the transients for this transient */
855 if (tmp!=wwin && tmp->transient_for == wwin->client_win
856 && /*!tmp->flags.mapped*/ tmp->flags.miniaturized
857 && tmp->icon==NULL) {
858 mapTransientsFor(tmp);
859 tmp->flags.miniaturized = 0;
860 if (!tmp->flags.shaded) {
861 wWindowMap(tmp);
862 } else {
863 XMapWindow(dpy, tmp->frame->core->window);
865 tmp->flags.semi_focused = 0;
867 if (!tmp->flags.shaded)
869 wClientSetState(tmp, NormalState, None);
871 WMPostNotificationName(WMNChangedState, tmp, "iconify-transient");
873 tmp = tmp->prev;
877 #if 0
878 static void
879 setupIconGrabs(WIcon *icon)
881 /* setup passive grabs on the icon */
882 XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
883 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
884 XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
885 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
886 XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
887 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
888 XSync(dpy, 0);
890 #endif
892 static WWindow*
893 recursiveTransientFor(WWindow *wwin)
895 int i;
897 if (!wwin)
898 return None;
900 /* hackish way to detect transient_for cycle */
901 i = wwin->screen_ptr->window_count+1;
903 while (wwin && wwin->transient_for != None && i>0) {
904 wwin = wWindowFor(wwin->transient_for);
905 i--;
907 if (i==0 && wwin) {
908 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
909 wwin->frame->title);
910 return NULL;
913 return wwin;
916 #if 0
917 static void
918 removeIconGrabs(WIcon *icon)
920 /* remove passive grabs on the icon */
921 XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
922 XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
923 XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);
924 XSync(dpy, 0);
926 #endif
929 void
930 wIconifyWindow(WWindow *wwin)
932 XWindowAttributes attribs;
933 int present;
936 if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
937 /* the window doesn't exist anymore */
938 return;
941 if (wwin->flags.miniaturized) {
942 return;
945 if (wwin->transient_for!=None &&
946 wwin->transient_for!=wwin->screen_ptr->root_win) {
947 WWindow *owner = wWindowFor(wwin->transient_for);
949 if (owner && owner->flags.miniaturized)
950 return;
953 present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
955 /* if the window is in another workspace, simplify process */
956 if (present) {
957 /* icon creation may take a while */
958 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
959 ButtonMotionMask|ButtonReleaseMask, GrabModeAsync,
960 GrabModeAsync, None, None, CurrentTime);
963 if (!wPreferences.disable_miniwindows
964 #ifdef NETWM_HINTS
965 && !wwin->flags.net_handle_icon
966 #endif
968 if (!wwin->flags.icon_moved) {
969 PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y, wGetHeadForWindow(wwin));
971 wwin->icon = wIconCreate(wwin);
973 wwin->icon->mapped = 1;
976 wwin->flags.miniaturized = 1;
977 wwin->flags.mapped = 0;
979 /* unmap transients */
981 unmapTransientsFor(wwin);
983 if (present) {
984 wSoundPlay(WSOUND_ICONIFY);
986 XUngrabPointer(dpy, CurrentTime);
987 wWindowUnmap(wwin);
988 /* let all Expose events arrive so that we can repaint
989 * something before the animation starts (and the server is grabbed) */
990 XSync(dpy, 0);
992 if (wPreferences.disable_miniwindows
993 #ifdef NETWM_HINTS
994 || wwin->flags.net_handle_icon
995 #endif
997 wClientSetState(wwin, IconicState, None);
998 else
999 wClientSetState(wwin, IconicState, wwin->icon->icon_win);
1001 flushExpose();
1002 #ifdef ANIMATIONS
1003 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
1004 && !wPreferences.no_animations) {
1005 int ix, iy, iw, ih;
1007 if (!wPreferences.disable_miniwindows
1008 #ifdef NETWM_HINTS
1009 && !wwin->flags.net_handle_icon
1010 #endif
1012 ix = wwin->icon_x;
1013 iy = wwin->icon_y;
1014 iw = wwin->icon->core->width;
1015 ih = wwin->icon->core->height;
1016 } else {
1017 #ifdef KWM_HINTS
1018 WArea area;
1020 if (wKWMGetIconGeometry(wwin, &area)) {
1021 ix = area.x1;
1022 iy = area.y1;
1023 iw = area.x2 - ix;
1024 ih = area.y2 - iy;
1025 } else
1026 #endif /* KWM_HINTS */
1027 #ifdef NETWM_HINTS
1028 if (wwin->flags.net_handle_icon) {
1029 ix = wwin->icon_x;
1030 iy = wwin->icon_y;
1031 iw = wwin->icon_w;
1032 ih = wwin->icon_h;
1033 } else
1034 #endif
1036 ix = 0;
1037 iy = 0;
1038 iw = wwin->screen_ptr->scr_width;
1039 ih = wwin->screen_ptr->scr_height;
1042 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1043 wwin->frame->core->width, wwin->frame->core->height,
1044 ix, iy, iw, ih, False);
1046 #endif
1049 wwin->flags.skip_next_animation = 0;
1051 if (!wPreferences.disable_miniwindows
1052 #ifdef NETWM_HINTS
1053 && !wwin->flags.net_handle_icon
1054 #endif
1057 if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
1058 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)
1060 XMapWindow(dpy, wwin->icon->core->window);
1062 AddToStackList(wwin->icon->core);
1064 wLowerFrame(wwin->icon->core);
1067 if (present) {
1068 WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
1071 * It doesn't seem to be working and causes button event hangup
1072 * when deiconifying a transient window.
1073 setupIconGrabs(wwin->icon);
1075 if ((wwin->flags.focused
1076 || (owner && wwin->client_win == owner->client_win))
1077 && wPreferences.focus_mode==WKF_CLICK) {
1078 WWindow *tmp;
1080 tmp = wwin->prev;
1081 while (tmp) {
1082 if (!WFLAGP(tmp, no_focusable)
1083 && !(tmp->flags.hidden||tmp->flags.miniaturized)
1084 && (wwin->frame->workspace == tmp->frame->workspace))
1085 break;
1086 tmp = tmp->prev;
1088 wSetFocusTo(wwin->screen_ptr, tmp);
1089 } else if (wPreferences.focus_mode!=WKF_CLICK) {
1090 wSetFocusTo(wwin->screen_ptr, NULL);
1093 #ifdef ANIMATIONS
1094 if (!wwin->screen_ptr->flags.startup) {
1095 /* Catch up with events not processed while animation was running */
1096 Window clientwin = wwin->client_win;
1098 ProcessPendingEvents();
1100 /* the window can disappear while ProcessPendingEvents() runs */
1101 if (!wWindowFor(clientwin)) {
1102 return;
1105 #endif
1108 /* maybe we want to do this regardless of net_handle_icon
1109 * it seems to me we might break behaviour this way.
1111 if (wwin->flags.selected && !wPreferences.disable_miniwindows
1112 #ifdef NETWM_HINTS
1113 && !wwin->flags.net_handle_icon
1114 #endif
1116 wIconSelect(wwin->icon);
1118 WMPostNotificationName(WMNChangedState, wwin, "iconify");
1124 void
1125 wDeiconifyWindow(WWindow *wwin)
1127 #ifdef NETWM_HINTS
1128 /* we're hiding for show_desktop */
1129 int netwm_hidden = wwin->flags.net_show_desktop &&
1130 wwin->frame->workspace!=wwin->screen_ptr->current_workspace;
1131 #else
1132 int netwm_hidden = False;
1133 #endif
1135 if (!netwm_hidden)
1136 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1138 if (!wwin->flags.miniaturized)
1139 return;
1141 if (wwin->transient_for != None
1142 && wwin->transient_for != wwin->screen_ptr->root_win) {
1143 WWindow *owner = recursiveTransientFor(wwin);
1145 if (owner && owner->flags.miniaturized) {
1146 wDeiconifyWindow(owner);
1147 wSetFocusTo(wwin->screen_ptr, wwin);
1148 wRaiseFrame(wwin->frame->core);
1149 return;
1153 wwin->flags.miniaturized = 0;
1155 if (!netwm_hidden && !wwin->flags.shaded) {
1156 wwin->flags.mapped = 1;
1159 if (!netwm_hidden || wPreferences.sticky_icons) {
1160 /* maybe we want to do this regardless of net_handle_icon
1161 * it seems to me we might break behaviour this way.
1163 if (!wPreferences.disable_miniwindows
1164 #ifdef NETWM_HINTS
1165 && !wwin->flags.net_handle_icon
1166 #endif
1167 && wwin->icon != NULL) {
1168 if (wwin->icon->selected)
1169 wIconSelect(wwin->icon);
1171 XUnmapWindow(dpy, wwin->icon->core->window);
1175 if (!netwm_hidden)
1176 wSoundPlay(WSOUND_DEICONIFY);
1178 /* if the window is in another workspace, do it silently */
1179 if (!netwm_hidden) {
1180 #ifdef ANIMATIONS
1181 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1182 && !wwin->flags.skip_next_animation && wwin->icon != NULL) {
1183 int ix, iy, iw, ih;
1185 if (!wPreferences.disable_miniwindows
1186 #ifdef NETWM_HINTS
1187 && !wwin->flags.net_handle_icon
1188 #endif
1190 ix = wwin->icon_x;
1191 iy = wwin->icon_y;
1192 iw = wwin->icon->core->width;
1193 ih = wwin->icon->core->height;
1194 } else {
1195 #ifdef KWM_HINTS
1196 WArea area;
1198 if (wKWMGetIconGeometry(wwin, &area)) {
1199 ix = area.x1;
1200 iy = area.y1;
1201 iw = area.x2 - ix;
1202 ih = area.y2 - iy;
1203 } else
1204 #endif /* KWM_HINTS */
1205 #ifdef NETWM_HINTS
1206 if (wwin->flags.net_handle_icon) {
1207 ix = wwin->icon_x;
1208 iy = wwin->icon_y;
1209 iw = wwin->icon_w;
1210 ih = wwin->icon_h;
1211 } else
1212 #endif
1214 ix = 0;
1215 iy = 0;
1216 iw = wwin->screen_ptr->scr_width;
1217 ih = wwin->screen_ptr->scr_height;
1220 animateResize(wwin->screen_ptr, ix, iy, iw, ih,
1221 wwin->frame_x, wwin->frame_y,
1222 wwin->frame->core->width, wwin->frame->core->height,
1223 False);
1225 #endif /* ANIMATIONS */
1226 wwin->flags.skip_next_animation = 0;
1227 XGrabServer(dpy);
1228 if (!wwin->flags.shaded) {
1229 XMapWindow(dpy, wwin->client_win);
1231 XMapWindow(dpy, wwin->frame->core->window);
1232 wRaiseFrame(wwin->frame->core);
1233 if (!wwin->flags.shaded) {
1234 wClientSetState(wwin, NormalState, None);
1236 mapTransientsFor(wwin);
1239 if (!wPreferences.disable_miniwindows && wwin->icon != NULL
1240 #ifdef NETWM_HINTS
1241 && !wwin->flags.net_handle_icon
1242 #endif
1244 RemoveFromStackList(wwin->icon->core);
1245 /* removeIconGrabs(wwin->icon);*/
1246 wIconDestroy(wwin->icon);
1247 wwin->icon = NULL;
1250 if (!netwm_hidden) {
1251 XUngrabServer(dpy);
1253 wSetFocusTo(wwin->screen_ptr, wwin);
1255 #ifdef ANIMATIONS
1256 if (!wwin->screen_ptr->flags.startup) {
1257 /* Catch up with events not processed while animation was running */
1258 Window clientwin = wwin->client_win;
1260 ProcessPendingEvents();
1262 /* the window can disappear while ProcessPendingEvents() runs */
1263 if (!wWindowFor(clientwin)) {
1264 return;
1267 #endif
1270 if (wPreferences.auto_arrange_icons) {
1271 wArrangeIcons(wwin->screen_ptr, True);
1274 WMPostNotificationName(WMNChangedState, wwin, "iconify");
1276 /* In case we were shaded and iconified, also unshade */
1277 if (!netwm_hidden)
1278 wUnshadeWindow(wwin);
1283 static void
1284 hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
1286 if (wwin->flags.miniaturized) {
1287 if (wwin->icon) {
1288 XUnmapWindow(dpy, wwin->icon->core->window);
1289 wwin->icon->mapped = 0;
1291 wwin->flags.hidden = 1;
1293 WMPostNotificationName(WMNChangedState, wwin, "hide");
1294 return;
1297 if (wwin->flags.inspector_open) {
1298 wHideInspectorForWindow(wwin);
1301 wwin->flags.hidden = 1;
1302 wWindowUnmap(wwin);
1304 wClientSetState(wwin, IconicState, icon->icon_win);
1305 flushExpose();
1306 wSoundPlay(WSOUND_HIDE);
1307 #ifdef ANIMATIONS
1308 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1309 !wwin->flags.skip_next_animation && animate) {
1310 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1311 wwin->frame->core->width, wwin->frame->core->height,
1312 icon_x, icon_y, icon->core->width, icon->core->height,
1313 True);
1315 #endif
1316 wwin->flags.skip_next_animation = 0;
1318 WMPostNotificationName(WMNChangedState, wwin, "hide");
1323 void
1324 wHideOtherApplications(WWindow *awin)
1326 WWindow *wwin;
1327 WApplication *tapp;
1329 if (!awin)
1330 return;
1331 wwin = awin->screen_ptr->focused_window;
1334 while (wwin) {
1335 if (wwin!=awin
1336 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1337 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1338 && !wwin->flags.internal_window
1339 && wGetWindowOfInspectorForWindow(wwin) != awin
1340 && !WFLAGP(wwin, no_hide_others)) {
1342 if (wwin->main_window==None || WFLAGP(wwin, no_appicon)) {
1343 if (!WFLAGP(wwin, no_miniaturizable)) {
1344 wwin->flags.skip_next_animation = 1;
1345 wIconifyWindow(wwin);
1347 } else if (wwin->main_window!=None
1348 && awin->main_window != wwin->main_window) {
1349 tapp = wApplicationOf(wwin->main_window);
1350 if (tapp) {
1351 tapp->flags.skip_next_animation = 1;
1352 wHideApplication(tapp);
1353 } else {
1354 if (!WFLAGP(wwin, no_miniaturizable)) {
1355 wwin->flags.skip_next_animation = 1;
1356 wIconifyWindow(wwin);
1361 wwin = wwin->prev;
1364 wSetFocusTo(awin->screen_ptr, awin);
1370 void
1371 wHideApplication(WApplication *wapp)
1373 WScreen *scr;
1374 WWindow *wlist;
1375 int hadfocus;
1377 if (!wapp) {
1378 wwarning("trying to hide a non grouped window");
1379 return;
1381 if (!wapp->main_window_desc) {
1382 wwarning("group leader not found for window group");
1383 return;
1385 scr = wapp->main_window_desc->screen_ptr;
1386 hadfocus = 0;
1387 wlist = scr->focused_window;
1388 if (!wlist)
1389 return;
1391 if (wlist->main_window == wapp->main_window)
1392 wapp->last_focused = wlist;
1393 else
1394 wapp->last_focused = NULL;
1395 while (wlist) {
1396 if (wlist->main_window == wapp->main_window) {
1397 if (wlist->flags.focused) {
1398 hadfocus = 1;
1400 if (wapp->app_icon)
1401 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1402 wapp->app_icon->y_pos, wlist,
1403 !wapp->flags.skip_next_animation);
1405 wlist = wlist->prev;
1408 wapp->flags.skip_next_animation = 0;
1410 if (hadfocus) {
1411 if (wPreferences.focus_mode==WKF_CLICK) {
1412 wlist = scr->focused_window;
1413 while (wlist) {
1414 if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden
1415 && (wlist->flags.mapped || wlist->flags.shaded))
1416 break;
1417 wlist = wlist->prev;
1419 wSetFocusTo(scr, wlist);
1420 } else {
1421 wSetFocusTo(scr, NULL);
1425 wapp->flags.hidden = 1;
1427 if(wPreferences.auto_arrange_icons) {
1428 wArrangeIcons(scr, True);
1430 #ifdef HIDDENDOT
1431 if (wapp->app_icon)
1432 wAppIconPaint(wapp->app_icon);
1433 #endif
1439 static void
1440 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1441 int bringToCurrentWS)
1443 if (bringToCurrentWS)
1444 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1446 wwin->flags.hidden=0;
1448 wSoundPlay(WSOUND_UNHIDE);
1449 #ifdef ANIMATIONS
1450 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1451 && animate) {
1452 animateResize(wwin->screen_ptr, icon_x, icon_y,
1453 icon->core->width, icon->core->height,
1454 wwin->frame_x, wwin->frame_y,
1455 wwin->frame->core->width, wwin->frame->core->height,
1456 True);
1458 #endif
1459 wwin->flags.skip_next_animation = 0;
1460 if (wwin->screen_ptr->current_workspace == wwin->frame->workspace) {
1461 XMapWindow(dpy, wwin->client_win);
1462 XMapWindow(dpy, wwin->frame->core->window);
1463 wClientSetState(wwin, NormalState, None);
1464 wwin->flags.mapped=1;
1465 wRaiseFrame(wwin->frame->core);
1467 if (wwin->flags.inspector_open) {
1468 wUnhideInspectorForWindow(wwin);
1471 WMPostNotificationName(WMNChangedState, wwin, "hide");
1475 void
1476 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1478 WScreen *scr;
1479 WWindow *wlist, *next;
1480 WWindow *focused=NULL;
1481 Bool shouldArrangeIcons = False;
1483 if (!wapp)
1484 return;
1486 scr = wapp->main_window_desc->screen_ptr;
1487 wlist = scr->focused_window;
1488 if (!wlist)
1489 return;
1491 /* goto beginning of list */
1492 while (wlist->prev)
1493 wlist = wlist->prev;
1495 while (wlist) {
1496 next = wlist->next;
1498 if (wlist->main_window == wapp->main_window) {
1499 if (wlist->flags.focused)
1500 focused = wlist;
1501 else if (!focused || !focused->flags.focused)
1502 focused = wlist;
1504 if (wlist->flags.miniaturized) {
1505 if (bringToCurrentWS || wPreferences.sticky_icons ||
1506 wlist->frame->workspace == scr->current_workspace) {
1507 if (wlist->icon && !wlist->icon->mapped) {
1508 XMapWindow(dpy, wlist->icon->core->window);
1509 wlist->icon->mapped = 1;
1512 if (bringToCurrentWS)
1513 wWindowChangeWorkspace(wlist, scr->current_workspace);
1514 wlist->flags.hidden = 0;
1515 if (miniwindows &&
1516 wlist->frame->workspace == scr->current_workspace) {
1517 wDeiconifyWindow(wlist);
1519 shouldArrangeIcons = True;
1520 WMPostNotificationName(WMNChangedState, wlist, "hide");
1521 } else if (wlist->flags.shaded) {
1522 if (bringToCurrentWS)
1523 wWindowChangeWorkspace(wlist, scr->current_workspace);
1524 wlist->flags.hidden = 0;
1525 if (wlist->frame->workspace == scr->current_workspace) {
1526 XMapWindow(dpy, wlist->frame->core->window);
1527 if (miniwindows) {
1528 wUnshadeWindow(wlist);
1529 wRaiseFrame(wlist->frame->core);
1532 WMPostNotificationName(WMNChangedState, wlist, "hide");
1533 } else if (wlist->flags.hidden) {
1534 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1535 wapp->app_icon->y_pos, wlist,
1536 !wapp->flags.skip_next_animation,
1537 bringToCurrentWS);
1538 } else {
1539 if (bringToCurrentWS
1540 && wlist->frame->workspace != scr->current_workspace) {
1541 wWindowChangeWorkspace(wlist, scr->current_workspace);
1543 wRaiseFrame(wlist->frame->core);
1546 wlist = next;
1549 wapp->flags.skip_next_animation = 0;
1550 wapp->flags.hidden = 0;
1552 if (wapp->last_focused && wapp->last_focused->flags.mapped) {
1553 wRaiseFrame(wapp->last_focused->frame->core);
1554 wSetFocusTo(scr, wapp->last_focused);
1555 } else if (focused) {
1556 wSetFocusTo(scr, focused);
1558 wapp->last_focused = NULL;
1559 if (shouldArrangeIcons || wPreferences.auto_arrange_icons) {
1560 wArrangeIcons(scr, True);
1562 #ifdef HIDDENDOT
1563 wAppIconPaint(wapp->app_icon);
1564 #endif
1569 void
1570 wShowAllWindows(WScreen *scr)
1572 WWindow *wwin, *old_foc;
1573 WApplication *wapp;
1575 old_foc = wwin = scr->focused_window;
1576 while (wwin) {
1577 if (!wwin->flags.internal_window &&
1578 (scr->current_workspace == wwin->frame->workspace
1579 || IS_OMNIPRESENT(wwin))) {
1580 if (wwin->flags.miniaturized) {
1581 wwin->flags.skip_next_animation = 1;
1582 wDeiconifyWindow(wwin);
1583 } else if (wwin->flags.hidden) {
1584 wapp = wApplicationOf(wwin->main_window);
1585 if (wapp) {
1586 wUnhideApplication(wapp, False, False);
1587 } else {
1588 wwin->flags.skip_next_animation = 1;
1589 wDeiconifyWindow(wwin);
1593 wwin = wwin->prev;
1595 wSetFocusTo(scr, old_foc);
1596 /*wRaiseFrame(old_foc->frame->core);*/
1600 void
1601 wRefreshDesktop(WScreen *scr)
1603 Window win;
1604 XSetWindowAttributes attr;
1606 attr.backing_store = NotUseful;
1607 attr.save_under = False;
1608 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1609 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1610 (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
1611 &attr);
1612 XMapRaised(dpy, win);
1613 XDestroyWindow(dpy, win);
1614 XFlush(dpy);
1618 void
1619 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1621 WWindow *wwin;
1622 WAppIcon *aicon;
1624 int head;
1625 const int heads = wXineramaHeads(scr);
1627 struct HeadVars {
1628 int pf; /* primary axis */
1629 int sf; /* secondary axis */
1630 int fullW;
1631 int fullH;
1632 int pi, si;
1633 int sx1, sx2, sy1, sy2; /* screen boundary */
1634 int sw, sh;
1635 int xo, yo;
1636 int xs, ys;
1637 } *vars;
1639 int isize = wPreferences.icon_size;
1641 vars = (struct HeadVars*)wmalloc(sizeof(struct HeadVars)*heads);
1643 for (head = 0; head < heads; ++head) {
1644 #if 0
1645 WMRect rect = wGetRectForHead(scr, head);
1646 #else
1647 WArea area = wGetUsableAreaForHead(scr, head, NULL, False);
1648 WMRect rect = wmkrect(area.x1, area.y1, area.x2-area.x1, area.y2-area.y1);
1649 #endif
1651 vars[head].pi = vars[head].si = 0;
1652 vars[head].sx1 = rect.pos.x;
1653 vars[head].sy1 = rect.pos.y;
1654 vars[head].sw = rect.size.width;
1655 vars[head].sh = rect.size.height;
1656 vars[head].sx2 = vars[head].sx1 + vars[head].sw;
1657 vars[head].sy2 = vars[head].sy1 + vars[head].sh;
1659 #if 0
1660 if (scr->dock) {
1661 if (scr->dock->on_right_side)
1662 vars[head].sx2 -= isize + DOCK_EXTRA_SPACE;
1663 else
1664 vars[head].sx1 += isize + DOCK_EXTRA_SPACE;
1666 #endif
1668 vars[head].sw = isize * (vars[head].sw/isize);
1669 vars[head].sh = isize * (vars[head].sh/isize);
1670 vars[head].fullW = (vars[head].sx2-vars[head].sx1)/isize;
1671 vars[head].fullH = (vars[head].sy2-vars[head].sy1)/isize;
1673 /* icon yard boundaries */
1674 if (wPreferences.icon_yard & IY_VERT) {
1675 vars[head].pf = vars[head].fullH;
1676 vars[head].sf = vars[head].fullW;
1677 } else {
1678 vars[head].pf = vars[head].fullW;
1679 vars[head].sf = vars[head].fullH;
1681 if (wPreferences.icon_yard & IY_RIGHT) {
1682 vars[head].xo = vars[head].sx2 - isize;
1683 vars[head].xs = -1;
1684 } else {
1685 vars[head].xo = vars[head].sx1;
1686 vars[head].xs = 1;
1688 if (wPreferences.icon_yard & IY_TOP) {
1689 vars[head].yo = vars[head].sy1;
1690 vars[head].ys = 1;
1691 } else {
1692 vars[head].yo = vars[head].sy2 - isize;
1693 vars[head].ys = -1;
1697 #define X ((wPreferences.icon_yard & IY_VERT) \
1698 ? vars[head].xo + vars[head].xs*(vars[head].si*isize) \
1699 : vars[head].xo + vars[head].xs*(vars[head].pi*isize))
1701 #define Y ((wPreferences.icon_yard & IY_VERT) \
1702 ? vars[head].yo + vars[head].ys*(vars[head].pi*isize) \
1703 : vars[head].yo + vars[head].ys*(vars[head].si*isize))
1706 /* arrange application icons */
1707 aicon = scr->app_icon_list;
1708 /* reverse them to avoid unnecessarily sliding of icons */
1709 while (aicon && aicon->next)
1710 aicon = aicon->next;
1712 while (aicon) {
1713 if (!aicon->docked) {
1714 /* CHECK: can icon be NULL here ? */
1715 /* The intention here is to place the AppIcon on the head that
1716 * contains most of the applications _main_ window. */
1717 head = wGetHeadForWindow(aicon->icon->owner);
1719 if (aicon->x_pos != X || aicon->y_pos != Y) {
1720 #ifdef ANIMATIONS
1721 if (!wPreferences.no_animations) {
1722 SlideWindow(aicon->icon->core->window,
1723 aicon->x_pos, aicon->y_pos, X, Y);
1725 #endif /* ANIMATIONS */
1727 wAppIconMove(aicon, X, Y);
1728 vars[head].pi++;
1729 if (vars[head].pi >= vars[head].pf) {
1730 vars[head].pi = 0;
1731 vars[head].si++;
1734 aicon = aicon->prev;
1737 /* arrange miniwindows */
1738 wwin = scr->focused_window;
1739 /* reverse them to avoid unnecessarily shuffling */
1740 while (wwin && wwin->prev)
1741 wwin = wwin->prev;
1743 while (wwin) {
1744 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1745 (wwin->frame->workspace==scr->current_workspace ||
1746 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1748 head = wGetHeadForWindow(wwin);
1750 if (arrangeAll || !wwin->flags.icon_moved) {
1751 if (wwin->icon_x != X || wwin->icon_y != Y) {
1752 #ifdef ANIMATIONS
1753 if (wPreferences.no_animations) {
1754 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1755 } else {
1756 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1757 wwin->icon_y, X, Y);
1759 #else
1760 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1761 #endif /* ANIMATIONS */
1763 wwin->icon_x = X;
1764 wwin->icon_y = Y;
1766 vars[head].pi++;
1767 if (vars[head].pi >= vars[head].pf) {
1768 vars[head].pi = 0;
1769 vars[head].si++;
1773 if (arrangeAll) {
1774 wwin->flags.icon_moved = 0;
1776 /* we reversed the order, so we use next */
1777 wwin = wwin->next;
1780 wfree(vars);
1783 #if 0
1784 void
1785 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1787 WWindow *wwin;
1788 WAppIcon *aicon;
1789 int pf; /* primary axis */
1790 int sf; /* secondary axis */
1791 int fullW;
1792 int fullH;
1793 int pi, si;
1794 int sx1, sx2, sy1, sy2; /* screen boundary */
1795 int sw, sh;
1796 int xo, yo;
1797 int xs, ys;
1798 int isize = wPreferences.icon_size;
1801 * Find out screen boundaries.
1805 * Allows each head to have miniwindows
1807 WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
1809 sx1 = rect.pos.x;
1810 sy1 = rect.pos.y;
1811 sw = rect.size.width;
1812 sh = rect.size.height;
1813 sx2 = sx1 + sw;
1814 sy2 = sy1 + sh;
1815 if (scr->dock) {
1816 if (scr->dock->on_right_side)
1817 sx2 -= isize + DOCK_EXTRA_SPACE;
1818 else
1819 sx1 += isize + DOCK_EXTRA_SPACE;
1822 #if 0
1823 sw = isize * (scr->scr_width/isize);
1824 sh = isize * (scr->scr_height/isize);
1825 #else
1826 sw = isize * (sw/isize);
1827 sh = isize * (sh/isize);
1828 #endif
1829 fullW = (sx2-sx1)/isize;
1830 fullH = (sy2-sy1)/isize;
1832 /* icon yard boundaries */
1833 if (wPreferences.icon_yard & IY_VERT) {
1834 pf = fullH;
1835 sf = fullW;
1836 } else {
1837 pf = fullW;
1838 sf = fullH;
1840 if (wPreferences.icon_yard & IY_RIGHT) {
1841 xo = sx2 - isize;
1842 xs = -1;
1843 } else {
1844 xo = sx1;
1845 xs = 1;
1847 if (wPreferences.icon_yard & IY_TOP) {
1848 yo = sy1;
1849 ys = 1;
1850 } else {
1851 yo = sy2 - isize;
1852 ys = -1;
1855 /* arrange icons putting the most recently focused window
1856 * as the last icon */
1857 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1858 : xo + xs*(pi*isize))
1859 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1860 : yo + ys*(si*isize))
1862 /* arrange application icons */
1863 aicon = scr->app_icon_list;
1864 /* reverse them to avoid unnecessarily sliding of icons */
1865 while (aicon && aicon->next)
1866 aicon = aicon->next;
1868 pi = 0;
1869 si = 0;
1870 while (aicon) {
1871 if (!aicon->docked) {
1872 if (aicon->x_pos != X || aicon->y_pos != Y) {
1873 #ifdef ANIMATIONS
1874 if (!wPreferences.no_animations) {
1875 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1876 X, Y);
1878 #endif /* ANIMATIONS */
1880 wAppIconMove(aicon, X, Y);
1881 pi++;
1883 /* we reversed the order so we use prev */
1884 aicon = aicon->prev;
1885 if (pi >= pf) {
1886 pi=0;
1887 si++;
1891 /* arrange miniwindows */
1893 wwin = scr->focused_window;
1894 /* reverse them to avoid unnecessarily shuffling */
1895 while (wwin && wwin->prev)
1896 wwin = wwin->prev;
1898 while (wwin) {
1899 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1900 (wwin->frame->workspace==scr->current_workspace ||
1901 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1903 if (arrangeAll || !wwin->flags.icon_moved) {
1904 if (wwin->icon_x != X || wwin->icon_y != Y) {
1905 #ifdef ANIMATIONS
1906 if (wPreferences.no_animations) {
1907 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1908 } else {
1909 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1910 wwin->icon_y, X, Y);
1912 #else
1913 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1914 #endif /* ANIMATIONS */
1916 wwin->icon_x = X;
1917 wwin->icon_y = Y;
1918 pi++;
1921 if (arrangeAll) {
1922 wwin->flags.icon_moved = 0;
1924 /* we reversed the order, so we use next */
1925 wwin = wwin->next;
1926 if (pi >= pf) {
1927 pi=0;
1928 si++;
1932 #endif
1934 void
1935 wSelectWindow(WWindow *wwin, Bool flag)
1937 WScreen *scr = wwin->screen_ptr;
1939 if (flag) {
1940 wwin->flags.selected = 1;
1941 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1943 if (!HAS_BORDER(wwin)) {
1944 XSetWindowBorderWidth(dpy, wwin->frame->core->window,
1945 FRAME_BORDER_WIDTH);
1948 if (!scr->selected_windows)
1949 scr->selected_windows = WMCreateArray(4);
1950 WMAddToArray(scr->selected_windows, wwin);
1951 } else {
1952 wwin->flags.selected = 0;
1953 XSetWindowBorder(dpy, wwin->frame->core->window,
1954 scr->frame_border_pixel);
1956 if (!HAS_BORDER(wwin)) {
1957 XSetWindowBorderWidth(dpy, wwin->frame->core->window, 0);
1960 if (scr->selected_windows) {
1961 WMRemoveFromArray(scr->selected_windows, wwin);
1967 void
1968 wMakeWindowVisible(WWindow *wwin)
1970 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
1971 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1973 if (wwin->flags.shaded) {
1974 wUnshadeWindow(wwin);
1976 if (wwin->flags.hidden) {
1977 WApplication *app;
1979 app = wApplicationOf(wwin->main_window);
1980 if (app) {
1981 /* trick to get focus to this window */
1982 app->last_focused = wwin;
1983 wUnhideApplication(app, False, False);
1986 if (wwin->flags.miniaturized) {
1987 wDeiconifyWindow(wwin);
1988 } else {
1989 if (!WFLAGP(wwin, no_focusable))
1990 wSetFocusTo(wwin->screen_ptr, wwin);
1991 wRaiseFrame(wwin->frame->core);