- Fixed labels not to display '\n' as a character if multiple '\n' are passed
[wmaker-crm.git] / src / actions.c
blob478944dae801aa8ded1098dc130d85c834e12b50
1 /* action.c- misc. window commands (miniaturize, hide etc.)
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997-2002 Alfredo K. Kojima
6 * Copyright (c) 1998-2002 Dan Pascu
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 * USA.
24 #include "wconfig.h"
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <math.h>
33 #include <time.h>
35 #include "WindowMaker.h"
36 #include "wcore.h"
37 #include "framewin.h"
38 #include "window.h"
39 #include "client.h"
40 #include "icon.h"
41 #include "funcs.h"
42 #include "application.h"
43 #include "actions.h"
44 #include "stacking.h"
45 #include "appicon.h"
46 #include "dock.h"
47 #include "appmenu.h"
48 #include "winspector.h"
49 #include "workspace.h"
50 #include "wsound.h"
52 #ifdef GNOME_STUFF
53 # include "gnome.h"
54 #endif
55 #ifdef KWM_HINTS
56 # include "kwm.h"
57 #endif
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 *******/
73 static struct {
74 int steps;
75 int delay;
76 } shadePars[5] = {
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_US, SHADE_DELAY_US}};
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;
90 #ifdef ANIMATIONS
91 static void
92 processEvents(int event_count)
94 XEvent event;
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
105 * the animation.
107 ignoreTimestamp=1;
108 while (XPending(dpy) && event_count--) {
109 WMNextEvent(dpy, &event);
110 WMHandleEvent(&event);
112 ignoreTimestamp=0;
114 #endif /* ANIMATIONS */
119 *----------------------------------------------------------------------
120 * wSetFocusTo--
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
124 * unfocused.
126 * Side effects:
127 * Window list may be reordered and the window focus is changed.
129 *----------------------------------------------------------------------
131 void
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;
140 int wasfocused;
142 if (!old_scr)
143 old_scr=scr;
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.
152 if (ignoreTimestamp)
154 timestamp = CurrentTime;
156 if (old_focused)
157 oapp = wApplicationOf(old_focused->main_window);
159 if (wwin == NULL) {
160 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
161 if (old_focused) {
162 wWindowUnfocus(old_focused);
164 if (oapp) {
165 wAppMenuUnmap(oapp->menu);
166 #ifdef NEWAPPICON
167 wApplicationDeactivate(oapp);
168 #endif
171 WMPostNotificationName(WMNChangedFocus, NULL, (void*)True);
172 return;
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 */
181 if (napp) {
182 /*napp->last_workspace = wwin->screen_ptr->current_workspace;*/
183 napp->last_workspace = wwin->frame->workspace;
186 if (wwin->flags.mapped && !WFLAGP(wwin, no_focusable)) {
187 /* install colormap if colormap mode is lock mode */
188 if (wPreferences.colormap_mode==WCM_CLICK)
189 wColormapInstallForWindow(scr, wwin);
191 /* set input focus */
192 switch (wwin->focus_mode) {
193 case WFM_NO_INPUT:
194 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
195 break;
197 case WFM_PASSIVE:
198 case WFM_LOCALLY_ACTIVE:
199 XSetInputFocus(dpy, wwin->client_win, RevertToParent, timestamp);
200 break;
202 case WFM_GLOBALLY_ACTIVE:
203 break;
205 XFlush(dpy);
206 if (wwin->protocols.TAKE_FOCUS) {
207 wClientSendProtocol(wwin, _XA_WM_TAKE_FOCUS, timestamp);
209 XSync(dpy, False);
210 } else {
211 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
213 if (WFLAGP(wwin, no_focusable))
214 return;
216 /* if this is not the focused window focus it */
217 if (focused!=wwin) {
218 /* change the focus window list order */
219 if (wwin->prev)
220 wwin->prev->next = wwin->next;
222 if (wwin->next)
223 wwin->next->prev = wwin->prev;
225 wwin->prev = focused;
226 focused->next = wwin;
227 wwin->next = NULL;
228 scr->focused_window = wwin;
230 if (oapp && oapp != napp) {
231 wAppMenuUnmap(oapp->menu);
232 #ifdef NEWAPPICON
233 wApplicationDeactivate(oapp);
234 #endif
238 wWindowFocus(wwin, focused);
240 if (napp && !wasfocused) {
241 #ifdef USER_MENU
242 wUserMenuRefreshInstances(napp->menu, wwin);
243 #endif /* USER_MENU */
245 if (wwin->flags.mapped)
246 wAppMenuMap(napp->menu, wwin);
247 #ifdef NEWAPPICON
248 wApplicationActivate(napp);
249 #endif
252 XFlush(dpy);
253 old_scr=scr;
257 void
258 wShadeWindow(WWindow *wwin)
260 time_t time0;
261 #ifdef ANIMATIONS
262 int y, s, w, h;
263 #endif
265 if (wwin->flags.shaded)
266 return;
268 time0 = time(NULL);
270 XLowerWindow(dpy, wwin->client_win);
272 wSoundPlay(WSOUND_SHADE);
274 #ifdef ANIMATIONS
275 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
276 && !wPreferences.no_animations) {
277 /* do the shading animation */
278 h = wwin->frame->core->height;
279 s = h/SHADE_STEPS;
280 if (s < 1) s=1;
281 w = wwin->frame->core->width;
282 y = wwin->frame->top_width;
283 while (h>wwin->frame->top_width+1) {
284 XMoveWindow(dpy, wwin->client_win, 0, y);
285 XResizeWindow(dpy, wwin->frame->core->window, w, h);
286 XFlush(dpy);
288 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
289 break;
291 if (SHADE_DELAY > 0) {
292 wusleep(SHADE_DELAY*1000L);
293 } else {
294 wusleep(10);
296 h-=s;
297 y-=s;
299 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
301 #endif /* ANIMATIONS */
303 wwin->flags.skip_next_animation = 0;
304 wwin->flags.shaded = 1;
305 wwin->flags.mapped = 0;
306 /* prevent window withdrawal when getting UnmapNotify */
307 XSelectInput(dpy, wwin->client_win,
308 wwin->event_mask & ~StructureNotifyMask);
309 XUnmapWindow(dpy, wwin->client_win);
310 XSelectInput(dpy, wwin->client_win, wwin->event_mask);
312 /* for the client it's just like iconification */
313 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
314 wwin->frame->top_width - 1);
316 wwin->client.y = wwin->frame_y - wwin->client.height
317 + wwin->frame->top_width;
318 wWindowSynthConfigureNotify(wwin);
321 wClientSetState(wwin, IconicState, None);
324 WMPostNotificationName(WMNChangedState, wwin, "shade");
326 #ifdef ANIMATIONS
327 if (!wwin->screen_ptr->flags.startup) {
328 /* Look at processEvents() for reason of this code. */
329 XSync(dpy, 0);
330 processEvents(XPending(dpy));
332 #endif
336 void
337 wUnshadeWindow(WWindow *wwin)
339 time_t time0;
340 #ifdef ANIMATIONS
341 int y, s, w, h;
342 #endif /* ANIMATIONS */
345 if (!wwin->flags.shaded)
346 return;
348 time0 = time(NULL);
350 wwin->flags.shaded = 0;
351 wwin->flags.mapped = 1;
352 XMapWindow(dpy, wwin->client_win);
354 wSoundPlay(WSOUND_UNSHADE);
356 #ifdef ANIMATIONS
357 if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) {
358 /* do the shading animation */
359 h = wwin->frame->top_width + wwin->frame->bottom_width;
360 y = wwin->frame->top_width - wwin->client.height;
361 s = abs(y)/SHADE_STEPS;
362 if (s<1) s=1;
363 w = wwin->frame->core->width;
364 XMoveWindow(dpy, wwin->client_win, 0, y);
365 if (s>0) {
366 while (h < wwin->client.height + wwin->frame->top_width
367 + wwin->frame->bottom_width) {
368 XResizeWindow(dpy, wwin->frame->core->window, w, h);
369 XMoveWindow(dpy, wwin->client_win, 0, y);
370 XFlush(dpy);
371 if (SHADE_DELAY > 0) {
372 wusleep(SHADE_DELAY*2000L/3);
373 } else {
374 wusleep(10);
376 h+=s;
377 y+=s;
379 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
380 break;
383 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
385 #endif /* ANIMATIONS */
387 wwin->flags.skip_next_animation = 0;
388 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
389 wwin->frame->top_width + wwin->client.height
390 + wwin->frame->bottom_width);
392 wwin->client.y = wwin->frame_y + wwin->frame->top_width;
393 wWindowSynthConfigureNotify(wwin);
396 wClientSetState(wwin, NormalState, None);
398 /* if the window is focused, set the focus again as it was disabled during
399 * shading */
400 if (wwin->flags.focused)
401 wSetFocusTo(wwin->screen_ptr, wwin);
403 WMPostNotificationName(WMNChangedState, wwin, "shade");
407 void
408 wMaximizeWindow(WWindow *wwin, int directions)
410 int new_width, new_height, new_x, new_y;
411 WArea usableArea = wwin->screen_ptr->totalUsableArea;
412 WArea totalArea;
415 if (WFLAGP(wwin, no_resizable))
416 return;
418 totalArea.x1 = 0;
419 totalArea.y1 = 0;
420 totalArea.x2 = wwin->screen_ptr->scr_width;
421 totalArea.y2 = wwin->screen_ptr->scr_height;
423 #ifdef XINERAMA
424 if (wwin->screen_ptr->xine_count > 0
425 && !(directions & MAX_IGNORE_XINERAMA)) {
426 WScreen *scr = wwin->screen_ptr;
427 WMRect rect;
429 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
430 totalArea.x1 = rect.pos.x;
431 totalArea.y1 = rect.pos.y;
432 totalArea.x2 = totalArea.x1 + rect.size.width;
433 totalArea.y2 = totalArea.y1 + rect.size.height;
435 usableArea.x1 = WMAX(totalArea.x1, usableArea.x1);
436 usableArea.y1 = WMAX(totalArea.y1, usableArea.y1);
437 usableArea.x2 = WMIN(totalArea.x2, usableArea.x2);
438 usableArea.y2 = WMIN(totalArea.y2, usableArea.y2);
440 #endif /* XINERAMA */
442 if (WFLAGP(wwin, full_maximize)) {
443 usableArea = totalArea;
446 if (wwin->flags.shaded) {
447 wwin->flags.skip_next_animation = 1;
448 wUnshadeWindow(wwin);
450 wwin->flags.maximized = directions;
451 wwin->old_geometry.width = wwin->client.width;
452 wwin->old_geometry.height = wwin->client.height;
453 wwin->old_geometry.x = wwin->frame_x;
454 wwin->old_geometry.y = wwin->frame_y;
456 #ifdef KWM_HINTS
457 wKWMUpdateClientGeometryRestore(wwin);
458 #endif
460 if (directions & MAX_HORIZONTAL) {
462 new_width = (usableArea.x2-usableArea.x1)-FRAME_BORDER_WIDTH*2;
463 new_x = usableArea.x1;
465 } else {
467 new_x = wwin->frame_x;
468 new_width = wwin->frame->core->width;
472 if (directions & MAX_VERTICAL) {
474 new_height = (usableArea.y2-usableArea.y1)-FRAME_BORDER_WIDTH*2;
475 new_y = usableArea.y1;
476 if (WFLAGP(wwin, full_maximize)) {
477 new_y -= wwin->frame->top_width;
478 new_height += wwin->frame->bottom_width - 1;
480 } else {
481 new_y = wwin->frame_y;
482 new_height = wwin->frame->core->height;
485 if (!WFLAGP(wwin, full_maximize)) {
486 new_height -= wwin->frame->top_width+wwin->frame->bottom_width;
489 wWindowConstrainSize(wwin, &new_width, &new_height);
491 wWindowCropSize(wwin, usableArea.x2-usableArea.x1,
492 usableArea.y2-usableArea.y1,
493 &new_width, &new_height);
495 wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
498 WMPostNotificationName(WMNChangedState, wwin, "maximize");
500 wSoundPlay(WSOUND_MAXIMIZE);
504 void
505 wUnmaximizeWindow(WWindow *wwin)
507 int restore_x, restore_y;
509 if (!wwin->flags.maximized)
510 return;
512 if (wwin->flags.shaded) {
513 wwin->flags.skip_next_animation = 1;
514 wUnshadeWindow(wwin);
516 restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ?
517 wwin->old_geometry.x : wwin->frame_x;
518 restore_y = (wwin->flags.maximized & MAX_VERTICAL) ?
519 wwin->old_geometry.y : wwin->frame_y;
520 wwin->flags.maximized = 0;
521 wWindowConfigure(wwin, restore_x, restore_y,
522 wwin->old_geometry.width, wwin->old_geometry.height);
524 WMPostNotificationName(WMNChangedState, wwin, "maximize");
526 wSoundPlay(WSOUND_UNMAXIMIZE);
529 #ifdef ANIMATIONS
530 static void
531 animateResizeFlip(WScreen *scr, int x, int y, int w, int h,
532 int fx, int fy, int fw, int fh, int steps)
534 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
535 float cx, cy, cw, ch;
536 float xstep, ystep, wstep, hstep;
537 XPoint points[5];
538 float dx, dch, midy;
539 float angle, final_angle, delta;
541 xstep = (float)(fx-x)/steps;
542 ystep = (float)(fy-y)/steps;
543 wstep = (float)(fw-w)/steps;
544 hstep = (float)(fh-h)/steps;
546 cx = (float)x;
547 cy = (float)y;
548 cw = (float)w;
549 ch = (float)h;
551 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F;
552 delta = (float)(final_angle/FRAMES);
553 for (angle=0;; angle+=delta) {
554 if (angle > final_angle)
555 angle = final_angle;
557 dx = (cw/10) - ((cw/5) * sin(angle));
558 dch = (ch/2) * cos(angle);
559 midy = cy + (ch/2);
561 points[0].x = cx + dx; points[0].y = midy - dch;
562 points[1].x = cx + cw - dx; points[1].y = points[0].y;
563 points[2].x = cx + cw + dx; points[2].y = midy + dch;
564 points[3].x = cx - dx; points[3].y = points[2].y;
565 points[4].x = points[0].x; points[4].y = points[0].y;
567 XGrabServer(dpy);
568 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
569 XFlush(dpy);
570 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
571 wusleep(MINIATURIZE_ANIMATION_DELAY_F);
572 #else
573 wusleep(10);
574 #endif
576 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
577 XUngrabServer(dpy);
578 cx+=xstep;
579 cy+=ystep;
580 cw+=wstep;
581 ch+=hstep;
582 if (angle >= final_angle)
583 break;
586 XFlush(dpy);
588 #undef FRAMES
591 static void
592 animateResizeTwist(WScreen *scr, int x, int y, int w, int h,
593 int fx, int fy, int fw, int fh, int steps)
595 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
596 float cx, cy, cw, ch;
597 float xstep, ystep, wstep, hstep;
598 XPoint points[5];
599 float angle, final_angle, a, d, delta;
601 x += w/2;
602 y += h/2;
603 fx += fw/2;
604 fy += fh/2;
606 xstep = (float)(fx-x)/steps;
607 ystep = (float)(fy-y)/steps;
608 wstep = (float)(fw-w)/steps;
609 hstep = (float)(fh-h)/steps;
611 cx = (float)x;
612 cy = (float)y;
613 cw = (float)w;
614 ch = (float)h;
616 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T;
617 delta = (float)(final_angle/FRAMES);
618 for (angle=0;; angle+=delta) {
619 if (angle > final_angle)
620 angle = final_angle;
622 a = atan(ch/cw);
623 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
625 points[0].x = cx+cos(angle-a)*d;
626 points[0].y = cy+sin(angle-a)*d;
627 points[1].x = cx+cos(angle+a)*d;
628 points[1].y = cy+sin(angle+a)*d;
629 points[2].x = cx+cos(angle-a+WM_PI)*d;
630 points[2].y = cy+sin(angle-a+WM_PI)*d;
631 points[3].x = cx+cos(angle+a+WM_PI)*d;
632 points[3].y = cy+sin(angle+a+WM_PI)*d;
633 points[4].x = cx+cos(angle-a)*d;
634 points[4].y = cy+sin(angle-a)*d;
635 XGrabServer(dpy);
636 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
637 XFlush(dpy);
638 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
639 wusleep(MINIATURIZE_ANIMATION_DELAY_T);
640 #else
641 wusleep(10);
642 #endif
644 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
645 XUngrabServer(dpy);
646 cx+=xstep;
647 cy+=ystep;
648 cw+=wstep;
649 ch+=hstep;
650 if (angle >= final_angle)
651 break;
654 XFlush(dpy);
656 #undef FRAMES
659 static void
660 animateResizeZoom(WScreen *scr, int x, int y, int w, int h,
661 int fx, int fy, int fw, int fh, int steps)
663 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
664 float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
665 float xstep, ystep, wstep, hstep;
666 int i, j;
668 xstep = (float)(fx-x)/steps;
669 ystep = (float)(fy-y)/steps;
670 wstep = (float)(fw-w)/steps;
671 hstep = (float)(fh-h)/steps;
673 for (j=0; j<FRAMES; j++) {
674 cx[j] = (float)x;
675 cy[j] = (float)y;
676 cw[j] = (float)w;
677 ch[j] = (float)h;
679 XGrabServer(dpy);
680 for (i=0; i<steps; i++) {
681 for (j=0; j<FRAMES; j++) {
682 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
683 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
685 XFlush(dpy);
686 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
687 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
688 #else
689 wusleep(10);
690 #endif
691 for (j=0; j<FRAMES; j++) {
692 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
693 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
694 if (j<FRAMES-1) {
695 cx[j]=cx[j+1];
696 cy[j]=cy[j+1];
697 cw[j]=cw[j+1];
698 ch[j]=ch[j+1];
699 } else {
700 cx[j]+=xstep;
701 cy[j]+=ystep;
702 cw[j]+=wstep;
703 ch[j]+=hstep;
708 for (j=0; j<FRAMES; j++) {
709 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
710 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
712 XFlush(dpy);
713 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
714 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
715 #else
716 wusleep(10);
717 #endif
718 for (j=0; j<FRAMES; j++) {
719 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
720 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
723 XUngrabServer(dpy);
725 #undef FRAMES
728 void
729 animateResize(WScreen *scr, int x, int y, int w, int h,
730 int fx, int fy, int fw, int fh, int hiding)
732 int style = wPreferences.iconification_style; /* Catch the value */
733 int steps, k;
735 if (style == WIS_NONE)
736 return;
738 if (style == WIS_RANDOM) {
739 style = rand()%3;
742 k = (hiding ? 2 : 3);
743 switch(style) {
744 case WIS_TWIST:
745 steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
746 if (steps>0)
747 animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
748 break;
749 case WIS_FLIP:
750 steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
751 if (steps>0)
752 animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
753 break;
754 case WIS_ZOOM:
755 default:
756 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
757 if (steps>0)
758 animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
759 break;
762 #endif /* ANIMATIONS */
765 static void
766 flushExpose()
768 XEvent tmpev;
770 while (XCheckTypedEvent(dpy, Expose, &tmpev))
771 WMHandleEvent(&tmpev);
772 XSync(dpy, 0);
775 static void
776 unmapTransientsFor(WWindow *wwin)
778 WWindow *tmp;
781 tmp = wwin->screen_ptr->focused_window;
782 while (tmp) {
783 /* unmap the transients for this transient */
784 if (tmp!=wwin && tmp->transient_for == wwin->client_win
785 && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
786 || tmp->flags.shaded)) {
787 unmapTransientsFor(tmp);
788 tmp->flags.miniaturized = 1;
789 if (!tmp->flags.shaded) {
790 wWindowUnmap(tmp);
791 } else {
792 XUnmapWindow(dpy, tmp->frame->core->window);
795 if (!tmp->flags.shaded)
797 wClientSetState(tmp, IconicState, None);
799 WMPostNotificationName(WMNChangedState, tmp, "iconify-transient");
801 tmp = tmp->prev;
806 static void
807 mapTransientsFor(WWindow *wwin)
809 WWindow *tmp;
811 tmp = wwin->screen_ptr->focused_window;
812 while (tmp) {
813 /* recursively map the transients for this transient */
814 if (tmp!=wwin && tmp->transient_for == wwin->client_win
815 && /*!tmp->flags.mapped*/ tmp->flags.miniaturized
816 && tmp->icon==NULL) {
817 mapTransientsFor(tmp);
818 tmp->flags.miniaturized = 0;
819 if (!tmp->flags.shaded) {
820 wWindowMap(tmp);
821 } else {
822 XMapWindow(dpy, tmp->frame->core->window);
824 tmp->flags.semi_focused = 0;
826 if (!tmp->flags.shaded)
828 wClientSetState(tmp, NormalState, None);
830 WMPostNotificationName(WMNChangedState, tmp, "iconify-transient");
832 tmp = tmp->prev;
836 #if 0
837 static void
838 setupIconGrabs(WIcon *icon)
840 /* setup passive grabs on the icon */
841 XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
842 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
843 XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
844 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
845 XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
846 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
847 XSync(dpy, 0);
849 #endif
851 static WWindow*
852 recursiveTransientFor(WWindow *wwin)
854 int i;
856 if (!wwin)
857 return None;
859 /* hackish way to detect transient_for cycle */
860 i = wwin->screen_ptr->window_count+1;
862 while (wwin && wwin->transient_for != None && i>0) {
863 wwin = wWindowFor(wwin->transient_for);
864 i--;
866 if (i==0 && wwin) {
867 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
868 wwin->frame->title);
869 return NULL;
872 return wwin;
875 #if 0
876 static void
877 removeIconGrabs(WIcon *icon)
879 /* remove passive grabs on the icon */
880 XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
881 XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
882 XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);
883 XSync(dpy, 0);
885 #endif
888 void
889 wIconifyWindow(WWindow *wwin)
891 XWindowAttributes attribs;
892 int present;
895 if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
896 /* the window doesn't exist anymore */
897 return;
900 if (wwin->flags.miniaturized) {
901 return;
904 if (wwin->transient_for!=None &&
905 wwin->transient_for!=wwin->screen_ptr->root_win) {
906 WWindow *owner = wWindowFor(wwin->transient_for);
908 if (owner && owner->flags.miniaturized)
909 return;
912 present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
914 /* if the window is in another workspace, simplify process */
915 if (present) {
916 /* icon creation may take a while */
917 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
918 ButtonMotionMask|ButtonReleaseMask, GrabModeAsync,
919 GrabModeAsync, None, None, CurrentTime);
922 if (!wPreferences.disable_miniwindows) {
923 if (!wwin->flags.icon_moved) {
924 PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y);
926 wwin->icon = wIconCreate(wwin);
928 wwin->icon->mapped = 1;
931 wwin->flags.miniaturized = 1;
932 wwin->flags.mapped = 0;
934 /* unmap transients */
936 unmapTransientsFor(wwin);
938 if (present) {
939 wSoundPlay(WSOUND_ICONIFY);
941 XUngrabPointer(dpy, CurrentTime);
942 wWindowUnmap(wwin);
943 /* let all Expose events arrive so that we can repaint
944 * something before the animation starts (and the server is grabbed) */
945 XSync(dpy, 0);
947 if (wPreferences.disable_miniwindows)
948 wClientSetState(wwin, IconicState, None);
949 else
950 wClientSetState(wwin, IconicState, wwin->icon->icon_win);
952 flushExpose();
953 #ifdef ANIMATIONS
954 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
955 && !wPreferences.no_animations) {
956 int ix, iy, iw, ih;
958 if (!wPreferences.disable_miniwindows) {
959 ix = wwin->icon_x;
960 iy = wwin->icon_y;
961 iw = wwin->icon->core->width;
962 ih = wwin->icon->core->height;
963 } else {
964 #ifdef KWM_HINTS
965 WArea area;
967 if (wKWMGetIconGeometry(wwin, &area)) {
968 ix = area.x1;
969 iy = area.y1;
970 iw = area.x2 - ix;
971 ih = area.y2 - iy;
972 } else
973 #endif /* KWM_HINTS */
975 ix = 0;
976 iy = 0;
977 iw = wwin->screen_ptr->scr_width;
978 ih = wwin->screen_ptr->scr_height;
981 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
982 wwin->frame->core->width, wwin->frame->core->height,
983 ix, iy, iw, ih, False);
985 #endif
988 wwin->flags.skip_next_animation = 0;
990 if (!wPreferences.disable_miniwindows) {
992 if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
993 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)
995 XMapWindow(dpy, wwin->icon->core->window);
997 AddToStackList(wwin->icon->core);
999 wLowerFrame(wwin->icon->core);
1002 if (present) {
1003 WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
1006 * It doesn't seem to be working and causes button event hangup
1007 * when deiconifying a transient window.
1008 setupIconGrabs(wwin->icon);
1010 if ((wwin->flags.focused
1011 || (owner && wwin->client_win == owner->client_win))
1012 && wPreferences.focus_mode==WKF_CLICK) {
1013 WWindow *tmp;
1015 tmp = wwin->prev;
1016 while (tmp) {
1017 if (!WFLAGP(tmp, no_focusable)
1018 && !(tmp->flags.hidden||tmp->flags.miniaturized)
1019 && (wwin->frame->workspace == tmp->frame->workspace))
1020 break;
1021 tmp = tmp->prev;
1023 wSetFocusTo(wwin->screen_ptr, tmp);
1024 } else if (wPreferences.focus_mode!=WKF_CLICK) {
1025 wSetFocusTo(wwin->screen_ptr, NULL);
1028 #ifdef ANIMATIONS
1029 if (!wwin->screen_ptr->flags.startup) {
1030 Window clientwin = wwin->client_win;
1032 XSync(dpy, 0);
1033 processEvents(XPending(dpy));
1035 /* the window can disappear while doing the processEvents() */
1036 if (!wWindowFor(clientwin))
1037 return;
1039 #endif
1043 if (wwin->flags.selected && !wPreferences.disable_miniwindows)
1044 wIconSelect(wwin->icon);
1046 WMPostNotificationName(WMNChangedState, wwin, "iconify");
1052 void
1053 wDeiconifyWindow(WWindow *wwin)
1055 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1057 if (!wwin->flags.miniaturized)
1058 return;
1060 if (wwin->transient_for != None
1061 && wwin->transient_for != wwin->screen_ptr->root_win) {
1062 WWindow *owner = recursiveTransientFor(wwin);
1064 if (owner && owner->flags.miniaturized) {
1065 wDeiconifyWindow(owner);
1066 wSetFocusTo(wwin->screen_ptr, wwin);
1067 wRaiseFrame(wwin->frame->core);
1068 return;
1072 wwin->flags.miniaturized = 0;
1073 if (!wwin->flags.shaded)
1074 wwin->flags.mapped = 1;
1076 if (!wPreferences.disable_miniwindows) {
1077 if (wwin->icon->selected)
1078 wIconSelect(wwin->icon);
1080 XUnmapWindow(dpy, wwin->icon->core->window);
1083 wSoundPlay(WSOUND_DEICONIFY);
1085 /* if the window is in another workspace, do it silently */
1086 #ifdef ANIMATIONS
1087 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1088 && !wwin->flags.skip_next_animation) {
1089 int ix, iy, iw, ih;
1091 if (!wPreferences.disable_miniwindows) {
1092 ix = wwin->icon_x;
1093 iy = wwin->icon_y;
1094 iw = wwin->icon->core->width;
1095 ih = wwin->icon->core->height;
1096 } else {
1097 #ifdef KWM_HINTS
1098 WArea area;
1100 if (wKWMGetIconGeometry(wwin, &area)) {
1101 ix = area.x1;
1102 iy = area.y1;
1103 iw = area.x2 - ix;
1104 ih = area.y2 - iy;
1105 } else
1106 #endif /* KWM_HINTS */
1108 ix = 0;
1109 iy = 0;
1110 iw = wwin->screen_ptr->scr_width;
1111 ih = wwin->screen_ptr->scr_height;
1114 animateResize(wwin->screen_ptr, ix, iy, iw, ih,
1115 wwin->frame_x, wwin->frame_y,
1116 wwin->frame->core->width, wwin->frame->core->height,
1117 False);
1119 #endif /* ANIMATIONS */
1120 wwin->flags.skip_next_animation = 0;
1121 XGrabServer(dpy);
1122 if (!wwin->flags.shaded) {
1123 XMapWindow(dpy, wwin->client_win);
1125 XMapWindow(dpy, wwin->frame->core->window);
1126 wRaiseFrame(wwin->frame->core);
1127 if (!wwin->flags.shaded) {
1128 wClientSetState(wwin, NormalState, None);
1130 mapTransientsFor(wwin);
1132 if (!wPreferences.disable_miniwindows) {
1133 RemoveFromStackList(wwin->icon->core);
1134 /* removeIconGrabs(wwin->icon);*/
1135 wIconDestroy(wwin->icon);
1136 wwin->icon = NULL;
1138 XUngrabServer(dpy);
1140 if (wPreferences.focus_mode==WKF_CLICK)
1141 wSetFocusTo(wwin->screen_ptr, wwin);
1143 #ifdef ANIMATIONS
1144 if (!wwin->screen_ptr->flags.startup) {
1145 Window clientwin = wwin->client_win;
1147 XSync(dpy, 0);
1148 processEvents(XPending(dpy));
1150 if (!wWindowFor(clientwin))
1151 return;
1153 #endif
1155 if (wPreferences.auto_arrange_icons) {
1156 wArrangeIcons(wwin->screen_ptr, True);
1159 WMPostNotificationName(WMNChangedState, wwin, "iconify");
1161 /* In case we were shaded and iconified, also unshade */
1162 wUnshadeWindow(wwin);
1167 static void
1168 hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
1170 if (wwin->flags.miniaturized) {
1171 if (wwin->icon) {
1172 XUnmapWindow(dpy, wwin->icon->core->window);
1173 wwin->icon->mapped = 0;
1175 wwin->flags.hidden = 1;
1177 WMPostNotificationName(WMNChangedState, wwin, "hide");
1178 return;
1181 if (wwin->flags.inspector_open) {
1182 wHideInspectorForWindow(wwin);
1185 wwin->flags.hidden = 1;
1186 wWindowUnmap(wwin);
1188 wClientSetState(wwin, IconicState, icon->icon_win);
1189 flushExpose();
1190 wSoundPlay(WSOUND_HIDE);
1191 #ifdef ANIMATIONS
1192 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1193 !wwin->flags.skip_next_animation && animate) {
1194 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1195 wwin->frame->core->width, wwin->frame->core->height,
1196 icon_x, icon_y, icon->core->width, icon->core->height,
1197 True);
1199 #endif
1200 wwin->flags.skip_next_animation = 0;
1202 WMPostNotificationName(WMNChangedState, wwin, "hide");
1207 void
1208 wHideOtherApplications(WWindow *awin)
1210 WWindow *wwin;
1211 WApplication *tapp;
1213 if (!awin)
1214 return;
1215 wwin = awin->screen_ptr->focused_window;
1218 while (wwin) {
1219 if (wwin!=awin
1220 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1221 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1222 && !wwin->flags.internal_window
1223 && wGetWindowOfInspectorForWindow(wwin) != awin
1224 && !WFLAGP(wwin, no_hide_others)) {
1226 if (wwin->main_window==None || WFLAGP(wwin, no_appicon)) {
1227 if (!WFLAGP(wwin, no_miniaturizable)) {
1228 wwin->flags.skip_next_animation = 1;
1229 wIconifyWindow(wwin);
1231 } else if (wwin->main_window!=None
1232 && awin->main_window != wwin->main_window) {
1233 tapp = wApplicationOf(wwin->main_window);
1234 if (tapp) {
1235 tapp->flags.skip_next_animation = 1;
1236 wHideApplication(tapp);
1237 } else {
1238 if (!WFLAGP(wwin, no_miniaturizable)) {
1239 wwin->flags.skip_next_animation = 1;
1240 wIconifyWindow(wwin);
1245 wwin = wwin->prev;
1248 wSetFocusTo(awin->screen_ptr, awin);
1254 void
1255 wHideApplication(WApplication *wapp)
1257 WScreen *scr;
1258 WWindow *wlist;
1259 int hadfocus;
1261 if (!wapp) {
1262 wwarning("trying to hide a non grouped window");
1263 return;
1265 if (!wapp->main_window_desc) {
1266 wwarning("group leader not found for window group");
1267 return;
1269 scr = wapp->main_window_desc->screen_ptr;
1270 hadfocus = 0;
1271 wlist = scr->focused_window;
1272 if (!wlist)
1273 return;
1275 if (wlist->main_window == wapp->main_window)
1276 wapp->last_focused = wlist;
1277 else
1278 wapp->last_focused = NULL;
1279 while (wlist) {
1280 if (wlist->main_window == wapp->main_window) {
1281 if (wlist->flags.focused) {
1282 hadfocus = 1;
1284 if (wapp->app_icon)
1285 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1286 wapp->app_icon->y_pos, wlist,
1287 !wapp->flags.skip_next_animation);
1289 wlist = wlist->prev;
1292 wapp->flags.skip_next_animation = 0;
1294 if (hadfocus) {
1295 if (wPreferences.focus_mode==WKF_CLICK) {
1296 wlist = scr->focused_window;
1297 while (wlist) {
1298 if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden
1299 && (wlist->flags.mapped || wlist->flags.shaded))
1300 break;
1301 wlist = wlist->prev;
1303 wSetFocusTo(scr, wlist);
1304 } else {
1305 wSetFocusTo(scr, NULL);
1309 wapp->flags.hidden = 1;
1311 if(wPreferences.auto_arrange_icons) {
1312 wArrangeIcons(scr, True);
1314 #ifdef HIDDENDOT
1315 if (wapp->app_icon)
1316 wAppIconPaint(wapp->app_icon);
1317 #endif
1323 static void
1324 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1325 int bringToCurrentWS)
1327 if (bringToCurrentWS)
1328 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1330 wwin->flags.hidden=0;
1332 wSoundPlay(WSOUND_UNHIDE);
1333 #ifdef ANIMATIONS
1334 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1335 && animate) {
1336 animateResize(wwin->screen_ptr, icon_x, icon_y,
1337 icon->core->width, icon->core->height,
1338 wwin->frame_x, wwin->frame_y,
1339 wwin->frame->core->width, wwin->frame->core->height,
1340 True);
1342 #endif
1343 wwin->flags.skip_next_animation = 0;
1344 if (wwin->screen_ptr->current_workspace == wwin->frame->workspace) {
1345 XMapWindow(dpy, wwin->client_win);
1346 XMapWindow(dpy, wwin->frame->core->window);
1347 wClientSetState(wwin, NormalState, None);
1348 wwin->flags.mapped=1;
1349 wRaiseFrame(wwin->frame->core);
1351 if (wwin->flags.inspector_open) {
1352 wUnhideInspectorForWindow(wwin);
1355 WMPostNotificationName(WMNChangedState, wwin, "hide");
1359 void
1360 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1362 WScreen *scr;
1363 WWindow *wlist, *next;
1364 WWindow *focused=NULL;
1366 if (!wapp) {
1367 return;
1369 scr = wapp->main_window_desc->screen_ptr;
1370 wlist = scr->focused_window;
1371 if (!wlist) return;
1372 /* goto beginning of list */
1373 while (wlist->prev)
1374 wlist = wlist->prev;
1376 while (wlist) {
1377 next = wlist->next;
1379 if (wlist->main_window == wapp->main_window) {
1380 if (wlist->flags.focused)
1381 focused = wlist;
1382 else if (!focused || !focused->flags.focused)
1383 focused = wlist;
1385 if (wlist->flags.miniaturized && wlist->icon) {
1386 if (bringToCurrentWS || wPreferences.sticky_icons
1387 || wlist->frame->workspace == scr->current_workspace) {
1388 if (!wlist->icon->mapped) {
1389 XMapWindow(dpy, wlist->icon->core->window);
1390 wlist->icon->mapped = 1;
1392 wlist->flags.hidden = 0;
1394 WMPostNotificationName(WMNChangedState, wlist, "hide");
1396 if (wlist->frame->workspace != scr->current_workspace)
1397 wWindowChangeWorkspace(wlist, scr->current_workspace);
1399 if (miniwindows) {
1400 wDeiconifyWindow(wlist);
1402 } else if (wlist->flags.hidden) {
1403 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1404 wapp->app_icon->y_pos, wlist,
1405 !wapp->flags.skip_next_animation,
1406 bringToCurrentWS);
1407 } else {
1408 if (bringToCurrentWS
1409 && wlist->frame->workspace != scr->current_workspace) {
1410 wWindowChangeWorkspace(wlist, scr->current_workspace);
1412 wRaiseFrame(wlist->frame->core);
1415 wlist = next;
1418 wapp->flags.skip_next_animation = 0;
1419 wapp->flags.hidden = 0;
1421 if (focused)
1422 wSetFocusTo(scr, focused);
1423 else if (wapp->last_focused && wapp->last_focused->flags.mapped)
1424 wSetFocusTo(scr, wapp->last_focused);
1425 wapp->last_focused = NULL;
1426 if (wPreferences.auto_arrange_icons) {
1427 wArrangeIcons(scr, True);
1429 #ifdef HIDDENDOT
1430 wAppIconPaint(wapp->app_icon);
1431 #endif
1436 void
1437 wShowAllWindows(WScreen *scr)
1439 WWindow *wwin, *old_foc;
1440 WApplication *wapp;
1442 old_foc = wwin = scr->focused_window;
1443 while (wwin) {
1444 if (!wwin->flags.internal_window &&
1445 (scr->current_workspace == wwin->frame->workspace
1446 || IS_OMNIPRESENT(wwin))) {
1447 if (wwin->flags.miniaturized) {
1448 wwin->flags.skip_next_animation = 1;
1449 wDeiconifyWindow(wwin);
1450 } else if (wwin->flags.hidden) {
1451 wapp = wApplicationOf(wwin->main_window);
1452 if (wapp) {
1453 wUnhideApplication(wapp, False, False);
1454 } else {
1455 wwin->flags.skip_next_animation = 1;
1456 wDeiconifyWindow(wwin);
1460 wwin = wwin->prev;
1462 wSetFocusTo(scr, old_foc);
1463 /*wRaiseFrame(old_foc->frame->core);*/
1467 void
1468 wRefreshDesktop(WScreen *scr)
1470 Window win;
1471 XSetWindowAttributes attr;
1473 attr.backing_store = NotUseful;
1474 attr.save_under = False;
1475 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1476 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1477 (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
1478 &attr);
1479 XMapRaised(dpy, win);
1480 XDestroyWindow(dpy, win);
1481 XFlush(dpy);
1485 void
1486 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1488 WWindow *wwin;
1489 WAppIcon *aicon;
1490 int pf; /* primary axis */
1491 int sf; /* secondary axis */
1492 int fullW;
1493 int fullH;
1494 int pi, si;
1495 int sx1, sx2, sy1, sy2; /* screen boundary */
1496 int sw, sh;
1497 int xo, yo;
1498 int xs, ys;
1499 int isize = wPreferences.icon_size;
1502 * Find out screen boundaries.
1504 sx1 = 0;
1505 sy1 = 0;
1506 sx2 = scr->scr_width;
1507 sy2 = scr->scr_height;
1508 if (scr->dock) {
1509 if (scr->dock->on_right_side)
1510 sx2 -= isize + DOCK_EXTRA_SPACE;
1511 else
1512 sx1 += isize + DOCK_EXTRA_SPACE;
1515 sw = isize * (scr->scr_width/isize);
1516 sh = isize * (scr->scr_height/isize);
1517 fullW = (sx2-sx1)/isize;
1518 fullH = (sy2-sy1)/isize;
1520 /* icon yard boundaries */
1521 if (wPreferences.icon_yard & IY_VERT) {
1522 pf = fullH;
1523 sf = fullW;
1524 } else {
1525 pf = fullW;
1526 sf = fullH;
1528 if (wPreferences.icon_yard & IY_RIGHT) {
1529 xo = sx2 - isize;
1530 xs = -1;
1531 } else {
1532 xo = sx1;
1533 xs = 1;
1535 if (wPreferences.icon_yard & IY_TOP) {
1536 yo = sy1;
1537 ys = 1;
1538 } else {
1539 yo = sy2 - isize;
1540 ys = -1;
1543 /* arrange icons putting the most recently focused window
1544 * as the last icon */
1545 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1546 : xo + xs*(pi*isize))
1547 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1548 : yo + ys*(si*isize))
1550 /* arrange application icons */
1551 aicon = scr->app_icon_list;
1552 /* reverse them to avoid unnecessarily sliding of icons */
1553 while (aicon && aicon->next)
1554 aicon = aicon->next;
1556 pi = 0;
1557 si = 0;
1558 while (aicon) {
1559 if (!aicon->docked) {
1560 if (aicon->x_pos != X || aicon->y_pos != Y) {
1561 #ifdef ANIMATIONS
1562 if (!wPreferences.no_animations) {
1563 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1564 X, Y);
1566 #endif /* ANIMATIONS */
1568 wAppIconMove(aicon, X, Y);
1569 pi++;
1571 /* we reversed the order so we use prev */
1572 aicon = aicon->prev;
1573 if (pi >= pf) {
1574 pi=0;
1575 si++;
1579 /* arrange miniwindows */
1581 wwin = scr->focused_window;
1582 /* reverse them to avoid unnecessarily shuffling */
1583 while (wwin && wwin->prev)
1584 wwin = wwin->prev;
1586 while (wwin) {
1587 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1588 (wwin->frame->workspace==scr->current_workspace ||
1589 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1591 if (arrangeAll || !wwin->flags.icon_moved) {
1592 if (wwin->icon_x != X || wwin->icon_y != Y) {
1593 #ifdef ANIMATIONS
1594 if (wPreferences.no_animations) {
1595 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1596 } else {
1597 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1598 wwin->icon_y, X, Y);
1600 #else
1601 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1602 #endif /* ANIMATIONS */
1604 wwin->icon_x = X;
1605 wwin->icon_y = Y;
1606 pi++;
1609 if (arrangeAll) {
1610 wwin->flags.icon_moved = 0;
1612 /* we reversed the order, so we use next */
1613 wwin = wwin->next;
1614 if (pi >= pf) {
1615 pi=0;
1616 si++;
1622 void
1623 wSelectWindow(WWindow *wwin, Bool flag)
1625 WScreen *scr = wwin->screen_ptr;
1627 if (flag) {
1628 wwin->flags.selected = 1;
1629 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1631 if (WFLAGP(wwin, no_border)) {
1632 XSetWindowBorderWidth(dpy, wwin->frame->core->window,
1633 FRAME_BORDER_WIDTH);
1636 if (!scr->selected_windows)
1637 scr->selected_windows = WMCreateArray(4);
1638 WMAddToArray(scr->selected_windows, wwin);
1639 } else {
1640 wwin->flags.selected = 0;
1641 XSetWindowBorder(dpy, wwin->frame->core->window,
1642 scr->frame_border_pixel);
1644 if (WFLAGP(wwin, no_border)) {
1645 XSetWindowBorderWidth(dpy, wwin->frame->core->window, 0);
1648 if (scr->selected_windows) {
1649 WMRemoveFromArray(scr->selected_windows, wwin);
1655 void
1656 wMakeWindowVisible(WWindow *wwin)
1658 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
1659 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1661 if (wwin->flags.shaded) {
1662 wUnshadeWindow(wwin);
1664 if (wwin->flags.hidden) {
1665 WApplication *app;
1667 app = wApplicationOf(wwin->main_window);
1668 if (app)
1669 wUnhideApplication(app, False, False);
1670 } else if (wwin->flags.miniaturized) {
1671 wDeiconifyWindow(wwin);
1672 } else {
1673 if (!WFLAGP(wwin, no_focusable))
1674 wSetFocusTo(wwin->screen_ptr, wwin);
1675 wRaiseFrame(wwin->frame->core);