1 /* action.c- misc. window commands (miniaturize, hide etc.)
3 * Window Maker window manager
5 * Copyright (c) 1997, 1998, 1999 Alfredo K. Kojima
6 * Copyright (c) 1998 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,
28 #include <X11/Xutil.h>
35 #include "WindowMaker.h"
42 #include "application.h"
48 #include "winspector.h"
49 #include "workspace.h"
61 /****** Global Variables ******/
62 extern Time LastTimestamp
;
63 extern Time LastFocusChange
;
65 extern Cursor wCursor
[WCUR_LAST
];
67 extern WPreferences wPreferences
;
69 extern Atom _XA_WM_TAKE_FOCUS
;
72 /******* Local Variables *******/
77 {SHADE_STEPS_UF
, SHADE_DELAY_UF
},
78 {SHADE_STEPS_F
, SHADE_DELAY_F
},
79 {SHADE_STEPS_M
, SHADE_DELAY_M
},
80 {SHADE_STEPS_S
, SHADE_DELAY_S
},
81 {SHADE_STEPS_U
, SHADE_DELAY_U
}};
83 #define SHADE_STEPS shadePars[(int)wPreferences.shade_speed].steps
84 #define SHADE_DELAY shadePars[(int)wPreferences.shade_speed].delay
87 static int ignoreTimestamp
=0;
92 processEvents(int event_count
)
97 * This is a hack. When animations are enabled, processing of
98 * events ocurred during a animation are delayed until it's end.
99 * Calls that consider the TimeStamp, like XSetInputFocus(), will
100 * fail because the TimeStamp is too old. Then, for example, if
101 * the user changes window focus while a miniaturize animation is
102 * in course, the window will not get focus properly after the end
103 * of the animation. This tries to workaround it by passing CurrentTime
104 * as the TimeStamp for XSetInputFocus() for all events ocurred during
108 while (XPending(dpy
) && event_count
--) {
109 WMNextEvent(dpy
, &event
);
110 WMHandleEvent(&event
);
114 #endif /* ANIMATIONS */
119 *----------------------------------------------------------------------
121 * Changes the window focus to the one passed as argument.
122 * If the window to focus is not already focused, it will be brought
123 * to the head of the list of windows. Previously focused window is
127 * Window list may be reordered and the window focus is changed.
129 *----------------------------------------------------------------------
132 wSetFocusTo(WScreen
*scr
, WWindow
*wwin
)
134 static WScreen
*old_scr
=NULL
;
136 WWindow
*old_focused
;
137 WWindow
*focused
=scr
->focused_window
;
138 int timestamp
=LastTimestamp
;
139 WApplication
*oapp
=NULL
, *napp
=NULL
;
144 old_focused
=old_scr
->focused_window
;
146 LastFocusChange
= timestamp
;
149 * This is a hack, because XSetInputFocus() should have a proper
150 * timestamp instead of CurrentTime but it seems that some times
151 * clients will not receive focus properly that way.
154 timestamp
= CurrentTime
;
157 oapp
= wApplicationOf(old_focused
->main_window
);
160 XSetInputFocus(dpy
, scr
->no_focus_win
, RevertToParent
, timestamp
);
162 wWindowUnfocus(old_focused
);
165 wAppMenuUnmap(oapp
->menu
);
167 wApplicationDeactivate(oapp
);
171 WMPostNotificationName(WMNChangedFocus
, NULL
, (void*)True
);
173 } else if (old_scr
!= scr
&& old_focused
) {
174 wWindowUnfocus(old_focused
);
177 wasfocused
= wwin
->flags
.focused
;
178 napp
= wApplicationOf(wwin
->main_window
);
180 /* remember last workspace where the app has been */
182 napp
->last_workspace
= wwin
->screen_ptr
->current_workspace
;
184 if (wwin
->flags
.mapped
&& !WFLAGP(wwin
, no_focusable
)) {
185 /* install colormap if colormap mode is lock mode */
186 if (wPreferences
.colormap_mode
==WCM_CLICK
)
187 wColormapInstallForWindow(scr
, wwin
);
189 /* set input focus */
190 switch (wwin
->focus_mode
) {
192 XSetInputFocus(dpy
, scr
->no_focus_win
, RevertToParent
, timestamp
);
196 case WFM_LOCALLY_ACTIVE
:
197 XSetInputFocus(dpy
, wwin
->client_win
, RevertToParent
, timestamp
);
200 case WFM_GLOBALLY_ACTIVE
:
204 if (wwin
->protocols
.TAKE_FOCUS
) {
205 wClientSendProtocol(wwin
, _XA_WM_TAKE_FOCUS
, timestamp
);
209 XSetInputFocus(dpy
, scr
->no_focus_win
, RevertToParent
, timestamp
);
211 if (WFLAGP(wwin
, no_focusable
))
214 /* if this is not the focused window focus it */
216 /* change the focus window list order */
218 wwin
->prev
->next
= wwin
->next
;
221 wwin
->next
->prev
= wwin
->prev
;
223 wwin
->prev
= focused
;
224 focused
->next
= wwin
;
226 scr
->focused_window
= wwin
;
228 if (oapp
&& oapp
!= napp
) {
229 wAppMenuUnmap(oapp
->menu
);
231 wApplicationDeactivate(oapp
);
236 wWindowFocus(wwin
, focused
);
238 if (napp
&& !wasfocused
) {
240 wUserMenuRefreshInstances(napp
->menu
, wwin
);
241 #endif /* USER_MENU */
243 if (wwin
->flags
.mapped
)
244 wAppMenuMap(napp
->menu
, wwin
);
246 wApplicationActivate(napp
);
256 wShadeWindow(WWindow
*wwin
)
263 if (wwin
->flags
.shaded
)
268 XLowerWindow(dpy
, wwin
->client_win
);
270 wSoundPlay(WSOUND_SHADE
);
273 if (!wwin
->screen_ptr
->flags
.startup
&& !wwin
->flags
.skip_next_animation
274 && !wPreferences
.no_animations
) {
275 /* do the shading animation */
276 h
= wwin
->frame
->core
->height
;
279 w
= wwin
->frame
->core
->width
;
280 y
= wwin
->frame
->top_width
;
281 while (h
>wwin
->frame
->top_width
+1) {
282 XMoveWindow(dpy
, wwin
->client_win
, 0, y
);
283 XResizeWindow(dpy
, wwin
->frame
->core
->window
, w
, h
);
286 if (time(NULL
)-time0
> MAX_ANIMATION_TIME
)
290 wusleep(SHADE_DELAY
*1000L);
294 XMoveWindow(dpy
, wwin
->client_win
, 0, wwin
->frame
->top_width
);
296 #endif /* ANIMATIONS */
298 wwin
->flags
.skip_next_animation
= 0;
299 wwin
->flags
.shaded
= 1;
300 wwin
->flags
.mapped
= 0;
301 /* prevent window withdrawal when getting UnmapNotify */
302 XSelectInput(dpy
, wwin
->client_win
,
303 wwin
->event_mask
& ~StructureNotifyMask
);
304 XUnmapWindow(dpy
, wwin
->client_win
);
305 XSelectInput(dpy
, wwin
->client_win
, wwin
->event_mask
);
307 /* for the client it's just like iconification */
308 wFrameWindowResize(wwin
->frame
, wwin
->frame
->core
->width
,
309 wwin
->frame
->top_width
- 1);
311 wwin
->client
.y
= wwin
->frame_y
- wwin
->client
.height
312 + wwin
->frame
->top_width
;
313 wWindowSynthConfigureNotify(wwin
);
316 wClientSetState(wwin, IconicState, None);
319 WMPostNotificationName(WMNChangedState
, wwin
, "shade");
322 if (!wwin
->screen_ptr
->flags
.startup
) {
323 /* Look at processEvents() for reason of this code. */
325 processEvents(XPending(dpy
));
332 wUnshadeWindow(WWindow
*wwin
)
337 #endif /* ANIMATIONS */
340 if (!wwin
->flags
.shaded
)
345 wwin
->flags
.shaded
= 0;
346 wwin
->flags
.mapped
= 1;
347 XMapWindow(dpy
, wwin
->client_win
);
349 wSoundPlay(WSOUND_UNSHADE
);
352 if (!wPreferences
.no_animations
&& !wwin
->flags
.skip_next_animation
) {
353 /* do the shading animation */
354 h
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
;
355 y
= wwin
->frame
->top_width
- wwin
->client
.height
;
356 s
= abs(y
)/SHADE_STEPS
;
358 w
= wwin
->frame
->core
->width
;
359 XMoveWindow(dpy
, wwin
->client_win
, 0, y
);
361 while (h
< wwin
->client
.height
+ wwin
->frame
->top_width
362 + wwin
->frame
->bottom_width
) {
363 XResizeWindow(dpy
, wwin
->frame
->core
->window
, w
, h
);
364 XMoveWindow(dpy
, wwin
->client_win
, 0, y
);
367 wusleep(SHADE_DELAY
*2000L/3);
371 if (time(NULL
)-time0
> MAX_ANIMATION_TIME
)
375 XMoveWindow(dpy
, wwin
->client_win
, 0, wwin
->frame
->top_width
);
377 #endif /* ANIMATIONS */
379 wwin
->flags
.skip_next_animation
= 0;
380 wFrameWindowResize(wwin
->frame
, wwin
->frame
->core
->width
,
381 wwin
->frame
->top_width
+ wwin
->client
.height
382 + wwin
->frame
->bottom_width
);
384 wwin
->client
.y
= wwin
->frame_y
+ wwin
->frame
->top_width
;
385 wWindowSynthConfigureNotify(wwin
);
388 wClientSetState(wwin, NormalState, None);
390 /* if the window is focused, set the focus again as it was disabled during
392 if (wwin
->flags
.focused
)
393 wSetFocusTo(wwin
->screen_ptr
, wwin
);
395 WMPostNotificationName(WMNChangedState
, wwin
, "shade");
400 wMaximizeWindow(WWindow
*wwin
, int directions
)
402 int new_width
, new_height
, new_x
, new_y
;
403 WArea usableArea
= wwin
->screen_ptr
->totalUsableArea
;
407 if (WFLAGP(wwin
, no_resizable
))
412 totalArea
.x2
= wwin
->screen_ptr
->scr_width
;
413 totalArea
.y2
= wwin
->screen_ptr
->scr_height
;
416 if (wwin
->screen_ptr
->xine_count
> 0
417 && !(directions
& MAX_IGNORE_XINERAMA
)) {
418 WScreen
*scr
= wwin
->screen_ptr
;
421 rect
= wGetRectForHead(scr
, wGetHeadForWindow(wwin
));
422 totalArea
.x1
= rect
.pos
.x
;
423 totalArea
.y1
= rect
.pos
.y
;
424 totalArea
.x2
= totalArea
.x1
+ rect
.size
.width
;
425 totalArea
.y2
= totalArea
.y1
+ rect
.size
.height
;
427 usableArea
.x1
= WMAX(totalArea
.x1
, usableArea
.x1
);
428 usableArea
.y1
= WMAX(totalArea
.y1
, usableArea
.y1
);
429 usableArea
.x2
= WMIN(totalArea
.x2
, usableArea
.x2
);
430 usableArea
.y2
= WMIN(totalArea
.y2
, usableArea
.y2
);
432 #endif /* XINERAMA */
434 if (WFLAGP(wwin
, full_maximize
)) {
435 usableArea
= totalArea
;
438 if (wwin
->flags
.shaded
) {
439 wwin
->flags
.skip_next_animation
= 1;
440 wUnshadeWindow(wwin
);
442 wwin
->flags
.maximized
= directions
;
443 wwin
->old_geometry
.width
= wwin
->client
.width
;
444 wwin
->old_geometry
.height
= wwin
->client
.height
;
445 wwin
->old_geometry
.x
= wwin
->frame_x
;
446 wwin
->old_geometry
.y
= wwin
->frame_y
;
449 wKWMUpdateClientGeometryRestore(wwin
);
452 if (directions
& MAX_HORIZONTAL
) {
454 new_width
= (usableArea
.x2
-usableArea
.x1
)-FRAME_BORDER_WIDTH
*2;
455 new_x
= usableArea
.x1
;
459 new_x
= wwin
->frame_x
;
460 new_width
= wwin
->frame
->core
->width
;
464 if (directions
& MAX_VERTICAL
) {
466 new_height
= (usableArea
.y2
-usableArea
.y1
)-FRAME_BORDER_WIDTH
*2;
467 new_y
= usableArea
.y1
;
468 if (WFLAGP(wwin
, full_maximize
)) {
469 new_y
-= wwin
->frame
->top_width
;
470 new_height
+= wwin
->frame
->bottom_width
- 1;
473 new_y
= wwin
->frame_y
;
474 new_height
= wwin
->frame
->core
->height
;
477 if (!WFLAGP(wwin
, full_maximize
)) {
478 new_height
-= wwin
->frame
->top_width
+wwin
->frame
->bottom_width
;
481 wWindowConstrainSize(wwin
, &new_width
, &new_height
);
483 wWindowCropSize(wwin
, usableArea
.x2
-usableArea
.x1
,
484 usableArea
.y2
-usableArea
.y1
,
485 &new_width
, &new_height
);
487 wWindowConfigure(wwin
, new_x
, new_y
, new_width
, new_height
);
490 WMPostNotificationName(WMNChangedState
, wwin
, "maximize");
492 wSoundPlay(WSOUND_MAXIMIZE
);
497 wUnmaximizeWindow(WWindow
*wwin
)
499 int restore_x
, restore_y
;
501 if (!wwin
->flags
.maximized
)
504 if (wwin
->flags
.shaded
) {
505 wwin
->flags
.skip_next_animation
= 1;
506 wUnshadeWindow(wwin
);
508 restore_x
= (wwin
->flags
.maximized
& MAX_HORIZONTAL
) ?
509 wwin
->old_geometry
.x
: wwin
->frame_x
;
510 restore_y
= (wwin
->flags
.maximized
& MAX_VERTICAL
) ?
511 wwin
->old_geometry
.y
: wwin
->frame_y
;
512 wwin
->flags
.maximized
= 0;
513 wWindowConfigure(wwin
, restore_x
, restore_y
,
514 wwin
->old_geometry
.width
, wwin
->old_geometry
.height
);
516 WMPostNotificationName(WMNChangedState
, wwin
, "maximize");
518 wSoundPlay(WSOUND_UNMAXIMIZE
);
523 animateResizeFlip(WScreen
*scr
, int x
, int y
, int w
, int h
,
524 int fx
, int fy
, int fw
, int fh
, int steps
)
526 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
527 float cx
, cy
, cw
, ch
;
528 float xstep
, ystep
, wstep
, hstep
;
531 float angle
, final_angle
, delta
;
533 xstep
= (float)(fx
-x
)/steps
;
534 ystep
= (float)(fy
-y
)/steps
;
535 wstep
= (float)(fw
-w
)/steps
;
536 hstep
= (float)(fh
-h
)/steps
;
543 final_angle
= 2*WM_PI
*MINIATURIZE_ANIMATION_TWIST_F
;
544 delta
= (float)(final_angle
/FRAMES
);
545 for (angle
=0;; angle
+=delta
) {
546 if (angle
> final_angle
)
549 dx
= (cw
/10) - ((cw
/5) * sin(angle
));
550 dch
= (ch
/2) * cos(angle
);
553 points
[0].x
= cx
+ dx
; points
[0].y
= midy
- dch
;
554 points
[1].x
= cx
+ cw
- dx
; points
[1].y
= points
[0].y
;
555 points
[2].x
= cx
+ cw
+ dx
; points
[2].y
= midy
+ dch
;
556 points
[3].x
= cx
- dx
; points
[3].y
= points
[2].y
;
557 points
[4].x
= points
[0].x
; points
[4].y
= points
[0].y
;
560 XDrawLines(dpy
,scr
->root_win
,scr
->frame_gc
,points
, 5, CoordModeOrigin
);
562 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
563 wusleep(MINIATURIZE_ANIMATION_DELAY_F
);
566 XDrawLines(dpy
,scr
->root_win
,scr
->frame_gc
,points
, 5, CoordModeOrigin
);
572 if (angle
>= final_angle
)
582 animateResizeTwist(WScreen
*scr
, int x
, int y
, int w
, int h
,
583 int fx
, int fy
, int fw
, int fh
, int steps
)
585 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
586 float cx
, cy
, cw
, ch
;
587 float xstep
, ystep
, wstep
, hstep
;
589 float angle
, final_angle
, a
, d
, delta
;
596 xstep
= (float)(fx
-x
)/steps
;
597 ystep
= (float)(fy
-y
)/steps
;
598 wstep
= (float)(fw
-w
)/steps
;
599 hstep
= (float)(fh
-h
)/steps
;
606 final_angle
= 2*WM_PI
*MINIATURIZE_ANIMATION_TWIST_T
;
607 delta
= (float)(final_angle
/FRAMES
);
608 for (angle
=0;; angle
+=delta
) {
609 if (angle
> final_angle
)
613 d
= sqrt((cw
/2)*(cw
/2)+(ch
/2)*(ch
/2));
615 points
[0].x
= cx
+cos(angle
-a
)*d
;
616 points
[0].y
= cy
+sin(angle
-a
)*d
;
617 points
[1].x
= cx
+cos(angle
+a
)*d
;
618 points
[1].y
= cy
+sin(angle
+a
)*d
;
619 points
[2].x
= cx
+cos(angle
-a
+WM_PI
)*d
;
620 points
[2].y
= cy
+sin(angle
-a
+WM_PI
)*d
;
621 points
[3].x
= cx
+cos(angle
+a
+WM_PI
)*d
;
622 points
[3].y
= cy
+sin(angle
+a
+WM_PI
)*d
;
623 points
[4].x
= cx
+cos(angle
-a
)*d
;
624 points
[4].y
= cy
+sin(angle
-a
)*d
;
626 XDrawLines(dpy
, scr
->root_win
, scr
->frame_gc
, points
, 5, CoordModeOrigin
);
628 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
629 wusleep(MINIATURIZE_ANIMATION_DELAY_T
);
632 XDrawLines(dpy
, scr
->root_win
, scr
->frame_gc
, points
, 5, CoordModeOrigin
);
638 if (angle
>= final_angle
)
648 animateResizeZoom(WScreen
*scr
, int x
, int y
, int w
, int h
,
649 int fx
, int fy
, int fw
, int fh
, int steps
)
651 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
652 float cx
[FRAMES
], cy
[FRAMES
], cw
[FRAMES
], ch
[FRAMES
];
653 float xstep
, ystep
, wstep
, hstep
;
656 xstep
= (float)(fx
-x
)/steps
;
657 ystep
= (float)(fy
-y
)/steps
;
658 wstep
= (float)(fw
-w
)/steps
;
659 hstep
= (float)(fh
-h
)/steps
;
661 for (j
=0; j
<FRAMES
; j
++) {
668 for (i
=0; i
<steps
; i
++) {
669 for (j
=0; j
<FRAMES
; j
++) {
670 XDrawRectangle(dpy
, scr
->root_win
, scr
->frame_gc
,
671 (int)cx
[j
], (int)cy
[j
], (int)cw
[j
], (int)ch
[j
]);
674 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
675 wusleep(MINIATURIZE_ANIMATION_DELAY_Z
);
677 for (j
=0; j
<FRAMES
; j
++) {
678 XDrawRectangle(dpy
, scr
->root_win
, scr
->frame_gc
,
679 (int)cx
[j
], (int)cy
[j
], (int)cw
[j
], (int)ch
[j
]);
694 for (j
=0; j
<FRAMES
; j
++) {
695 XDrawRectangle(dpy
, scr
->root_win
, scr
->frame_gc
,
696 (int)cx
[j
], (int)cy
[j
], (int)cw
[j
], (int)ch
[j
]);
699 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
700 wusleep(MINIATURIZE_ANIMATION_DELAY_Z
);
702 for (j
=0; j
<FRAMES
; j
++) {
703 XDrawRectangle(dpy
, scr
->root_win
, scr
->frame_gc
,
704 (int)cx
[j
], (int)cy
[j
], (int)cw
[j
], (int)ch
[j
]);
713 animateResize(WScreen
*scr
, int x
, int y
, int w
, int h
,
714 int fx
, int fy
, int fw
, int fh
, int hiding
)
716 int style
= wPreferences
.iconification_style
; /* Catch the value */
719 if (style
== WIS_NONE
)
722 if (style
== WIS_RANDOM
) {
726 k
= (hiding
? 2 : 3);
729 steps
= (MINIATURIZE_ANIMATION_STEPS_T
* k
)/3;
731 animateResizeTwist(scr
, x
, y
, w
, h
, fx
, fy
, fw
, fh
, steps
);
734 steps
= (MINIATURIZE_ANIMATION_STEPS_F
* k
)/3;
736 animateResizeFlip(scr
, x
, y
, w
, h
, fx
, fy
, fw
, fh
, steps
);
740 steps
= (MINIATURIZE_ANIMATION_STEPS_Z
* k
)/3;
742 animateResizeZoom(scr
, x
, y
, w
, h
, fx
, fy
, fw
, fh
, steps
);
746 #endif /* ANIMATIONS */
754 while (XCheckTypedEvent(dpy
, Expose
, &tmpev
))
755 WMHandleEvent(&tmpev
);
760 unmapTransientsFor(WWindow
*wwin
)
765 tmp
= wwin
->screen_ptr
->focused_window
;
767 /* unmap the transients for this transient */
768 if (tmp
!=wwin
&& tmp
->transient_for
== wwin
->client_win
769 && (tmp
->flags
.mapped
|| wwin
->screen_ptr
->flags
.startup
770 || tmp
->flags
.shaded
)) {
771 unmapTransientsFor(tmp
);
772 tmp
->flags
.miniaturized
= 1;
773 if (!tmp
->flags
.shaded
) {
776 XUnmapWindow(dpy
, tmp
->frame
->core
->window
);
779 if (!tmp->flags.shaded)
781 wClientSetState(tmp
, IconicState
, None
);
783 WMPostNotificationName(WMNChangedState
, tmp
, "iconify-transient");
791 mapTransientsFor(WWindow
*wwin
)
795 tmp
= wwin
->screen_ptr
->focused_window
;
797 /* recursively map the transients for this transient */
798 if (tmp
!=wwin
&& tmp
->transient_for
== wwin
->client_win
799 && /*!tmp->flags.mapped*/ tmp
->flags
.miniaturized
800 && tmp
->icon
==NULL
) {
801 mapTransientsFor(tmp
);
802 tmp
->flags
.miniaturized
= 0;
803 if (!tmp
->flags
.shaded
) {
806 XMapWindow(dpy
, tmp
->frame
->core
->window
);
808 tmp
->flags
.semi_focused
= 0;
810 if (!tmp->flags.shaded)
812 wClientSetState(tmp
, NormalState
, None
);
814 WMPostNotificationName(WMNChangedState
, tmp
, "iconify-transient");
822 setupIconGrabs(WIcon
*icon
)
824 /* setup passive grabs on the icon */
825 XGrabButton(dpy
, Button1
, AnyModifier
, icon
->core
->window
, True
,
826 ButtonPressMask
, GrabModeSync
, GrabModeAsync
, None
, None
);
827 XGrabButton(dpy
, Button2
, AnyModifier
, icon
->core
->window
, True
,
828 ButtonPressMask
, GrabModeSync
, GrabModeAsync
, None
, None
);
829 XGrabButton(dpy
, Button3
, AnyModifier
, icon
->core
->window
, True
,
830 ButtonPressMask
, GrabModeSync
, GrabModeAsync
, None
, None
);
836 recursiveTransientFor(WWindow
*wwin
)
843 /* hackish way to detect transient_for cycle */
844 i
= wwin
->screen_ptr
->window_count
+1;
846 while (wwin
&& wwin
->transient_for
!= None
&& i
>0) {
847 wwin
= wWindowFor(wwin
->transient_for
);
851 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
861 removeIconGrabs(WIcon
*icon
)
863 /* remove passive grabs on the icon */
864 XUngrabButton(dpy
, Button1
, AnyModifier
, icon
->core
->window
);
865 XUngrabButton(dpy
, Button2
, AnyModifier
, icon
->core
->window
);
866 XUngrabButton(dpy
, Button3
, AnyModifier
, icon
->core
->window
);
873 wIconifyWindow(WWindow
*wwin
)
875 XWindowAttributes attribs
;
879 if (!XGetWindowAttributes(dpy
, wwin
->client_win
, &attribs
)) {
880 /* the window doesn't exist anymore */
884 if (wwin
->flags
.miniaturized
) {
889 if (wwin
->transient_for
!=None
) {
890 WWindow
*owner
= wWindowFor(wwin
->transient_for
);
892 if (owner
&& owner
->flags
.miniaturized
)
896 present
= wwin
->frame
->workspace
==wwin
->screen_ptr
->current_workspace
;
898 /* if the window is in another workspace, simplify process */
900 /* icon creation may take a while */
901 XGrabPointer(dpy
, wwin
->screen_ptr
->root_win
, False
,
902 ButtonMotionMask
|ButtonReleaseMask
, GrabModeAsync
,
903 GrabModeAsync
, None
, None
, CurrentTime
);
906 if (!wPreferences
.disable_miniwindows
) {
907 if (!wwin
->flags
.icon_moved
) {
908 PlaceIcon(wwin
->screen_ptr
, &wwin
->icon_x
, &wwin
->icon_y
);
910 wwin
->icon
= wIconCreate(wwin
);
912 wwin
->icon
->mapped
= 1;
915 wwin
->flags
.miniaturized
= 1;
916 wwin
->flags
.mapped
= 0;
918 /* unmap transients */
920 unmapTransientsFor(wwin
);
923 wSoundPlay(WSOUND_ICONIFY
);
925 XUngrabPointer(dpy
, CurrentTime
);
927 /* let all Expose events arrive so that we can repaint
928 * something before the animation starts (and the server is grabbed) */
931 if (wPreferences
.disable_miniwindows
)
932 wClientSetState(wwin
, IconicState
, None
);
934 wClientSetState(wwin
, IconicState
, wwin
->icon
->icon_win
);
938 if (!wwin
->screen_ptr
->flags
.startup
&& !wwin
->flags
.skip_next_animation
939 && !wPreferences
.no_animations
) {
942 if (!wPreferences
.disable_miniwindows
) {
945 iw
= wwin
->icon
->core
->width
;
946 ih
= wwin
->icon
->core
->height
;
951 if (wKWMGetIconGeometry(wwin
, &area
)) {
957 #endif /* KWM_HINTS */
961 iw
= wwin
->screen_ptr
->scr_width
;
962 ih
= wwin
->screen_ptr
->scr_height
;
965 animateResize(wwin
->screen_ptr
, wwin
->frame_x
, wwin
->frame_y
,
966 wwin
->frame
->core
->width
, wwin
->frame
->core
->height
,
967 ix
, iy
, iw
, ih
, False
);
972 wwin
->flags
.skip_next_animation
= 0;
974 if (!wPreferences
.disable_miniwindows
) {
976 if (wwin
->screen_ptr
->current_workspace
==wwin
->frame
->workspace
||
977 IS_OMNIPRESENT(wwin
) || wPreferences
.sticky_icons
)
979 XMapWindow(dpy
, wwin
->icon
->core
->window
);
981 AddToStackList(wwin
->icon
->core
);
983 wLowerFrame(wwin
->icon
->core
);
987 WWindow
*owner
= recursiveTransientFor(wwin
->screen_ptr
->focused_window
);
990 * It doesn't seem to be working and causes button event hangup
991 * when deiconifying a transient window.
992 setupIconGrabs(wwin->icon);
994 if ((wwin
->flags
.focused
995 || (owner
&& wwin
->client_win
== owner
->client_win
))
996 && wPreferences
.focus_mode
==WKF_CLICK
) {
1001 if (!WFLAGP(tmp
, no_focusable
)
1002 && !(tmp
->flags
.hidden
||tmp
->flags
.miniaturized
)
1003 && (wwin
->frame
->workspace
== tmp
->frame
->workspace
))
1007 wSetFocusTo(wwin
->screen_ptr
, tmp
);
1008 } else if (wPreferences
.focus_mode
!=WKF_CLICK
) {
1009 wSetFocusTo(wwin
->screen_ptr
, NULL
);
1013 if (!wwin
->screen_ptr
->flags
.startup
) {
1014 Window clientwin
= wwin
->client_win
;
1017 processEvents(XPending(dpy
));
1019 /* the window can disappear while doing the processEvents() */
1020 if (!wWindowFor(clientwin
))
1027 if (wwin
->flags
.selected
&& !wPreferences
.disable_miniwindows
)
1028 wIconSelect(wwin
->icon
);
1030 WMPostNotificationName(WMNChangedState
, wwin
, "iconify");
1037 wDeiconifyWindow(WWindow
*wwin
)
1039 wWindowChangeWorkspace(wwin
, wwin
->screen_ptr
->current_workspace
);
1041 if (!wwin
->flags
.miniaturized
)
1044 if (wwin
->transient_for
!= None
1045 && wwin
->transient_for
!= wwin
->screen_ptr
->root_win
) {
1046 WWindow
*owner
= recursiveTransientFor(wwin
);
1048 if (owner
&& owner
->flags
.miniaturized
) {
1049 wDeiconifyWindow(owner
);
1050 wSetFocusTo(wwin
->screen_ptr
, wwin
);
1051 wRaiseFrame(wwin
->frame
->core
);
1056 wwin
->flags
.miniaturized
= 0;
1057 if (!wwin
->flags
.shaded
)
1058 wwin
->flags
.mapped
= 1;
1060 if (!wPreferences
.disable_miniwindows
) {
1061 if (wwin
->icon
->selected
)
1062 wIconSelect(wwin
->icon
);
1064 XUnmapWindow(dpy
, wwin
->icon
->core
->window
);
1067 wSoundPlay(WSOUND_DEICONIFY
);
1069 /* if the window is in another workspace, do it silently */
1071 if (!wwin
->screen_ptr
->flags
.startup
&& !wPreferences
.no_animations
1072 && !wwin
->flags
.skip_next_animation
) {
1075 if (!wPreferences
.disable_miniwindows
) {
1078 iw
= wwin
->icon
->core
->width
;
1079 ih
= wwin
->icon
->core
->height
;
1084 if (wKWMGetIconGeometry(wwin
, &area
)) {
1090 #endif /* KWM_HINTS */
1094 iw
= wwin
->screen_ptr
->scr_width
;
1095 ih
= wwin
->screen_ptr
->scr_height
;
1098 animateResize(wwin
->screen_ptr
, ix
, iy
, iw
, ih
,
1099 wwin
->frame_x
, wwin
->frame_y
,
1100 wwin
->frame
->core
->width
, wwin
->frame
->core
->height
,
1103 #endif /* ANIMATIONS */
1104 wwin
->flags
.skip_next_animation
= 0;
1106 if (!wwin
->flags
.shaded
) {
1107 XMapWindow(dpy
, wwin
->client_win
);
1109 XMapWindow(dpy
, wwin
->frame
->core
->window
);
1110 wRaiseFrame(wwin
->frame
->core
);
1111 if (!wwin
->flags
.shaded
) {
1112 wClientSetState(wwin
, NormalState
, None
);
1114 mapTransientsFor(wwin
);
1116 if (!wPreferences
.disable_miniwindows
) {
1117 RemoveFromStackList(wwin
->icon
->core
);
1118 /* removeIconGrabs(wwin->icon);*/
1119 wIconDestroy(wwin
->icon
);
1124 if (wPreferences
.focus_mode
==WKF_CLICK
)
1125 wSetFocusTo(wwin
->screen_ptr
, wwin
);
1128 if (!wwin
->screen_ptr
->flags
.startup
) {
1129 Window clientwin
= wwin
->client_win
;
1132 processEvents(XPending(dpy
));
1134 if (!wWindowFor(clientwin
))
1139 if (wPreferences
.auto_arrange_icons
) {
1140 wArrangeIcons(wwin
->screen_ptr
, True
);
1143 WMPostNotificationName(WMNChangedState
, wwin
, "iconify");
1145 /* In case we were shaded and iconified, also unshade */
1146 wUnshadeWindow(wwin
);
1152 hideWindow(WIcon
*icon
, int icon_x
, int icon_y
, WWindow
*wwin
, int animate
)
1154 if (wwin
->flags
.miniaturized
) {
1156 XUnmapWindow(dpy
, wwin
->icon
->core
->window
);
1157 wwin
->icon
->mapped
= 0;
1159 wwin
->flags
.hidden
= 1;
1161 WMPostNotificationName(WMNChangedState
, wwin
, "hide");
1165 if (wwin
->flags
.inspector_open
) {
1166 wHideInspectorForWindow(wwin
);
1169 wwin
->flags
.hidden
= 1;
1172 wClientSetState(wwin
, IconicState
, icon
->icon_win
);
1174 wSoundPlay(WSOUND_HIDE
);
1176 if (!wwin
->screen_ptr
->flags
.startup
&& !wPreferences
.no_animations
&&
1177 !wwin
->flags
.skip_next_animation
&& animate
) {
1178 animateResize(wwin
->screen_ptr
, wwin
->frame_x
, wwin
->frame_y
,
1179 wwin
->frame
->core
->width
, wwin
->frame
->core
->height
,
1180 icon_x
, icon_y
, icon
->core
->width
, icon
->core
->height
,
1184 wwin
->flags
.skip_next_animation
= 0;
1186 WMPostNotificationName(WMNChangedState
, wwin
, "hide");
1192 wHideOtherApplications(WWindow
*awin
)
1199 wwin
= awin
->screen_ptr
->focused_window
;
1204 && wwin
->frame
->workspace
== awin
->screen_ptr
->current_workspace
1205 && !(wwin
->flags
.miniaturized
||wwin
->flags
.hidden
)
1206 && !wwin
->flags
.internal_window
1207 && wGetWindowOfInspectorForWindow(wwin
) != awin
1208 && !WFLAGP(wwin
, no_hide_others
)) {
1210 if (wwin
->main_window
==None
|| WFLAGP(wwin
, no_appicon
)) {
1211 if (!WFLAGP(wwin
, no_miniaturizable
)) {
1212 wwin
->flags
.skip_next_animation
= 1;
1213 wIconifyWindow(wwin
);
1215 } else if (wwin
->main_window
!=None
1216 && awin
->main_window
!= wwin
->main_window
) {
1217 tapp
= wApplicationOf(wwin
->main_window
);
1219 tapp
->flags
.skip_next_animation
= 1;
1220 wHideApplication(tapp
);
1222 if (!WFLAGP(wwin
, no_miniaturizable
)) {
1223 wwin
->flags
.skip_next_animation
= 1;
1224 wIconifyWindow(wwin
);
1232 wSetFocusTo(awin->screen_ptr, awin);
1239 wHideApplication(WApplication
*wapp
)
1246 wwarning("trying to hide a non grouped window");
1249 if (!wapp
->main_window_desc
) {
1250 wwarning("group leader not found for window group");
1253 scr
= wapp
->main_window_desc
->screen_ptr
;
1255 wlist
= scr
->focused_window
;
1259 if (wlist
->main_window
== wapp
->main_window
)
1260 wapp
->last_focused
= wlist
;
1262 wapp
->last_focused
= NULL
;
1264 if (wlist
->main_window
== wapp
->main_window
) {
1265 if (wlist
->flags
.focused
) {
1269 hideWindow(wapp
->app_icon
->icon
, wapp
->app_icon
->x_pos
,
1270 wapp
->app_icon
->y_pos
, wlist
,
1271 !wapp
->flags
.skip_next_animation
);
1273 wlist
= wlist
->prev
;
1276 wapp
->flags
.skip_next_animation
= 0;
1279 if (wPreferences
.focus_mode
==WKF_CLICK
) {
1280 wlist
= scr
->focused_window
;
1282 if (!WFLAGP(wlist
, no_focusable
) && !wlist
->flags
.hidden
1283 && (wlist
->flags
.mapped
|| wlist
->flags
.shaded
))
1285 wlist
= wlist
->prev
;
1287 wSetFocusTo(scr
, wlist
);
1289 wSetFocusTo(scr
, NULL
);
1293 wapp
->flags
.hidden
= 1;
1295 if(wPreferences
.auto_arrange_icons
) {
1296 wArrangeIcons(scr
, True
);
1300 wAppIconPaint(wapp
->app_icon
);
1308 unhideWindow(WIcon
*icon
, int icon_x
, int icon_y
, WWindow
*wwin
, int animate
,
1309 int bringToCurrentWS
)
1311 if (bringToCurrentWS
)
1312 wWindowChangeWorkspace(wwin
, wwin
->screen_ptr
->current_workspace
);
1314 wwin
->flags
.hidden
=0;
1315 wwin
->flags
.mapped
=1;
1317 wSoundPlay(WSOUND_UNHIDE
);
1319 if (!wwin
->screen_ptr
->flags
.startup
&& !wPreferences
.no_animations
1321 animateResize(wwin
->screen_ptr
, icon_x
, icon_y
,
1322 icon
->core
->width
, icon
->core
->height
,
1323 wwin
->frame_x
, wwin
->frame_y
,
1324 wwin
->frame
->core
->width
, wwin
->frame
->core
->height
,
1328 wwin
->flags
.skip_next_animation
= 0;
1329 XMapWindow(dpy
, wwin
->client_win
);
1330 XMapWindow(dpy
, wwin
->frame
->core
->window
);
1331 wClientSetState(wwin
, NormalState
, None
);
1332 wRaiseFrame(wwin
->frame
->core
);
1333 if (wwin
->flags
.inspector_open
) {
1334 wUnhideInspectorForWindow(wwin
);
1337 WMPostNotificationName(WMNChangedState
, wwin
, "hide");
1342 wUnhideApplication(WApplication
*wapp
, Bool miniwindows
, Bool bringToCurrentWS
)
1345 WWindow
*wlist
, *next
;
1346 WWindow
*focused
=NULL
;
1351 scr
= wapp
->main_window_desc
->screen_ptr
;
1352 wlist
= scr
->focused_window
;
1354 /* goto beginning of list */
1356 wlist
= wlist
->prev
;
1361 if (wlist
->main_window
== wapp
->main_window
) {
1362 if (wlist
->flags
.focused
)
1364 else if (!focused
|| !focused
->flags
.focused
)
1367 if (wlist
->flags
.miniaturized
&& wlist
->icon
) {
1368 if (bringToCurrentWS
|| wPreferences
.sticky_icons
1369 || wlist
->frame
->workspace
== scr
->current_workspace
) {
1370 if (!wlist
->icon
->mapped
) {
1371 XMapWindow(dpy
, wlist
->icon
->core
->window
);
1372 wlist
->icon
->mapped
= 1;
1374 wlist
->flags
.hidden
= 0;
1376 WMPostNotificationName(WMNChangedState
, wlist
, "hide");
1378 if (wlist
->frame
->workspace
!= scr
->current_workspace
)
1379 wWindowChangeWorkspace(wlist
, scr
->current_workspace
);
1382 wDeiconifyWindow(wlist
);
1384 } else if (wlist
->flags
.hidden
) {
1385 unhideWindow(wapp
->app_icon
->icon
, wapp
->app_icon
->x_pos
,
1386 wapp
->app_icon
->y_pos
, wlist
,
1387 !wapp
->flags
.skip_next_animation
,
1390 if (bringToCurrentWS
1391 && wlist
->frame
->workspace
!= scr
->current_workspace
) {
1392 wWindowChangeWorkspace(wlist
, scr
->current_workspace
);
1394 wRaiseFrame(wlist
->frame
->core
);
1400 wapp
->flags
.skip_next_animation
= 0;
1401 wapp
->flags
.hidden
= 0;
1404 wSetFocusTo(scr
, focused
);
1405 else if (wapp
->last_focused
&& wapp
->last_focused
->flags
.mapped
)
1406 wSetFocusTo(scr
, wapp
->last_focused
);
1407 wapp
->last_focused
= NULL
;
1408 if (wPreferences
.auto_arrange_icons
) {
1409 wArrangeIcons(scr
, True
);
1412 wAppIconPaint(wapp
->app_icon
);
1419 wShowAllWindows(WScreen
*scr
)
1421 WWindow
*wwin
, *old_foc
;
1424 old_foc
= wwin
= scr
->focused_window
;
1426 if (!wwin
->flags
.internal_window
&&
1427 (scr
->current_workspace
== wwin
->frame
->workspace
1428 || IS_OMNIPRESENT(wwin
))) {
1429 if (wwin
->flags
.miniaturized
) {
1430 wwin
->flags
.skip_next_animation
= 1;
1431 wDeiconifyWindow(wwin
);
1432 } else if (wwin
->flags
.hidden
) {
1433 wapp
= wApplicationOf(wwin
->main_window
);
1435 wUnhideApplication(wapp
, False
, False
);
1437 wwin
->flags
.skip_next_animation
= 1;
1438 wDeiconifyWindow(wwin
);
1444 wSetFocusTo(scr
, old_foc
);
1445 /*wRaiseFrame(old_foc->frame->core);*/
1450 wRefreshDesktop(WScreen
*scr
)
1453 XSetWindowAttributes attr
;
1455 attr
.backing_store
= NotUseful
;
1456 attr
.save_under
= False
;
1457 win
= XCreateWindow(dpy
, scr
->root_win
, 0, 0, scr
->scr_width
,
1458 scr
->scr_height
, 0, CopyFromParent
, CopyFromParent
,
1459 (Visual
*)CopyFromParent
, CWBackingStore
|CWSaveUnder
,
1461 XMapRaised(dpy
, win
);
1462 XDestroyWindow(dpy
, win
);
1468 wArrangeIcons(WScreen
*scr
, Bool arrangeAll
)
1472 int pf
; /* primary axis */
1473 int sf
; /* secondary axis */
1477 int sx1
, sx2
, sy1
, sy2
; /* screen boundary */
1481 int isize
= wPreferences
.icon_size
;
1484 * Find out screen boundaries.
1488 sx2
= scr
->scr_width
;
1489 sy2
= scr
->scr_height
;
1491 if (scr
->dock
->on_right_side
)
1492 sx2
-= isize
+ DOCK_EXTRA_SPACE
;
1494 sx1
+= isize
+ DOCK_EXTRA_SPACE
;
1497 sw
= isize
* (scr
->scr_width
/isize
);
1498 sh
= isize
* (scr
->scr_height
/isize
);
1499 fullW
= (sx2
-sx1
)/isize
;
1500 fullH
= (sy2
-sy1
)/isize
;
1502 /* icon yard boundaries */
1503 if (wPreferences
.icon_yard
& IY_VERT
) {
1510 if (wPreferences
.icon_yard
& IY_RIGHT
) {
1517 if (wPreferences
.icon_yard
& IY_TOP
) {
1525 /* arrange icons putting the most recently focused window
1526 * as the last icon */
1527 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1528 : xo + xs*(pi*isize))
1529 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1530 : yo + ys*(si*isize))
1532 /* arrange application icons */
1533 aicon
= scr
->app_icon_list
;
1534 /* reverse them to avoid unnecessarily sliding of icons */
1535 while (aicon
&& aicon
->next
)
1536 aicon
= aicon
->next
;
1541 if (!aicon
->docked
) {
1542 if (aicon
->x_pos
!= X
|| aicon
->y_pos
!= Y
) {
1544 if (!wPreferences
.no_animations
) {
1545 SlideWindow(aicon
->icon
->core
->window
, aicon
->x_pos
, aicon
->y_pos
,
1548 #endif /* ANIMATIONS */
1550 wAppIconMove(aicon
, X
, Y
);
1553 /* we reversed the order so we use prev */
1554 aicon
= aicon
->prev
;
1561 /* arrange miniwindows */
1563 wwin
= scr
->focused_window
;
1564 /* reverse them to avoid unnecessarily shuffling */
1565 while (wwin
&& wwin
->prev
)
1569 if (wwin
->icon
&& wwin
->flags
.miniaturized
&& !wwin
->flags
.hidden
&&
1570 (wwin
->frame
->workspace
==scr
->current_workspace
||
1571 IS_OMNIPRESENT(wwin
) || wPreferences
.sticky_icons
)) {
1573 if (arrangeAll
|| !wwin
->flags
.icon_moved
) {
1574 if (wwin
->icon_x
!= X
|| wwin
->icon_y
!= Y
) {
1576 if (wPreferences
.no_animations
) {
1577 XMoveWindow(dpy
, wwin
->icon
->core
->window
, X
, Y
);
1579 SlideWindow(wwin
->icon
->core
->window
, wwin
->icon_x
,
1580 wwin
->icon_y
, X
, Y
);
1583 XMoveWindow(dpy
, wwin
->icon
->core
->window
, X
, Y
);
1584 #endif /* ANIMATIONS */
1592 wwin
->flags
.icon_moved
= 0;
1594 /* we reversed the order, so we use next */
1605 wSelectWindow(WWindow
*wwin
, Bool flag
)
1607 WScreen
*scr
= wwin
->screen_ptr
;
1610 wwin
->flags
.selected
= 1;
1611 XSetWindowBorder(dpy
, wwin
->frame
->core
->window
, scr
->white_pixel
);
1613 if (WFLAGP(wwin
, no_border
)) {
1614 XSetWindowBorderWidth(dpy
, wwin
->frame
->core
->window
,
1615 FRAME_BORDER_WIDTH
);
1618 if (!scr
->selected_windows
)
1619 scr
->selected_windows
= WMCreateArray(4);
1620 WMAddToArray(scr
->selected_windows
, wwin
);
1622 wwin
->flags
.selected
= 0;
1623 XSetWindowBorder(dpy
, wwin
->frame
->core
->window
,
1624 scr
->frame_border_pixel
);
1626 if (WFLAGP(wwin
, no_border
)) {
1627 XSetWindowBorderWidth(dpy
, wwin
->frame
->core
->window
, 0);
1630 if (scr
->selected_windows
) {
1631 WMRemoveFromArray(scr
->selected_windows
, wwin
);
1638 wMakeWindowVisible(WWindow
*wwin
)
1640 if (wwin
->frame
->workspace
!= wwin
->screen_ptr
->current_workspace
)
1641 wWorkspaceChange(wwin
->screen_ptr
, wwin
->frame
->workspace
);
1643 if (wwin
->flags
.shaded
) {
1644 wUnshadeWindow(wwin
);
1646 if (wwin
->flags
.hidden
) {
1649 app
= wApplicationOf(wwin
->main_window
);
1651 wUnhideApplication(app
, False
, False
);
1652 } else if (wwin
->flags
.miniaturized
) {
1653 wDeiconifyWindow(wwin
);
1655 if (!WFLAGP(wwin
, no_focusable
))
1656 wSetFocusTo(wwin
->screen_ptr
, wwin
);
1657 wRaiseFrame(wwin
->frame
->core
);