fixed crash bug with WM_CLASS==NULL
[wmaker-crm.git] / src / actions.c
blobc6120ef222aadaba8480417684f5c7610746eae0
1 /* action.c- misc. window commands (miniaturize, hide etc.)
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997, 1998, 1999 Alfredo K. Kojima
6 * Copyright (c) 1998 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_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;
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
170 #ifdef KWM_HINTS
171 wKWMUpdateActiveWindowHint(scr);
172 wKWMSendEventMessage(NULL, WKWMFocusWindow);
173 #endif
174 return;
175 } else if (old_scr != scr && old_focused) {
176 wWindowUnfocus(old_focused);
179 wasfocused = wwin->flags.focused;
180 napp = wApplicationOf(wwin->main_window);
182 /* remember last workspace where the app has been */
183 if (napp)
184 napp->last_workspace = wwin->screen_ptr->current_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
251 #ifdef KWM_HINTS
252 wKWMUpdateActiveWindowHint(scr);
253 wKWMSendEventMessage(wwin, WKWMFocusWindow);
254 #endif
255 XFlush(dpy);
256 old_scr=scr;
260 void
261 wShadeWindow(WWindow *wwin)
263 time_t time0 = time(NULL);
264 #ifdef ANIMATIONS
265 int y, s, w, h;
266 #endif
268 if (wwin->flags.shaded)
269 return;
271 XLowerWindow(dpy, wwin->client_win);
273 wSoundPlay(WSOUND_SHADE);
275 #ifdef ANIMATIONS
276 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
277 && !wPreferences.no_animations) {
278 /* do the shading animation */
279 h = wwin->frame->core->height;
280 s = h/SHADE_STEPS;
281 if (s < 1) s=1;
282 w = wwin->frame->core->width;
283 y = wwin->frame->top_width;
284 while (h>wwin->frame->top_width+1) {
285 XMoveWindow(dpy, wwin->client_win, 0, y);
286 XResizeWindow(dpy, wwin->frame->core->window, w, h);
287 XFlush(dpy);
289 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
290 break;
292 if (SHADE_DELAY > 0)
293 wusleep(SHADE_DELAY*1000L);
294 h-=s;
295 y-=s;
297 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
299 #endif /* ANIMATIONS */
301 wwin->flags.skip_next_animation = 0;
302 wwin->flags.shaded = 1;
303 wwin->flags.mapped = 0;
304 /* prevent window withdrawal when getting UnmapNotify */
305 XSelectInput(dpy, wwin->client_win,
306 wwin->event_mask & ~StructureNotifyMask);
307 XUnmapWindow(dpy, wwin->client_win);
308 XSelectInput(dpy, wwin->client_win, wwin->event_mask);
310 /* for the client it's just like iconification */
311 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
312 wwin->frame->top_width - 1);
314 wwin->client.y = wwin->frame_y - wwin->client.height
315 + wwin->frame->top_width;
316 wWindowSynthConfigureNotify(wwin);
319 wClientSetState(wwin, IconicState, None);
322 #ifdef GNOME_STUFF
323 wGNOMEUpdateClientStateHint(wwin, False);
324 #endif
325 #ifdef KWM_HINTS
326 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
327 wKWMSendEventMessage(wwin, WKWMChangedClient);
328 #endif
329 /* update window list to reflect shaded state */
330 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
332 #ifdef ANIMATIONS
333 if (!wwin->screen_ptr->flags.startup) {
334 /* Look at processEvents() for reason of this code. */
335 XSync(dpy, 0);
336 processEvents(XPending(dpy));
338 #endif
342 void
343 wUnshadeWindow(WWindow *wwin)
345 time_t time0 = time(NULL);
346 #ifdef ANIMATIONS
347 int y, s, w, h;
348 #endif /* ANIMATIONS */
351 if (!wwin->flags.shaded)
352 return;
354 wwin->flags.shaded = 0;
355 wwin->flags.mapped = 1;
356 XMapWindow(dpy, wwin->client_win);
358 wSoundPlay(WSOUND_UNSHADE);
360 #ifdef ANIMATIONS
361 if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) {
362 /* do the shading animation */
363 h = wwin->frame->top_width + wwin->frame->bottom_width;
364 y = wwin->frame->top_width - wwin->client.height;
365 s = abs(y)/SHADE_STEPS;
366 if (s<1) s=1;
367 w = wwin->frame->core->width;
368 XMoveWindow(dpy, wwin->client_win, 0, y);
369 if (s>0) {
370 while (h < wwin->client.height + wwin->frame->top_width
371 + wwin->frame->bottom_width) {
372 XResizeWindow(dpy, wwin->frame->core->window, w, h);
373 XMoveWindow(dpy, wwin->client_win, 0, y);
374 XFlush(dpy);
375 if (SHADE_DELAY > 0)
376 wusleep(SHADE_DELAY*2000L/3);
377 h+=s;
378 y+=s;
380 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
381 break;
384 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
386 #endif /* ANIMATIONS */
388 wwin->flags.skip_next_animation = 0;
389 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
390 wwin->frame->top_width + wwin->client.height
391 + wwin->frame->bottom_width);
393 wwin->client.y = wwin->frame_y + wwin->frame->top_width;
394 wWindowSynthConfigureNotify(wwin);
397 wClientSetState(wwin, NormalState, None);
399 /* if the window is focused, set the focus again as it was disabled during
400 * shading */
401 if (wwin->flags.focused)
402 wSetFocusTo(wwin->screen_ptr, wwin);
404 #ifdef GNOME_STUFF
405 wGNOMEUpdateClientStateHint(wwin, False);
406 #endif
407 #ifdef KWM_HINTS
408 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
409 wKWMSendEventMessage(wwin, WKWMChangedClient);
410 #endif
412 /* update window list to reflect unshaded state */
413 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
418 void
419 wMaximizeWindow(WWindow *wwin, int directions)
421 int new_width, new_height, new_x, new_y;
422 WArea usableArea = wwin->screen_ptr->totalUsableArea;
423 WArea totalArea;
426 if (WFLAGP(wwin, no_resizable))
427 return;
429 totalArea.x1 = 0;
430 totalArea.y1 = 0;
431 totalArea.x2 = wwin->screen_ptr->scr_width;
432 totalArea.y2 = wwin->screen_ptr->scr_height;
434 #ifdef XINERAMA
435 if (wwin->screen_ptr->xine_count > 0
436 && !(directions & MAX_IGNORE_XINERAMA)) {
437 WScreen *scr = wwin->screen_ptr;
438 WMRect rect;
440 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
441 totalArea.x1 = rect.pos.x;
442 totalArea.y1 = rect.pos.y;
443 totalArea.x2 = totalArea.x1 + rect.size.width;
444 totalArea.y2 = totalArea.y1 + rect.size.height;
446 usableArea.x1 = WMAX(totalArea.x1, usableArea.x1);
447 usableArea.y1 = WMAX(totalArea.y1, usableArea.y1);
448 usableArea.x2 = WMIN(totalArea.x2, usableArea.x2);
449 usableArea.y2 = WMIN(totalArea.y2, usableArea.y2);
451 #endif /* XINERAMA */
453 if (WFLAGP(wwin, full_maximize)) {
454 usableArea = totalArea;
457 if (wwin->flags.shaded) {
458 wwin->flags.skip_next_animation = 1;
459 wUnshadeWindow(wwin);
461 wwin->flags.maximized = directions;
462 wwin->old_geometry.width = wwin->client.width;
463 wwin->old_geometry.height = wwin->client.height;
464 wwin->old_geometry.x = wwin->frame_x;
465 wwin->old_geometry.y = wwin->frame_y;
467 #ifdef KWM_HINTS
468 wKWMUpdateClientGeometryRestore(wwin);
469 #endif
471 if (directions & MAX_HORIZONTAL) {
473 new_width = (usableArea.x2-usableArea.x1)-FRAME_BORDER_WIDTH*2;
474 new_x = usableArea.x1;
476 } else {
478 new_x = wwin->frame_x;
479 new_width = wwin->frame->core->width;
483 if (directions & MAX_VERTICAL) {
485 new_height = (usableArea.y2-usableArea.y1)-FRAME_BORDER_WIDTH*2;
486 new_y = usableArea.y1;
487 if (WFLAGP(wwin, full_maximize)) {
488 new_y -= wwin->frame->top_width;
489 new_height += wwin->frame->bottom_width - 1;
491 } else {
492 new_y = wwin->frame_y;
493 new_height = wwin->frame->core->height;
496 if (!WFLAGP(wwin, full_maximize)) {
497 new_height -= wwin->frame->top_width+wwin->frame->bottom_width;
500 wWindowConstrainSize(wwin, &new_width, &new_height);
502 wWindowCropSize(wwin, usableArea.x2-usableArea.x1,
503 usableArea.y2-usableArea.y1,
504 &new_width, &new_height);
506 wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
509 #ifdef GNOME_STUFF
510 wGNOMEUpdateClientStateHint(wwin, False);
511 #endif
512 #ifdef KWM_HINTS
513 wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
514 wKWMSendEventMessage(wwin, WKWMChangedClient);
515 #endif
517 wSoundPlay(WSOUND_MAXIMIZE);
521 void
522 wUnmaximizeWindow(WWindow *wwin)
524 int restore_x, restore_y;
526 if (!wwin->flags.maximized)
527 return;
529 if (wwin->flags.shaded) {
530 wwin->flags.skip_next_animation = 1;
531 wUnshadeWindow(wwin);
533 restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ?
534 wwin->old_geometry.x : wwin->frame_x;
535 restore_y = (wwin->flags.maximized & MAX_VERTICAL) ?
536 wwin->old_geometry.y : wwin->frame_y;
537 wwin->flags.maximized = 0;
538 wWindowConfigure(wwin, restore_x, restore_y,
539 wwin->old_geometry.width, wwin->old_geometry.height);
541 #ifdef GNOME_STUFF
542 wGNOMEUpdateClientStateHint(wwin, False);
543 #endif
544 #ifdef KWM_HINTS
545 wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
546 wKWMSendEventMessage(wwin, WKWMChangedClient);
547 #endif
549 wSoundPlay(WSOUND_UNMAXIMIZE);
552 #ifdef ANIMATIONS
553 static void
554 animateResizeFlip(WScreen *scr, int x, int y, int w, int h,
555 int fx, int fy, int fw, int fh, int steps)
557 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
558 float cx, cy, cw, ch;
559 float xstep, ystep, wstep, hstep;
560 XPoint points[5];
561 float dx, dch, midy;
562 float angle, final_angle, delta;
564 xstep = (float)(fx-x)/steps;
565 ystep = (float)(fy-y)/steps;
566 wstep = (float)(fw-w)/steps;
567 hstep = (float)(fh-h)/steps;
569 cx = (float)x;
570 cy = (float)y;
571 cw = (float)w;
572 ch = (float)h;
574 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F;
575 delta = (float)(final_angle/FRAMES);
576 for (angle=0;; angle+=delta) {
577 if (angle > final_angle)
578 angle = final_angle;
580 dx = (cw/10) - ((cw/5) * sin(angle));
581 dch = (ch/2) * cos(angle);
582 midy = cy + (ch/2);
584 points[0].x = cx + dx; points[0].y = midy - dch;
585 points[1].x = cx + cw - dx; points[1].y = points[0].y;
586 points[2].x = cx + cw + dx; points[2].y = midy + dch;
587 points[3].x = cx - dx; points[3].y = points[2].y;
588 points[4].x = points[0].x; points[4].y = points[0].y;
590 XGrabServer(dpy);
591 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
592 XFlush(dpy);
593 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
594 wusleep(MINIATURIZE_ANIMATION_DELAY_F);
595 #endif
597 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
598 XUngrabServer(dpy);
599 cx+=xstep;
600 cy+=ystep;
601 cw+=wstep;
602 ch+=hstep;
603 if (angle >= final_angle)
604 break;
607 XFlush(dpy);
609 #undef FRAMES
612 static void
613 animateResizeTwist(WScreen *scr, int x, int y, int w, int h,
614 int fx, int fy, int fw, int fh, int steps)
616 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
617 float cx, cy, cw, ch;
618 float xstep, ystep, wstep, hstep;
619 XPoint points[5];
620 float angle, final_angle, a, d, delta;
622 x += w/2;
623 y += h/2;
624 fx += fw/2;
625 fy += fh/2;
627 xstep = (float)(fx-x)/steps;
628 ystep = (float)(fy-y)/steps;
629 wstep = (float)(fw-w)/steps;
630 hstep = (float)(fh-h)/steps;
632 cx = (float)x;
633 cy = (float)y;
634 cw = (float)w;
635 ch = (float)h;
637 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T;
638 delta = (float)(final_angle/FRAMES);
639 for (angle=0;; angle+=delta) {
640 if (angle > final_angle)
641 angle = final_angle;
643 a = atan(ch/cw);
644 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
646 points[0].x = cx+cos(angle-a)*d;
647 points[0].y = cy+sin(angle-a)*d;
648 points[1].x = cx+cos(angle+a)*d;
649 points[1].y = cy+sin(angle+a)*d;
650 points[2].x = cx+cos(angle-a+WM_PI)*d;
651 points[2].y = cy+sin(angle-a+WM_PI)*d;
652 points[3].x = cx+cos(angle+a+WM_PI)*d;
653 points[3].y = cy+sin(angle+a+WM_PI)*d;
654 points[4].x = cx+cos(angle-a)*d;
655 points[4].y = cy+sin(angle-a)*d;
656 XGrabServer(dpy);
657 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
658 XFlush(dpy);
659 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
660 wusleep(MINIATURIZE_ANIMATION_DELAY_T);
661 #endif
663 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
664 XUngrabServer(dpy);
665 cx+=xstep;
666 cy+=ystep;
667 cw+=wstep;
668 ch+=hstep;
669 if (angle >= final_angle)
670 break;
673 XFlush(dpy);
675 #undef FRAMES
678 static void
679 animateResizeZoom(WScreen *scr, int x, int y, int w, int h,
680 int fx, int fy, int fw, int fh, int steps)
682 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
683 float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
684 float xstep, ystep, wstep, hstep;
685 int i, j;
687 xstep = (float)(fx-x)/steps;
688 ystep = (float)(fy-y)/steps;
689 wstep = (float)(fw-w)/steps;
690 hstep = (float)(fh-h)/steps;
692 for (j=0; j<FRAMES; j++) {
693 cx[j] = (float)x;
694 cy[j] = (float)y;
695 cw[j] = (float)w;
696 ch[j] = (float)h;
698 XGrabServer(dpy);
699 for (i=0; i<steps; i++) {
700 for (j=0; j<FRAMES; j++) {
701 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
702 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
704 XFlush(dpy);
705 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
706 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
707 #endif
708 for (j=0; j<FRAMES; j++) {
709 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
710 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
711 if (j<FRAMES-1) {
712 cx[j]=cx[j+1];
713 cy[j]=cy[j+1];
714 cw[j]=cw[j+1];
715 ch[j]=ch[j+1];
716 } else {
717 cx[j]+=xstep;
718 cy[j]+=ystep;
719 cw[j]+=wstep;
720 ch[j]+=hstep;
725 for (j=0; j<FRAMES; j++) {
726 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
727 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
729 XFlush(dpy);
730 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
731 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
732 #endif
733 for (j=0; j<FRAMES; j++) {
734 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
735 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
738 XUngrabServer(dpy);
740 #undef FRAMES
743 void
744 animateResize(WScreen *scr, int x, int y, int w, int h,
745 int fx, int fy, int fw, int fh, int hiding)
747 int style = wPreferences.iconification_style; /* Catch the value */
748 int steps, k;
750 if (style == WIS_NONE)
751 return;
753 if (style == WIS_RANDOM) {
754 style = rand()%3;
757 k = (hiding ? 2 : 3);
758 switch(style) {
759 case WIS_TWIST:
760 steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
761 if (steps>0)
762 animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
763 break;
764 case WIS_FLIP:
765 steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
766 if (steps>0)
767 animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
768 break;
769 case WIS_ZOOM:
770 default:
771 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
772 if (steps>0)
773 animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
774 break;
777 #endif /* ANIMATIONS */
780 static void
781 flushExpose()
783 XEvent tmpev;
785 while (XCheckTypedEvent(dpy, Expose, &tmpev))
786 WMHandleEvent(&tmpev);
787 XSync(dpy, 0);
790 static void
791 unmapTransientsFor(WWindow *wwin)
793 WWindow *tmp;
796 tmp = wwin->screen_ptr->focused_window;
797 while (tmp) {
798 /* unmap the transients for this transient */
799 if (tmp!=wwin && tmp->transient_for == wwin->client_win
800 && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
801 || tmp->flags.shaded)) {
802 unmapTransientsFor(tmp);
803 tmp->flags.miniaturized = 1;
804 if (!tmp->flags.shaded) {
805 wWindowUnmap(tmp);
806 } else {
807 XUnmapWindow(dpy, tmp->frame->core->window);
810 if (!tmp->flags.shaded)
812 wClientSetState(tmp, IconicState, None);
813 #ifdef KWM_HINTS
814 wKWMUpdateClientStateHint(tmp, KWMIconifiedFlag);
815 wKWMSendEventMessage(tmp, WKWMRemoveWindow);
816 tmp->flags.kwm_hidden_for_modules = 1;
817 #endif
819 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
822 tmp = tmp->prev;
827 static void
828 mapTransientsFor(WWindow *wwin)
830 WWindow *tmp;
832 tmp = wwin->screen_ptr->focused_window;
833 while (tmp) {
834 /* recursively map the transients for this transient */
835 if (tmp!=wwin && tmp->transient_for == wwin->client_win
836 && /*!tmp->flags.mapped*/ tmp->flags.miniaturized
837 && tmp->icon==NULL) {
838 mapTransientsFor(tmp);
839 tmp->flags.miniaturized = 0;
840 if (!tmp->flags.shaded) {
841 wWindowMap(tmp);
842 } else {
843 XMapWindow(dpy, tmp->frame->core->window);
845 tmp->flags.semi_focused = 0;
847 if (!tmp->flags.shaded)
849 wClientSetState(tmp, NormalState, None);
850 #ifdef KWM_HINTS
851 wKWMUpdateClientStateHint(tmp, KWMIconifiedFlag);
852 if (tmp->flags.kwm_hidden_for_modules) {
853 wKWMSendEventMessage(tmp, WKWMAddWindow);
854 tmp->flags.kwm_hidden_for_modules = 0;
856 #endif
858 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
861 tmp = tmp->prev;
865 #if 0
866 static void
867 setupIconGrabs(WIcon *icon)
869 /* setup passive grabs on the icon */
870 XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
871 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
872 XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
873 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
874 XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
875 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
876 XSync(dpy, 0);
878 #endif
880 static WWindow*
881 recursiveTransientFor(WWindow *wwin)
883 int i;
885 if (!wwin)
886 return None;
888 /* hackish way to detect transient_for cycle */
889 i = wwin->screen_ptr->window_count+1;
891 while (wwin && wwin->transient_for != None && i>0) {
892 wwin = wWindowFor(wwin->transient_for);
893 i--;
895 if (i==0 && wwin) {
896 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
897 wwin->frame->title);
898 return NULL;
901 return wwin;
904 #if 0
905 static void
906 removeIconGrabs(WIcon *icon)
908 /* remove passive grabs on the icon */
909 XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
910 XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
911 XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);
912 XSync(dpy, 0);
914 #endif
917 void
918 wIconifyWindow(WWindow *wwin)
920 XWindowAttributes attribs;
921 int present;
924 if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
925 /* the window doesn't exist anymore */
926 return;
929 if (wwin->flags.miniaturized) {
930 return;
934 if (wwin->transient_for!=None) {
935 WWindow *owner = wWindowFor(wwin->transient_for);
937 if (owner && owner->flags.miniaturized)
938 return;
941 present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
943 /* if the window is in another workspace, simplify process */
944 if (present) {
945 /* icon creation may take a while */
946 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
947 ButtonMotionMask|ButtonReleaseMask, GrabModeAsync,
948 GrabModeAsync, None, None, CurrentTime);
951 if (!wPreferences.disable_miniwindows) {
952 if (!wwin->flags.icon_moved) {
953 PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y);
955 wwin->icon = wIconCreate(wwin);
957 wwin->icon->mapped = 1;
960 wwin->flags.miniaturized = 1;
961 wwin->flags.mapped = 0;
963 /* unmap transients */
965 unmapTransientsFor(wwin);
967 if (present) {
968 wSoundPlay(WSOUND_ICONIFY);
970 XUngrabPointer(dpy, CurrentTime);
971 wWindowUnmap(wwin);
972 /* let all Expose events arrive so that we can repaint
973 * something before the animation starts (and the server is grabbed) */
974 XSync(dpy, 0);
976 if (wPreferences.disable_miniwindows)
977 wClientSetState(wwin, IconicState, None);
978 else
979 wClientSetState(wwin, IconicState, wwin->icon->icon_win);
981 flushExpose();
982 #ifdef ANIMATIONS
983 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
984 && !wPreferences.no_animations) {
985 int ix, iy, iw, ih;
987 if (!wPreferences.disable_miniwindows) {
988 ix = wwin->icon_x;
989 iy = wwin->icon_y;
990 iw = wwin->icon->core->width;
991 ih = wwin->icon->core->height;
992 } else {
993 #ifdef KWM_HINTS
994 WArea area;
996 if (wKWMGetIconGeometry(wwin, &area)) {
997 ix = area.x1;
998 iy = area.y1;
999 iw = area.x2 - ix;
1000 ih = area.y2 - iy;
1001 } else
1002 #endif /* KWM_HINTS */
1004 ix = 0;
1005 iy = 0;
1006 iw = wwin->screen_ptr->scr_width;
1007 ih = wwin->screen_ptr->scr_height;
1010 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1011 wwin->frame->core->width, wwin->frame->core->height,
1012 ix, iy, iw, ih, False);
1014 #endif
1017 wwin->flags.skip_next_animation = 0;
1019 if (!wPreferences.disable_miniwindows) {
1021 if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
1022 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)
1024 XMapWindow(dpy, wwin->icon->core->window);
1026 AddToStackList(wwin->icon->core);
1028 wLowerFrame(wwin->icon->core);
1031 if (present) {
1032 WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
1035 * It doesn't seem to be working and causes button event hangup
1036 * when deiconifying a transient window.
1037 setupIconGrabs(wwin->icon);
1039 if ((wwin->flags.focused
1040 || (owner && wwin->client_win == owner->client_win))
1041 && wPreferences.focus_mode==WKF_CLICK) {
1042 WWindow *tmp;
1044 tmp = wwin->prev;
1045 while (tmp) {
1046 if (!WFLAGP(tmp, no_focusable)
1047 && !(tmp->flags.hidden||tmp->flags.miniaturized)
1048 && (wwin->frame->workspace == tmp->frame->workspace))
1049 break;
1050 tmp = tmp->prev;
1052 wSetFocusTo(wwin->screen_ptr, tmp);
1053 } else if (wPreferences.focus_mode!=WKF_CLICK) {
1054 wSetFocusTo(wwin->screen_ptr, NULL);
1057 #ifdef ANIMATIONS
1058 if (!wwin->screen_ptr->flags.startup) {
1059 Window clientwin = wwin->client_win;
1061 XSync(dpy, 0);
1062 processEvents(XPending(dpy));
1064 /* the window can disappear while doing the processEvents() */
1065 if (!wWindowFor(clientwin))
1066 return;
1068 #endif
1072 if (wwin->flags.selected && !wPreferences.disable_miniwindows)
1073 wIconSelect(wwin->icon);
1075 #ifdef GNOME_STUFF
1076 wGNOMEUpdateClientStateHint(wwin, False);
1077 #endif
1078 #ifdef KWM_HINTS
1079 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1080 wKWMSendEventMessage(wwin, WKWMChangedClient);
1081 #endif
1083 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1089 void
1090 wDeiconifyWindow(WWindow *wwin)
1092 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1094 if (!wwin->flags.miniaturized)
1095 return;
1097 if (wwin->transient_for != None
1098 && wwin->transient_for != wwin->screen_ptr->root_win) {
1099 WWindow *owner = recursiveTransientFor(wwin);
1101 if (owner && owner->flags.miniaturized) {
1102 wDeiconifyWindow(owner);
1103 wSetFocusTo(wwin->screen_ptr, wwin);
1104 wRaiseFrame(wwin->frame->core);
1105 return;
1109 wwin->flags.miniaturized = 0;
1110 if (!wwin->flags.shaded)
1111 wwin->flags.mapped = 1;
1113 if (!wPreferences.disable_miniwindows) {
1114 if (wwin->icon->selected)
1115 wIconSelect(wwin->icon);
1117 XUnmapWindow(dpy, wwin->icon->core->window);
1120 wSoundPlay(WSOUND_DEICONIFY);
1122 /* if the window is in another workspace, do it silently */
1123 #ifdef ANIMATIONS
1124 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1125 && !wwin->flags.skip_next_animation) {
1126 int ix, iy, iw, ih;
1128 if (!wPreferences.disable_miniwindows) {
1129 ix = wwin->icon_x;
1130 iy = wwin->icon_y;
1131 iw = wwin->icon->core->width;
1132 ih = wwin->icon->core->height;
1133 } else {
1134 #ifdef KWM_HINTS
1135 WArea area;
1137 if (wKWMGetIconGeometry(wwin, &area)) {
1138 ix = area.x1;
1139 iy = area.y1;
1140 iw = area.x2 - ix;
1141 ih = area.y2 - iy;
1142 } else
1143 #endif /* KWM_HINTS */
1145 ix = 0;
1146 iy = 0;
1147 iw = wwin->screen_ptr->scr_width;
1148 ih = wwin->screen_ptr->scr_height;
1151 animateResize(wwin->screen_ptr, ix, iy, iw, ih,
1152 wwin->frame_x, wwin->frame_y,
1153 wwin->frame->core->width, wwin->frame->core->height,
1154 False);
1156 #endif /* ANIMATIONS */
1157 wwin->flags.skip_next_animation = 0;
1158 XGrabServer(dpy);
1159 if (!wwin->flags.shaded) {
1160 XMapWindow(dpy, wwin->client_win);
1162 XMapWindow(dpy, wwin->frame->core->window);
1163 wRaiseFrame(wwin->frame->core);
1164 if (!wwin->flags.shaded) {
1165 wClientSetState(wwin, NormalState, None);
1167 mapTransientsFor(wwin);
1169 if (!wPreferences.disable_miniwindows) {
1170 RemoveFromStackList(wwin->icon->core);
1171 /* removeIconGrabs(wwin->icon);*/
1172 wIconDestroy(wwin->icon);
1173 wwin->icon = NULL;
1175 XUngrabServer(dpy);
1177 if (wPreferences.focus_mode==WKF_CLICK)
1178 wSetFocusTo(wwin->screen_ptr, wwin);
1180 #ifdef ANIMATIONS
1181 if (!wwin->screen_ptr->flags.startup) {
1182 Window clientwin = wwin->client_win;
1184 XSync(dpy, 0);
1185 processEvents(XPending(dpy));
1187 if (!wWindowFor(clientwin))
1188 return;
1190 #endif
1192 if (wPreferences.auto_arrange_icons) {
1193 wArrangeIcons(wwin->screen_ptr, True);
1196 #ifdef GNOME_STUFF
1197 wGNOMEUpdateClientStateHint(wwin, False);
1198 #endif
1199 #ifdef KWM_HINTS
1200 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1201 wKWMSendEventMessage(wwin, WKWMChangedClient);
1202 #endif
1204 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1209 static void
1210 hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
1212 if (wwin->flags.miniaturized) {
1213 if (wwin->icon) {
1214 XUnmapWindow(dpy, wwin->icon->core->window);
1215 wwin->icon->mapped = 0;
1217 wwin->flags.hidden = 1;
1218 #ifdef GNOME_STUFF
1219 wGNOMEUpdateClientStateHint(wwin, False);
1220 #endif
1222 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1224 return;
1227 if (wwin->flags.inspector_open) {
1228 wHideInspectorForWindow(wwin);
1231 wwin->flags.hidden = 1;
1232 wWindowUnmap(wwin);
1234 wClientSetState(wwin, IconicState, icon->icon_win);
1235 flushExpose();
1236 wSoundPlay(WSOUND_HIDE);
1237 #ifdef ANIMATIONS
1238 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1239 !wwin->flags.skip_next_animation && animate) {
1240 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1241 wwin->frame->core->width, wwin->frame->core->height,
1242 icon_x, icon_y, icon->core->width, icon->core->height,
1243 True);
1245 #endif
1246 wwin->flags.skip_next_animation = 0;
1248 #ifdef GNOME_STUFF
1249 wGNOMEUpdateClientStateHint(wwin, False);
1250 #endif
1252 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1257 void
1258 wHideOtherApplications(WWindow *awin)
1260 WWindow *wwin;
1261 WApplication *tapp;
1263 if (!awin)
1264 return;
1265 wwin = awin->screen_ptr->focused_window;
1268 while (wwin) {
1269 if (wwin!=awin
1270 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1271 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1272 && !wwin->flags.internal_window
1273 && wGetWindowOfInspectorForWindow(wwin) != awin
1274 && !WFLAGP(wwin, no_hide_others)) {
1276 if (wwin->main_window==None || WFLAGP(wwin, no_appicon)) {
1277 if (!WFLAGP(wwin, no_miniaturizable)) {
1278 wwin->flags.skip_next_animation = 1;
1279 wIconifyWindow(wwin);
1281 } else if (wwin->main_window!=None
1282 && awin->main_window != wwin->main_window) {
1283 tapp = wApplicationOf(wwin->main_window);
1284 if (tapp) {
1285 tapp->flags.skip_next_animation = 1;
1286 wHideApplication(tapp);
1287 } else {
1288 if (!WFLAGP(wwin, no_miniaturizable)) {
1289 wwin->flags.skip_next_animation = 1;
1290 wIconifyWindow(wwin);
1295 wwin = wwin->prev;
1298 wSetFocusTo(awin->screen_ptr, awin);
1304 void
1305 wHideApplication(WApplication *wapp)
1307 WScreen *scr;
1308 WWindow *wlist;
1309 int hadfocus;
1311 if (!wapp) {
1312 wwarning("trying to hide a non grouped window");
1313 return;
1315 if (!wapp->main_window_desc) {
1316 wwarning("group leader not found for window group");
1317 return;
1319 scr = wapp->main_window_desc->screen_ptr;
1320 hadfocus = 0;
1321 wlist = scr->focused_window;
1322 if (!wlist)
1323 return;
1325 if (wlist->main_window == wapp->main_window)
1326 wapp->last_focused = wlist;
1327 else
1328 wapp->last_focused = NULL;
1329 while (wlist) {
1330 if (wlist->main_window == wapp->main_window) {
1331 if (wlist->flags.focused) {
1332 hadfocus = 1;
1334 if (wapp->app_icon)
1335 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1336 wapp->app_icon->y_pos, wlist,
1337 !wapp->flags.skip_next_animation);
1339 wlist = wlist->prev;
1342 wapp->flags.skip_next_animation = 0;
1344 if (hadfocus) {
1345 if (wPreferences.focus_mode==WKF_CLICK) {
1346 wlist = scr->focused_window;
1347 while (wlist) {
1348 if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden
1349 && (wlist->flags.mapped || wlist->flags.shaded))
1350 break;
1351 wlist = wlist->prev;
1353 wSetFocusTo(scr, wlist);
1354 } else {
1355 wSetFocusTo(scr, NULL);
1359 wapp->flags.hidden = 1;
1361 if(wPreferences.auto_arrange_icons) {
1362 wArrangeIcons(scr, True);
1364 #ifdef HIDDENDOT
1365 if (wapp->app_icon)
1366 wAppIconPaint(wapp->app_icon);
1367 #endif
1373 static void
1374 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1375 int bringToCurrentWS)
1377 if (bringToCurrentWS)
1378 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1380 wwin->flags.hidden=0;
1381 wwin->flags.mapped=1;
1383 wSoundPlay(WSOUND_UNHIDE);
1384 #ifdef ANIMATIONS
1385 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1386 && animate) {
1387 animateResize(wwin->screen_ptr, icon_x, icon_y,
1388 icon->core->width, icon->core->height,
1389 wwin->frame_x, wwin->frame_y,
1390 wwin->frame->core->width, wwin->frame->core->height,
1391 True);
1393 #endif
1394 wwin->flags.skip_next_animation = 0;
1395 XMapWindow(dpy, wwin->client_win);
1396 XMapWindow(dpy, wwin->frame->core->window);
1397 wClientSetState(wwin, NormalState, None);
1398 wRaiseFrame(wwin->frame->core);
1399 if (wwin->flags.inspector_open) {
1400 wUnhideInspectorForWindow(wwin);
1403 #ifdef GNOME_STUFF
1404 wGNOMEUpdateClientStateHint(wwin, False);
1405 #endif
1407 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1412 void
1413 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1415 WScreen *scr;
1416 WWindow *wlist, *next;
1417 WWindow *focused=NULL;
1419 if (!wapp) {
1420 return;
1422 scr = wapp->main_window_desc->screen_ptr;
1423 wlist = scr->focused_window;
1424 if (!wlist) return;
1425 /* goto beginning of list */
1426 while (wlist->prev)
1427 wlist = wlist->prev;
1429 while (wlist) {
1430 next = wlist->next;
1432 if (wlist->main_window == wapp->main_window) {
1433 if (wlist->flags.focused)
1434 focused = wlist;
1435 else if (!focused || !focused->flags.focused)
1436 focused = wlist;
1438 if (wlist->flags.miniaturized && wlist->icon) {
1439 if (bringToCurrentWS || wPreferences.sticky_icons
1440 || wlist->frame->workspace == scr->current_workspace) {
1441 if (!wlist->icon->mapped) {
1442 XMapWindow(dpy, wlist->icon->core->window);
1443 wlist->icon->mapped = 1;
1445 wlist->flags.hidden = 0;
1447 UpdateSwitchMenu(scr, wlist, ACTION_CHANGE_STATE);
1449 if (wlist->frame->workspace != scr->current_workspace)
1450 wWindowChangeWorkspace(wlist, scr->current_workspace);
1452 if (miniwindows) {
1453 wDeiconifyWindow(wlist);
1455 } else if (wlist->flags.hidden) {
1456 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1457 wapp->app_icon->y_pos, wlist,
1458 !wapp->flags.skip_next_animation,
1459 bringToCurrentWS);
1460 } else {
1461 if (bringToCurrentWS
1462 && wlist->frame->workspace != scr->current_workspace) {
1463 wWindowChangeWorkspace(wlist, scr->current_workspace);
1465 wRaiseFrame(wlist->frame->core);
1468 wlist = next;
1471 wapp->flags.skip_next_animation = 0;
1472 wapp->flags.hidden = 0;
1474 if (focused)
1475 wSetFocusTo(scr, focused);
1476 else if (wapp->last_focused && wapp->last_focused->flags.mapped)
1477 wSetFocusTo(scr, wapp->last_focused);
1478 wapp->last_focused = NULL;
1479 if (wPreferences.auto_arrange_icons) {
1480 wArrangeIcons(scr, True);
1482 #ifdef HIDDENDOT
1483 wAppIconPaint(wapp->app_icon);
1484 #endif
1489 void
1490 wShowAllWindows(WScreen *scr)
1492 WWindow *wwin, *old_foc;
1493 WApplication *wapp;
1495 old_foc = wwin = scr->focused_window;
1496 while (wwin) {
1497 if (!wwin->flags.internal_window &&
1498 (scr->current_workspace == wwin->frame->workspace
1499 || IS_OMNIPRESENT(wwin))) {
1500 if (wwin->flags.miniaturized) {
1501 wwin->flags.skip_next_animation = 1;
1502 wDeiconifyWindow(wwin);
1503 } else if (wwin->flags.hidden) {
1504 wapp = wApplicationOf(wwin->main_window);
1505 if (wapp) {
1506 wUnhideApplication(wapp, False, False);
1507 } else {
1508 wwin->flags.skip_next_animation = 1;
1509 wDeiconifyWindow(wwin);
1513 wwin = wwin->prev;
1515 wSetFocusTo(scr, old_foc);
1516 /*wRaiseFrame(old_foc->frame->core);*/
1520 void
1521 wRefreshDesktop(WScreen *scr)
1523 Window win;
1524 XSetWindowAttributes attr;
1526 attr.backing_store = NotUseful;
1527 attr.save_under = False;
1528 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1529 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1530 (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
1531 &attr);
1532 XMapRaised(dpy, win);
1533 XDestroyWindow(dpy, win);
1534 XFlush(dpy);
1538 void
1539 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1541 WWindow *wwin;
1542 WAppIcon *aicon;
1543 int pf; /* primary axis */
1544 int sf; /* secondary axis */
1545 int fullW;
1546 int fullH;
1547 int pi, si;
1548 int sx1, sx2, sy1, sy2; /* screen boundary */
1549 int sw, sh;
1550 int xo, yo;
1551 int xs, ys;
1552 int isize = wPreferences.icon_size;
1555 * Find out screen boundaries.
1557 sx1 = 0;
1558 sy1 = 0;
1559 sx2 = scr->scr_width;
1560 sy2 = scr->scr_height;
1561 if (scr->dock) {
1562 if (scr->dock->on_right_side)
1563 sx2 -= isize + DOCK_EXTRA_SPACE;
1564 else
1565 sx1 += isize + DOCK_EXTRA_SPACE;
1568 sw = isize * (scr->scr_width/isize);
1569 sh = isize * (scr->scr_height/isize);
1570 fullW = (sx2-sx1)/isize;
1571 fullH = (sy2-sy1)/isize;
1573 /* icon yard boundaries */
1574 if (wPreferences.icon_yard & IY_VERT) {
1575 pf = fullH;
1576 sf = fullW;
1577 } else {
1578 pf = fullW;
1579 sf = fullH;
1581 if (wPreferences.icon_yard & IY_RIGHT) {
1582 xo = sx2 - isize;
1583 xs = -1;
1584 } else {
1585 xo = sx1;
1586 xs = 1;
1588 if (wPreferences.icon_yard & IY_TOP) {
1589 yo = sy1;
1590 ys = 1;
1591 } else {
1592 yo = sy2 - isize;
1593 ys = -1;
1596 /* arrange icons putting the most recently focused window
1597 * as the last icon */
1598 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1599 : xo + xs*(pi*isize))
1600 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1601 : yo + ys*(si*isize))
1603 /* arrange application icons */
1604 aicon = scr->app_icon_list;
1605 /* reverse them to avoid unnecessarily sliding of icons */
1606 while (aicon && aicon->next)
1607 aicon = aicon->next;
1609 pi = 0;
1610 si = 0;
1611 while (aicon) {
1612 if (!aicon->docked && wAppIconIsFirstInstance(aicon)) {
1613 if (aicon->x_pos != X || aicon->y_pos != Y) {
1614 #ifdef ANIMATIONS
1615 if (!wPreferences.no_animations) {
1616 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1617 X, Y);
1619 #endif /* ANIMATIONS */
1621 wAppIconMove(aicon, X, Y);
1622 pi++;
1624 /* we reversed the order so we use prev */
1625 aicon = aicon->prev;
1626 if (pi >= pf) {
1627 pi=0;
1628 si++;
1632 /* arrange miniwindows */
1634 wwin = scr->focused_window;
1635 /* reverse them to avoid unnecessarily shuffling */
1636 while (wwin && wwin->prev)
1637 wwin = wwin->prev;
1639 while (wwin) {
1640 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1641 (wwin->frame->workspace==scr->current_workspace ||
1642 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1644 if (arrangeAll || !wwin->flags.icon_moved) {
1645 if (wwin->icon_x != X || wwin->icon_y != Y) {
1646 #ifdef ANIMATIONS
1647 if (wPreferences.no_animations) {
1648 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1649 } else {
1650 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1651 wwin->icon_y, X, Y);
1653 #else
1654 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1655 #endif /* ANIMATIONS */
1657 wwin->icon_x = X;
1658 wwin->icon_y = Y;
1659 pi++;
1662 if (arrangeAll) {
1663 wwin->flags.icon_moved = 0;
1665 /* we reversed the order, so we use next */
1666 wwin = wwin->next;
1667 if (pi >= pf) {
1668 pi=0;
1669 si++;
1675 void
1676 wSelectWindow(WWindow *wwin, Bool flag)
1678 WScreen *scr = wwin->screen_ptr;
1680 if (flag) {
1681 wwin->flags.selected = 1;
1682 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1684 if (WFLAGP(wwin, no_border)) {
1685 XSetWindowBorderWidth(dpy, wwin->frame->core->window,
1686 FRAME_BORDER_WIDTH);
1689 if (!scr->selected_windows)
1690 scr->selected_windows = WMCreateArray(4);
1691 WMAddToArray(scr->selected_windows, wwin);
1692 } else {
1693 wwin->flags.selected = 0;
1694 XSetWindowBorder(dpy, wwin->frame->core->window,
1695 scr->frame_border_pixel);
1697 if (WFLAGP(wwin, no_border)) {
1698 XSetWindowBorderWidth(dpy, wwin->frame->core->window, 0);
1701 if (scr->selected_windows) {
1702 WMRemoveFromArray(scr->selected_windows, wwin);
1708 void
1709 wMakeWindowVisible(WWindow *wwin)
1711 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
1712 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1714 if (wwin->flags.shaded) {
1715 wUnshadeWindow(wwin);
1717 if (wwin->flags.hidden) {
1718 WApplication *app;
1720 app = wApplicationOf(wwin->main_window);
1721 if (app)
1722 wUnhideApplication(app, False, False);
1723 } else if (wwin->flags.miniaturized) {
1724 wDeiconifyWindow(wwin);
1725 } else {
1726 if (!WFLAGP(wwin, no_focusable))
1727 wSetFocusTo(wwin->screen_ptr, wwin);
1728 wRaiseFrame(wwin->frame->core);