Applied patch from Largo to update sound related stuff and documentation
[wmaker-crm.git] / src / actions.c
blobf1be29b2e88502239ead72a9136855bc1c05a2c2
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"
51 #ifdef GNOME_STUFF
52 # include "gnome.h"
53 #endif
54 #ifdef KWM_HINTS
55 # include "kwm.h"
56 #endif
58 #ifdef WSOUND
59 #include "wsound.h"
60 #endif
63 /****** Global Variables ******/
64 extern Time LastTimestamp;
65 extern Time LastFocusChange;
67 extern Cursor wCursor[WCUR_LAST];
69 extern WPreferences wPreferences;
71 extern Atom _XA_WM_TAKE_FOCUS;
74 /******* Local Variables *******/
75 static struct {
76 int steps;
77 int delay;
78 } shadePars[5] = {
79 {SHADE_STEPS_UF, SHADE_DELAY_UF},
80 {SHADE_STEPS_F, SHADE_DELAY_F},
81 {SHADE_STEPS_M, SHADE_DELAY_M},
82 {SHADE_STEPS_S, SHADE_DELAY_S},
83 {SHADE_STEPS_U, SHADE_DELAY_U}};
85 #define SHADE_STEPS shadePars[(int)wPreferences.shade_speed].steps
86 #define SHADE_DELAY shadePars[(int)wPreferences.shade_speed].delay
89 static int ignoreTimestamp=0;
92 #ifdef ANIMATIONS
93 static void
94 processEvents(int event_count)
96 XEvent event;
99 * This is a hack. When animations are enabled, processing of
100 * events ocurred during a animation are delayed until it's end.
101 * Calls that consider the TimeStamp, like XSetInputFocus(), will
102 * fail because the TimeStamp is too old. Then, for example, if
103 * the user changes window focus while a miniaturize animation is
104 * in course, the window will not get focus properly after the end
105 * of the animation. This tries to workaround it by passing CurrentTime
106 * as the TimeStamp for XSetInputFocus() for all events ocurred during
107 * the animation.
109 ignoreTimestamp=1;
110 while (XPending(dpy) && event_count--) {
111 WMNextEvent(dpy, &event);
112 WMHandleEvent(&event);
114 ignoreTimestamp=0;
116 #endif /* ANIMATIONS */
121 *----------------------------------------------------------------------
122 * wSetFocusTo--
123 * Changes the window focus to the one passed as argument.
124 * If the window to focus is not already focused, it will be brought
125 * to the head of the list of windows. Previously focused window is
126 * unfocused.
128 * Side effects:
129 * Window list may be reordered and the window focus is changed.
131 *----------------------------------------------------------------------
133 void
134 wSetFocusTo(WScreen *scr, WWindow *wwin)
136 static WScreen *old_scr=NULL;
138 WWindow *old_focused;
139 WWindow *focused=scr->focused_window;
140 int timestamp=LastTimestamp;
141 WApplication *oapp=NULL, *napp=NULL;
142 int wasfocused;
144 if (!old_scr)
145 old_scr=scr;
146 old_focused=old_scr->focused_window;
148 LastFocusChange = timestamp;
151 * This is a hack, because XSetInputFocus() should have a proper
152 * timestamp instead of CurrentTime but it seems that some times
153 * clients will not receive focus properly that way.
154 if (ignoreTimestamp)
156 timestamp = CurrentTime;
158 if (old_focused)
159 oapp = wApplicationOf(old_focused->main_window);
161 if (wwin == NULL) {
162 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
163 if (old_focused && !old_focused->flags.is_gnustep) {
164 wWindowUnfocus(old_focused);
166 if (oapp) {
167 wAppMenuUnmap(oapp->menu);
168 #ifdef NEWAPPICON
169 wApplicationDeactivate(oapp);
170 #endif
172 #ifdef KWM_HINTS
173 wKWMUpdateActiveWindowHint(scr);
174 wKWMSendEventMessage(NULL, WKWMFocusWindow);
175 #endif
176 return;
177 } else if (old_scr != scr && old_focused && !old_focused->flags.is_gnustep) {
178 wWindowUnfocus(old_focused);
181 wasfocused = wwin->flags.focused;
182 napp = wApplicationOf(wwin->main_window);
184 /* remember last workspace where the app has been */
185 if (napp)
186 napp->last_workspace = wwin->screen_ptr->current_workspace;
188 if (wwin->flags.mapped && !WFLAGP(wwin, no_focusable)) {
189 /* install colormap if colormap mode is lock mode */
190 if (wPreferences.colormap_mode==WKF_CLICK)
191 wColormapInstallForWindow(scr, wwin);
193 /* set input focus */
194 switch (wwin->focus_mode) {
195 case WFM_NO_INPUT:
196 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
197 break;
199 case WFM_PASSIVE:
200 case WFM_LOCALLY_ACTIVE:
201 XSetInputFocus(dpy, wwin->client_win, RevertToParent, timestamp);
202 break;
204 case WFM_GLOBALLY_ACTIVE:
205 break;
207 XFlush(dpy);
208 if (wwin->protocols.TAKE_FOCUS) {
209 wClientSendProtocol(wwin, _XA_WM_TAKE_FOCUS, timestamp);
211 XSync(dpy, False);
212 } else {
213 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
215 if (WFLAGP(wwin, no_focusable))
216 return;
218 /* if this is not the focused window focus it */
219 if (focused!=wwin) {
220 /* change the focus window list order */
221 if (wwin->prev)
222 wwin->prev->next = wwin->next;
224 if (wwin->next)
225 wwin->next->prev = wwin->prev;
227 wwin->prev = focused;
228 focused->next = wwin;
229 wwin->next = NULL;
230 scr->focused_window = wwin;
232 if (oapp && oapp != napp) {
233 wAppMenuUnmap(oapp->menu);
234 #ifdef NEWAPPICON
235 wApplicationDeactivate(oapp);
236 #endif
240 if (!wwin->flags.is_gnustep)
241 wWindowFocus(wwin, focused);
243 if (napp && !wasfocused) {
244 #ifdef USER_MENU
245 wUserMenuRefreshInstances(napp->menu, wwin);
246 #endif /* USER_MENU */
248 if (wwin->flags.mapped)
249 wAppMenuMap(napp->menu, wwin);
250 #ifdef NEWAPPICON
251 wApplicationActivate(napp);
252 #endif
254 #ifdef KWM_HINTS
255 wKWMUpdateActiveWindowHint(scr);
256 wKWMSendEventMessage(wwin, WKWMFocusWindow);
257 #endif
258 XFlush(dpy);
259 old_scr=scr;
263 void
264 wShadeWindow(WWindow *wwin)
266 time_t time0 = time(NULL);
267 #ifdef ANIMATIONS
268 int y, s, w, h;
269 #endif
271 if (wwin->flags.shaded)
272 return;
274 XLowerWindow(dpy, wwin->client_win);
276 #ifdef WSOUND
277 wSoundPlay(WSOUND_SHADE);
278 #endif
280 #ifdef ANIMATIONS
281 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
282 && !wPreferences.no_animations) {
283 /* do the shading animation */
284 h = wwin->frame->core->height;
285 s = h/SHADE_STEPS;
286 if (s < 1) s=1;
287 w = wwin->frame->core->width;
288 y = wwin->frame->top_width;
289 while (h>wwin->frame->top_width+1) {
290 XMoveWindow(dpy, wwin->client_win, 0, y);
291 XResizeWindow(dpy, wwin->frame->core->window, w, h);
292 XFlush(dpy);
294 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
295 break;
297 if (SHADE_DELAY > 0)
298 wusleep(SHADE_DELAY*1000L);
299 h-=s;
300 y-=s;
302 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
304 #endif /* ANIMATIONS */
306 wwin->flags.skip_next_animation = 0;
307 wwin->flags.shaded = 1;
308 wwin->flags.mapped = 0;
309 /* prevent window withdrawal when getting UnmapNotify */
310 XSelectInput(dpy, wwin->client_win,
311 wwin->event_mask & ~StructureNotifyMask);
312 XUnmapWindow(dpy, wwin->client_win);
313 XSelectInput(dpy, wwin->client_win, wwin->event_mask);
315 /* for the client it's just like iconification */
316 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
317 wwin->frame->top_width - 1);
319 wwin->client.y = wwin->frame_y - wwin->client.height
320 + wwin->frame->top_width;
321 wWindowSynthConfigureNotify(wwin);
324 wClientSetState(wwin, IconicState, None);
327 #ifdef GNOME_STUFF
328 wGNOMEUpdateClientStateHint(wwin, False);
329 #endif
330 #ifdef KWM_HINTS
331 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
332 wKWMSendEventMessage(wwin, WKWMChangedClient);
333 #endif
334 /* update window list to reflect shaded state */
335 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
337 #ifdef ANIMATIONS
338 if (!wwin->screen_ptr->flags.startup) {
339 /* Look at processEvents() for reason of this code. */
340 XSync(dpy, 0);
341 processEvents(XPending(dpy));
343 #endif
347 void
348 wUnshadeWindow(WWindow *wwin)
350 time_t time0 = time(NULL);
351 #ifdef ANIMATIONS
352 int y, s, w, h;
353 #endif /* ANIMATIONS */
356 if (!wwin->flags.shaded)
357 return;
359 wwin->flags.shaded = 0;
360 wwin->flags.mapped = 1;
361 XMapWindow(dpy, wwin->client_win);
363 #ifdef WSOUND
364 wSoundPlay(WSOUND_UNSHADE);
365 #endif
367 #ifdef ANIMATIONS
368 if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) {
369 /* do the shading animation */
370 h = wwin->frame->top_width + wwin->frame->bottom_width;
371 y = wwin->frame->top_width - wwin->client.height;
372 s = abs(y)/SHADE_STEPS;
373 if (s<1) s=1;
374 w = wwin->frame->core->width;
375 XMoveWindow(dpy, wwin->client_win, 0, y);
376 if (s>0) {
377 while (h < wwin->client.height + wwin->frame->top_width
378 + wwin->frame->bottom_width) {
379 XResizeWindow(dpy, wwin->frame->core->window, w, h);
380 XMoveWindow(dpy, wwin->client_win, 0, y);
381 XFlush(dpy);
382 if (SHADE_DELAY > 0)
383 wusleep(SHADE_DELAY*2000L/3);
384 h+=s;
385 y+=s;
387 if (time(NULL)-time0 > MAX_ANIMATION_TIME)
388 break;
391 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
393 #endif /* ANIMATIONS */
395 wwin->flags.skip_next_animation = 0;
396 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
397 wwin->frame->top_width + wwin->client.height
398 + wwin->frame->bottom_width);
400 wwin->client.y = wwin->frame_y + wwin->frame->top_width;
401 wWindowSynthConfigureNotify(wwin);
404 wClientSetState(wwin, NormalState, None);
406 /* if the window is focused, set the focus again as it was disabled during
407 * shading */
408 if (wwin->flags.focused)
409 wSetFocusTo(wwin->screen_ptr, wwin);
411 #ifdef GNOME_STUFF
412 wGNOMEUpdateClientStateHint(wwin, False);
413 #endif
414 #ifdef KWM_HINTS
415 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
416 wKWMSendEventMessage(wwin, WKWMChangedClient);
417 #endif
419 /* update window list to reflect unshaded state */
420 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
425 void
426 wMaximizeWindow(WWindow *wwin, int directions)
428 int new_width, new_height, new_x, new_y;
429 WArea usableArea = wwin->screen_ptr->totalUsableArea;
430 WArea totalArea;
433 if (WFLAGP(wwin, no_resizable))
434 return;
436 totalArea.x1 = 0;
437 totalArea.y1 = 0;
438 totalArea.x2 = wwin->screen_ptr->scr_width;
439 totalArea.y2 = wwin->screen_ptr->scr_height;
441 #ifdef XINERAMA
442 if (wwin->screen_ptr->xine_count > 0
443 && !(directions & MAX_IGNORE_XINERAMA)) {
444 WScreen *scr = wwin->screen_ptr;
445 WMRect rect;
447 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
448 totalArea.x1 = rect.pos.x;
449 totalArea.y1 = rect.pos.y;
450 totalArea.x2 = totalArea.x1 + rect.size.width;
451 totalArea.y2 = totalArea.y1 + rect.size.height;
453 usableArea.x1 = WMAX(totalArea.x1, usableArea.x1);
454 usableArea.y1 = WMAX(totalArea.y1, usableArea.y1);
455 usableArea.x2 = WMIN(totalArea.x2, usableArea.x2);
456 usableArea.y2 = WMIN(totalArea.y2, usableArea.y2);
458 #endif /* XINERAMA */
460 if (WFLAGP(wwin, full_maximize)) {
461 usableArea = totalArea;
464 if (wwin->flags.shaded) {
465 wwin->flags.skip_next_animation = 1;
466 wUnshadeWindow(wwin);
468 wwin->flags.maximized = directions;
469 wwin->old_geometry.width = wwin->client.width;
470 wwin->old_geometry.height = wwin->client.height;
471 wwin->old_geometry.x = wwin->frame_x;
472 wwin->old_geometry.y = wwin->frame_y;
474 #ifdef KWM_HINTS
475 wKWMUpdateClientGeometryRestore(wwin);
476 #endif
478 if (directions & MAX_HORIZONTAL) {
480 new_width = (usableArea.x2-usableArea.x1)-FRAME_BORDER_WIDTH*2;
481 new_x = usableArea.x1;
483 } else {
485 new_x = wwin->frame_x;
486 new_width = wwin->frame->core->width;
490 if (directions & MAX_VERTICAL) {
492 new_height = (usableArea.y2-usableArea.y1)-FRAME_BORDER_WIDTH*2;
493 new_y = usableArea.y1;
494 if (WFLAGP(wwin, full_maximize)) {
495 new_y -= wwin->frame->top_width;
496 new_height += wwin->frame->bottom_width - 1;
498 } else {
499 new_y = wwin->frame_y;
500 new_height = wwin->frame->core->height;
503 if (!WFLAGP(wwin, full_maximize)) {
504 new_height -= wwin->frame->top_width+wwin->frame->bottom_width;
507 wWindowConstrainSize(wwin, &new_width, &new_height);
508 wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
510 #ifdef GNOME_STUFF
511 wGNOMEUpdateClientStateHint(wwin, False);
512 #endif
513 #ifdef KWM_HINTS
514 wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
515 wKWMSendEventMessage(wwin, WKWMChangedClient);
516 #endif
518 #ifdef WSOUND
519 wSoundPlay(WSOUND_MAXIMIZE);
520 #endif
524 void
525 wUnmaximizeWindow(WWindow *wwin)
527 int restore_x, restore_y;
529 if (!wwin->flags.maximized)
530 return;
532 if (wwin->flags.shaded) {
533 wwin->flags.skip_next_animation = 1;
534 wUnshadeWindow(wwin);
536 restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ?
537 wwin->old_geometry.x : wwin->frame_x;
538 restore_y = (wwin->flags.maximized & MAX_VERTICAL) ?
539 wwin->old_geometry.y : wwin->frame_y;
540 wwin->flags.maximized = 0;
541 wWindowConfigure(wwin, restore_x, restore_y,
542 wwin->old_geometry.width, wwin->old_geometry.height);
544 #ifdef GNOME_STUFF
545 wGNOMEUpdateClientStateHint(wwin, False);
546 #endif
547 #ifdef KWM_HINTS
548 wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
549 wKWMSendEventMessage(wwin, WKWMChangedClient);
550 #endif
552 #ifdef WSOUND
553 wSoundPlay(WSOUND_UNMAXIMIZE);
554 #endif
557 #ifdef ANIMATIONS
558 static void
559 animateResizeFlip(WScreen *scr, int x, int y, int w, int h,
560 int fx, int fy, int fw, int fh, int steps)
562 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
563 float cx, cy, cw, ch;
564 float xstep, ystep, wstep, hstep;
565 XPoint points[5];
566 float dx, dch, midy;
567 float angle, final_angle, delta;
569 xstep = (float)(fx-x)/steps;
570 ystep = (float)(fy-y)/steps;
571 wstep = (float)(fw-w)/steps;
572 hstep = (float)(fh-h)/steps;
574 cx = (float)x;
575 cy = (float)y;
576 cw = (float)w;
577 ch = (float)h;
579 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F;
580 delta = (float)(final_angle/FRAMES);
581 for (angle=0;; angle+=delta) {
582 if (angle > final_angle)
583 angle = final_angle;
585 dx = (cw/10) - ((cw/5) * sin(angle));
586 dch = (ch/2) * cos(angle);
587 midy = cy + (ch/2);
589 points[0].x = cx + dx; points[0].y = midy - dch;
590 points[1].x = cx + cw - dx; points[1].y = points[0].y;
591 points[2].x = cx + cw + dx; points[2].y = midy + dch;
592 points[3].x = cx - dx; points[3].y = points[2].y;
593 points[4].x = points[0].x; points[4].y = points[0].y;
595 XGrabServer(dpy);
596 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
597 XFlush(dpy);
598 #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
599 wusleep(MINIATURIZE_ANIMATION_DELAY_F);
600 #endif
602 XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
603 XUngrabServer(dpy);
604 cx+=xstep;
605 cy+=ystep;
606 cw+=wstep;
607 ch+=hstep;
608 if (angle >= final_angle)
609 break;
612 XFlush(dpy);
614 #undef FRAMES
617 static void
618 animateResizeTwist(WScreen *scr, int x, int y, int w, int h,
619 int fx, int fy, int fw, int fh, int steps)
621 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
622 float cx, cy, cw, ch;
623 float xstep, ystep, wstep, hstep;
624 XPoint points[5];
625 float angle, final_angle, a, d, delta;
627 x += w/2;
628 y += h/2;
629 fx += fw/2;
630 fy += fh/2;
632 xstep = (float)(fx-x)/steps;
633 ystep = (float)(fy-y)/steps;
634 wstep = (float)(fw-w)/steps;
635 hstep = (float)(fh-h)/steps;
637 cx = (float)x;
638 cy = (float)y;
639 cw = (float)w;
640 ch = (float)h;
642 final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T;
643 delta = (float)(final_angle/FRAMES);
644 for (angle=0;; angle+=delta) {
645 if (angle > final_angle)
646 angle = final_angle;
648 a = atan(ch/cw);
649 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
651 points[0].x = cx+cos(angle-a)*d;
652 points[0].y = cy+sin(angle-a)*d;
653 points[1].x = cx+cos(angle+a)*d;
654 points[1].y = cy+sin(angle+a)*d;
655 points[2].x = cx+cos(angle-a+WM_PI)*d;
656 points[2].y = cy+sin(angle-a+WM_PI)*d;
657 points[3].x = cx+cos(angle+a+WM_PI)*d;
658 points[3].y = cy+sin(angle+a+WM_PI)*d;
659 points[4].x = cx+cos(angle-a)*d;
660 points[4].y = cy+sin(angle-a)*d;
661 XGrabServer(dpy);
662 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
663 XFlush(dpy);
664 #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
665 wusleep(MINIATURIZE_ANIMATION_DELAY_T);
666 #endif
668 XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
669 XUngrabServer(dpy);
670 cx+=xstep;
671 cy+=ystep;
672 cw+=wstep;
673 ch+=hstep;
674 if (angle >= final_angle)
675 break;
678 XFlush(dpy);
680 #undef FRAMES
683 static void
684 animateResizeZoom(WScreen *scr, int x, int y, int w, int h,
685 int fx, int fy, int fw, int fh, int steps)
687 #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
688 float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
689 float xstep, ystep, wstep, hstep;
690 int i, j;
692 xstep = (float)(fx-x)/steps;
693 ystep = (float)(fy-y)/steps;
694 wstep = (float)(fw-w)/steps;
695 hstep = (float)(fh-h)/steps;
697 for (j=0; j<FRAMES; j++) {
698 cx[j] = (float)x;
699 cy[j] = (float)y;
700 cw[j] = (float)w;
701 ch[j] = (float)h;
703 XGrabServer(dpy);
704 for (i=0; i<steps; i++) {
705 for (j=0; j<FRAMES; j++) {
706 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
707 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
709 XFlush(dpy);
710 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
711 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
712 #endif
713 for (j=0; j<FRAMES; j++) {
714 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
715 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
716 if (j<FRAMES-1) {
717 cx[j]=cx[j+1];
718 cy[j]=cy[j+1];
719 cw[j]=cw[j+1];
720 ch[j]=ch[j+1];
721 } else {
722 cx[j]+=xstep;
723 cy[j]+=ystep;
724 cw[j]+=wstep;
725 ch[j]+=hstep;
730 for (j=0; j<FRAMES; j++) {
731 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
732 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
734 XFlush(dpy);
735 #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
736 wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
737 #endif
738 for (j=0; j<FRAMES; j++) {
739 XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
740 (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
743 XUngrabServer(dpy);
745 #undef FRAMES
748 static void
749 animateResize(WScreen *scr, int x, int y, int w, int h,
750 int fx, int fy, int fw, int fh, int hiding)
752 int style = wPreferences.iconification_style; /* Catch the value */
753 int steps, k;
755 if (style == WIS_NONE)
756 return;
758 if (style == WIS_RANDOM) {
759 style = rand()%3;
762 k = (hiding ? 2 : 3);
763 switch(style) {
764 case WIS_TWIST:
765 steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
766 if (steps>0)
767 animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
768 break;
769 case WIS_FLIP:
770 steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
771 if (steps>0)
772 animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
773 break;
774 case WIS_ZOOM:
775 default:
776 steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
777 if (steps>0)
778 animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
779 break;
782 #endif /* ANIMATIONS */
785 static void
786 flushExpose()
788 XEvent tmpev;
790 while (XCheckTypedEvent(dpy, Expose, &tmpev))
791 WMHandleEvent(&tmpev);
792 XSync(dpy, 0);
795 static void
796 unmapTransientsFor(WWindow *wwin)
798 WWindow *tmp;
801 tmp = wwin->screen_ptr->focused_window;
802 while (tmp) {
803 /* unmap the transients for this transient */
804 if (tmp!=wwin && tmp->transient_for == wwin->client_win
805 && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
806 || tmp->flags.shaded)) {
807 unmapTransientsFor(tmp);
808 tmp->flags.miniaturized = 1;
809 if (!tmp->flags.shaded) {
810 wWindowUnmap(tmp);
811 } else {
812 XUnmapWindow(dpy, tmp->frame->core->window);
815 if (!tmp->flags.shaded)
817 wClientSetState(tmp, IconicState, None);
818 #ifdef KWM_HINTS
819 wKWMUpdateClientStateHint(tmp, KWMIconifiedFlag);
820 wKWMSendEventMessage(tmp, WKWMRemoveWindow);
821 tmp->flags.kwm_hidden_for_modules = 1;
822 #endif
824 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
827 tmp = tmp->prev;
832 static void
833 mapTransientsFor(WWindow *wwin)
835 WWindow *tmp;
837 tmp = wwin->screen_ptr->focused_window;
838 while (tmp) {
839 /* recursively map the transients for this transient */
840 if (tmp!=wwin && tmp->transient_for == wwin->client_win
841 && /*!tmp->flags.mapped*/ tmp->flags.miniaturized
842 && tmp->icon==NULL) {
843 mapTransientsFor(tmp);
844 tmp->flags.miniaturized = 0;
845 if (!tmp->flags.shaded) {
846 wWindowMap(tmp);
847 } else {
848 XMapWindow(dpy, tmp->frame->core->window);
850 tmp->flags.semi_focused = 0;
852 if (!tmp->flags.shaded)
854 wClientSetState(tmp, NormalState, None);
855 #ifdef KWM_HINTS
856 wKWMUpdateClientStateHint(tmp, KWMIconifiedFlag);
857 if (tmp->flags.kwm_hidden_for_modules) {
858 wKWMSendEventMessage(tmp, WKWMAddWindow);
859 tmp->flags.kwm_hidden_for_modules = 0;
861 #endif
863 UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
866 tmp = tmp->prev;
870 #if 0
871 static void
872 setupIconGrabs(WIcon *icon)
874 /* setup passive grabs on the icon */
875 XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
876 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
877 XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
878 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
879 XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
880 ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
881 XSync(dpy, 0);
883 #endif
885 static WWindow*
886 recursiveTransientFor(WWindow *wwin)
888 int i;
890 if (!wwin)
891 return None;
893 /* hackish way to detect transient_for cycle */
894 i = wwin->screen_ptr->window_count+1;
896 while (wwin && wwin->transient_for != None && i>0) {
897 wwin = wWindowFor(wwin->transient_for);
898 i--;
900 if (i==0 && wwin) {
901 wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
902 wwin->frame->title);
903 return NULL;
906 return wwin;
909 #if 0
910 static void
911 removeIconGrabs(WIcon *icon)
913 /* remove passive grabs on the icon */
914 XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
915 XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
916 XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);
917 XSync(dpy, 0);
919 #endif
922 void
923 wIconifyWindow(WWindow *wwin)
925 XWindowAttributes attribs;
926 int present;
929 if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
930 /* the window doesn't exist anymore */
931 return;
934 if (wwin->flags.miniaturized) {
935 return;
939 if (wwin->transient_for!=None) {
940 WWindow *owner = wWindowFor(wwin->transient_for);
942 if (owner && owner->flags.miniaturized)
943 return;
946 present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
948 /* if the window is in another workspace, simplify process */
949 if (present) {
950 /* icon creation may take a while */
951 XGrabPointer(dpy, wwin->screen_ptr->root_win, False,
952 ButtonMotionMask|ButtonReleaseMask, GrabModeAsync,
953 GrabModeAsync, None, None, CurrentTime);
956 if (!wPreferences.disable_miniwindows) {
957 if (!wwin->flags.icon_moved) {
958 PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y);
960 wwin->icon = wIconCreate(wwin);
962 wwin->icon->mapped = 1;
965 wwin->flags.miniaturized = 1;
966 wwin->flags.mapped = 0;
968 /* unmap transients */
970 unmapTransientsFor(wwin);
972 if (present) {
973 #ifdef WSOUND
974 wSoundPlay(WSOUND_ICONIFY);
975 #endif
977 XUngrabPointer(dpy, CurrentTime);
978 wWindowUnmap(wwin);
979 /* let all Expose events arrive so that we can repaint
980 * something before the animation starts (and the server is grabbed) */
981 XSync(dpy, 0);
983 if (wPreferences.disable_miniwindows)
984 wClientSetState(wwin, IconicState, None);
985 else
986 wClientSetState(wwin, IconicState, wwin->icon->icon_win);
988 flushExpose();
989 #ifdef ANIMATIONS
990 if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
991 && !wPreferences.no_animations) {
992 int ix, iy, iw, ih;
994 if (!wPreferences.disable_miniwindows) {
995 ix = wwin->icon_x;
996 iy = wwin->icon_y;
997 iw = wwin->icon->core->width;
998 ih = wwin->icon->core->height;
999 } else {
1000 #ifdef KWM_HINTS
1001 WArea area;
1003 if (wKWMGetIconGeometry(wwin, &area)) {
1004 ix = area.x1;
1005 iy = area.y1;
1006 iw = area.x2 - ix;
1007 ih = area.y2 - iy;
1008 } else
1009 #endif /* KWM_HINTS */
1011 ix = 0;
1012 iy = 0;
1013 iw = wwin->screen_ptr->scr_width;
1014 ih = wwin->screen_ptr->scr_height;
1017 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1018 wwin->frame->core->width, wwin->frame->core->height,
1019 ix, iy, iw, ih, False);
1021 #endif
1024 wwin->flags.skip_next_animation = 0;
1026 if (!wPreferences.disable_miniwindows) {
1028 if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
1029 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)
1031 XMapWindow(dpy, wwin->icon->core->window);
1033 AddToStackList(wwin->icon->core);
1035 wLowerFrame(wwin->icon->core);
1038 if (present) {
1039 WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
1042 * It doesn't seem to be working and causes button event hangup
1043 * when deiconifying a transient window.
1044 setupIconGrabs(wwin->icon);
1046 if ((wwin->flags.focused
1047 || (owner && wwin->client_win == owner->client_win))
1048 && wPreferences.focus_mode==WKF_CLICK) {
1049 WWindow *tmp;
1051 tmp = wwin->prev;
1052 while (tmp) {
1053 if (!WFLAGP(tmp, no_focusable)
1054 && !(tmp->flags.hidden||tmp->flags.miniaturized)
1055 && (wwin->frame->workspace == tmp->frame->workspace))
1056 break;
1057 tmp = tmp->prev;
1059 wSetFocusTo(wwin->screen_ptr, tmp);
1060 } else if (wPreferences.focus_mode!=WKF_CLICK) {
1061 wSetFocusTo(wwin->screen_ptr, NULL);
1064 #ifdef ANIMATIONS
1065 if (!wwin->screen_ptr->flags.startup) {
1066 Window clientwin = wwin->client_win;
1068 XSync(dpy, 0);
1069 processEvents(XPending(dpy));
1071 /* the window can disappear while doing the processEvents() */
1072 if (!wWindowFor(clientwin))
1073 return;
1075 #endif
1079 if (wwin->flags.selected && !wPreferences.disable_miniwindows)
1080 wIconSelect(wwin->icon);
1082 #ifdef GNOME_STUFF
1083 wGNOMEUpdateClientStateHint(wwin, False);
1084 #endif
1085 #ifdef KWM_HINTS
1086 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1087 wKWMSendEventMessage(wwin, WKWMChangedClient);
1088 #endif
1090 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1096 void
1097 wDeiconifyWindow(WWindow *wwin)
1099 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1101 if (!wwin->flags.miniaturized)
1102 return;
1104 if (wwin->transient_for != None
1105 && wwin->transient_for != wwin->screen_ptr->root_win) {
1106 WWindow *owner = recursiveTransientFor(wwin);
1108 if (owner && owner->flags.miniaturized) {
1109 wDeiconifyWindow(owner);
1110 wSetFocusTo(wwin->screen_ptr, wwin);
1111 wRaiseFrame(wwin->frame->core);
1112 return;
1116 wwin->flags.miniaturized = 0;
1117 if (!wwin->flags.shaded)
1118 wwin->flags.mapped = 1;
1120 if (!wPreferences.disable_miniwindows) {
1121 if (wwin->icon->selected)
1122 wIconSelect(wwin->icon);
1124 XUnmapWindow(dpy, wwin->icon->core->window);
1127 #ifdef WSOUND
1128 wSoundPlay(WSOUND_DEICONIFY);
1129 #endif
1131 /* if the window is in another workspace, do it silently */
1132 #ifdef ANIMATIONS
1133 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1134 && !wwin->flags.skip_next_animation) {
1135 int ix, iy, iw, ih;
1137 if (!wPreferences.disable_miniwindows) {
1138 ix = wwin->icon_x;
1139 iy = wwin->icon_y;
1140 iw = wwin->icon->core->width;
1141 ih = wwin->icon->core->height;
1142 } else {
1143 #ifdef KWM_HINTS
1144 WArea area;
1146 if (wKWMGetIconGeometry(wwin, &area)) {
1147 ix = area.x1;
1148 iy = area.y1;
1149 iw = area.x2 - ix;
1150 ih = area.y2 - iy;
1151 } else
1152 #endif /* KWM_HINTS */
1154 ix = 0;
1155 iy = 0;
1156 iw = wwin->screen_ptr->scr_width;
1157 ih = wwin->screen_ptr->scr_height;
1160 animateResize(wwin->screen_ptr, ix, iy, iw, ih,
1161 wwin->frame_x, wwin->frame_y,
1162 wwin->frame->core->width, wwin->frame->core->height,
1163 False);
1165 #endif /* ANIMATIONS */
1166 wwin->flags.skip_next_animation = 0;
1167 XGrabServer(dpy);
1168 if (!wwin->flags.shaded) {
1169 XMapWindow(dpy, wwin->client_win);
1171 XMapWindow(dpy, wwin->frame->core->window);
1172 wRaiseFrame(wwin->frame->core);
1173 if (!wwin->flags.shaded) {
1174 wClientSetState(wwin, NormalState, None);
1176 mapTransientsFor(wwin);
1178 if (!wPreferences.disable_miniwindows) {
1179 RemoveFromStackList(wwin->icon->core);
1180 /* removeIconGrabs(wwin->icon);*/
1181 wIconDestroy(wwin->icon);
1182 wwin->icon = NULL;
1184 XUngrabServer(dpy);
1186 if (wPreferences.focus_mode==WKF_CLICK)
1187 wSetFocusTo(wwin->screen_ptr, wwin);
1189 #ifdef ANIMATIONS
1190 if (!wwin->screen_ptr->flags.startup) {
1191 Window clientwin = wwin->client_win;
1193 XSync(dpy, 0);
1194 processEvents(XPending(dpy));
1196 if (!wWindowFor(clientwin))
1197 return;
1199 #endif
1201 if (wPreferences.auto_arrange_icons) {
1202 wArrangeIcons(wwin->screen_ptr, True);
1205 #ifdef GNOME_STUFF
1206 wGNOMEUpdateClientStateHint(wwin, False);
1207 #endif
1208 #ifdef KWM_HINTS
1209 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1210 wKWMSendEventMessage(wwin, WKWMChangedClient);
1211 #endif
1213 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1218 static void
1219 hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
1221 if (wwin->flags.miniaturized) {
1222 if (wwin->icon) {
1223 XUnmapWindow(dpy, wwin->icon->core->window);
1224 wwin->icon->mapped = 0;
1226 wwin->flags.hidden = 1;
1227 #ifdef GNOME_STUFF
1228 wGNOMEUpdateClientStateHint(wwin, False);
1229 #endif
1231 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1233 return;
1236 if (wwin->flags.inspector_open) {
1237 wHideInspectorForWindow(wwin);
1240 wwin->flags.hidden = 1;
1241 wWindowUnmap(wwin);
1243 wClientSetState(wwin, IconicState, icon->icon_win);
1244 flushExpose();
1245 #ifdef WSOUND
1246 wSoundPlay(WSOUND_HIDE);
1247 #endif
1248 #ifdef ANIMATIONS
1249 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
1250 !wwin->flags.skip_next_animation && animate) {
1251 animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
1252 wwin->frame->core->width, wwin->frame->core->height,
1253 icon_x, icon_y, icon->core->width, icon->core->height,
1254 True);
1256 #endif
1257 wwin->flags.skip_next_animation = 0;
1259 #ifdef GNOME_STUFF
1260 wGNOMEUpdateClientStateHint(wwin, False);
1261 #endif
1263 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1268 void
1269 wHideOtherApplications(WWindow *awin)
1271 WWindow *wwin;
1272 WApplication *tapp;
1273 #ifdef REDUCE_APPICONS
1274 char *tinstance, *tclass;
1275 unsigned int brokenwin = 0, match = 0;
1276 #endif
1278 if (!awin)
1279 return;
1280 wwin = awin->screen_ptr->focused_window;
1282 #ifdef REDUCE_APPICONS
1283 if (awin->wm_instance == NULL || awin->wm_class == NULL)
1284 brokenwin++;
1285 #endif
1287 while (wwin) {
1288 if (wwin!=awin
1289 && wwin->frame->workspace == awin->screen_ptr->current_workspace
1290 && !(wwin->flags.miniaturized||wwin->flags.hidden)
1291 && !wwin->flags.internal_window
1292 && wGetWindowOfInspectorForWindow(wwin) != awin
1293 && !WFLAGP(wwin, no_hide_others)) {
1295 #ifdef REDUCE_APPICONS
1296 match = 0;
1297 if (!brokenwin) {
1298 if ((tinstance = wwin->wm_instance) == NULL)
1299 tinstance = "";
1300 if ((tclass = wwin->wm_class) == NULL)
1301 tclass = "";
1302 if ((strcmp(awin->wm_instance, tinstance) == 0) &&
1303 (strcmp(awin->wm_class, tclass) == 0) )
1304 match++;
1306 #endif
1308 if (wwin->main_window==None || WFLAGP(wwin, no_appicon)) {
1309 if (!WFLAGP(wwin, no_miniaturizable)) {
1310 wwin->flags.skip_next_animation = 1;
1311 wIconifyWindow(wwin);
1313 } else if (wwin->main_window!=None
1314 #ifndef REDUCE_APPICONS
1315 && awin->main_window != wwin->main_window) {
1316 #else
1317 && (awin->main_window != wwin->main_window && !match)) {
1318 #endif
1319 tapp = wApplicationOf(wwin->main_window);
1320 if (tapp) {
1321 tapp->flags.skip_next_animation = 1;
1322 wHideApplication(tapp);
1323 } else {
1324 if (!WFLAGP(wwin, no_miniaturizable)) {
1325 wwin->flags.skip_next_animation = 1;
1326 wIconifyWindow(wwin);
1331 wwin = wwin->prev;
1334 wSetFocusTo(awin->screen_ptr, awin);
1340 void
1341 wHideApplication(WApplication *wapp)
1343 #ifdef REDUCE_APPICONS
1344 WApplication *tapp;
1345 char *tinstance, *tclass;
1346 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1347 #endif
1348 WScreen *scr;
1349 WWindow *wlist;
1350 int hadfocus;
1352 if (!wapp) {
1353 wwarning("trying to hide a non grouped window");
1354 return;
1356 if (!wapp->main_window_desc) {
1357 wwarning("group leader not found for window group");
1358 return;
1360 #ifdef REDUCE_APPICONS
1361 if ((wapp->main_window_desc->wm_instance == NULL) ||
1362 (wapp->main_window_desc->wm_class == NULL))
1363 nowmhints++;
1364 #endif
1365 scr = wapp->main_window_desc->screen_ptr;
1366 hadfocus = 0;
1367 wlist = scr->focused_window;
1368 if (!wlist)
1369 return;
1371 if (wlist->main_window == wapp->main_window)
1372 wapp->last_focused = wlist;
1373 else
1374 wapp->last_focused = NULL;
1375 while (wlist) {
1376 #ifdef REDUCE_APPICONS
1377 matchwmhints = matchworkspace = 0;
1378 if (!nowmhints) {
1379 tapp = wApplicationOf(wlist->main_window);
1380 tinstance = tclass = NULL;
1381 if (tapp) {
1382 if (tapp->main_window_desc) {
1383 tinstance = tapp->main_window_desc->wm_instance;
1384 tclass = tapp->main_window_desc->wm_class;
1387 if (tapp == NULL || tinstance == NULL || tclass == NULL) {
1388 /* Should never reach here */
1389 tinstance = "";
1390 tclass = "";
1392 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0) &&
1393 (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1394 matchwmhints++;
1396 if (wlist->frame) {
1397 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1398 matchworkspace++;
1400 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1401 matchworkspace) {
1402 #ifdef I_HATE_THIS
1404 #endif
1405 #else
1406 if (wlist->main_window == wapp->main_window) {
1407 #endif
1408 if (wlist->flags.focused) {
1409 hadfocus = 1;
1411 if (wapp->app_icon)
1412 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1413 wapp->app_icon->y_pos, wlist,
1414 !wapp->flags.skip_next_animation);
1416 wlist = wlist->prev;
1419 wapp->flags.skip_next_animation = 0;
1421 if (hadfocus) {
1422 if (wPreferences.focus_mode==WKF_CLICK) {
1423 wlist = scr->focused_window;
1424 while (wlist) {
1425 if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden
1426 && (wlist->flags.mapped || wlist->flags.shaded))
1427 break;
1428 wlist = wlist->prev;
1430 wSetFocusTo(scr, wlist);
1431 } else {
1432 wSetFocusTo(scr, NULL);
1436 wapp->flags.hidden = 1;
1438 if(wPreferences.auto_arrange_icons) {
1439 wArrangeIcons(scr, True);
1441 #ifdef HIDDENDOT
1442 if (wapp->app_icon)
1443 wAppIconPaint(wapp->app_icon);
1444 #endif
1450 static void
1451 unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
1452 int bringToCurrentWS)
1454 if (bringToCurrentWS)
1455 wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
1457 wwin->flags.hidden=0;
1458 wwin->flags.mapped=1;
1460 #ifdef WSOUND
1461 wSoundPlay(WSOUND_UNHIDE);
1462 #endif
1463 #ifdef ANIMATIONS
1464 if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
1465 && animate) {
1466 animateResize(wwin->screen_ptr, icon_x, icon_y,
1467 icon->core->width, icon->core->height,
1468 wwin->frame_x, wwin->frame_y,
1469 wwin->frame->core->width, wwin->frame->core->height,
1470 True);
1472 #endif
1473 wwin->flags.skip_next_animation = 0;
1474 XMapWindow(dpy, wwin->client_win);
1475 XMapWindow(dpy, wwin->frame->core->window);
1476 wClientSetState(wwin, NormalState, None);
1477 wRaiseFrame(wwin->frame->core);
1478 if (wwin->flags.inspector_open) {
1479 wUnhideInspectorForWindow(wwin);
1482 #ifdef GNOME_STUFF
1483 wGNOMEUpdateClientStateHint(wwin, False);
1484 #endif
1486 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1491 void
1492 wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
1494 WScreen *scr;
1495 WWindow *wlist, *next;
1496 WWindow *focused=NULL;
1497 #ifdef REDUCE_APPICONS
1498 char *tinstance, *tclass;
1499 unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
1500 #endif
1502 if (!wapp) {
1503 return;
1506 #ifdef REDUCE_APPICONS
1507 if ((wapp->main_window_desc->wm_class == NULL) ||
1508 (wapp->main_window_desc->wm_instance == NULL))
1509 nowmhints++;
1510 #endif
1512 scr = wapp->main_window_desc->screen_ptr;
1513 wlist = scr->focused_window;
1514 if (!wlist) return;
1515 /* goto beginning of list */
1516 while (wlist->prev)
1517 wlist = wlist->prev;
1519 while (wlist) {
1520 next = wlist->next;
1522 #ifndef REDUCE_APPICONS
1523 if (wlist->main_window == wapp->main_window) {
1524 #else
1525 matchwmhints = matchworkspace = 0;
1526 if (!nowmhints) {
1527 if ((tinstance = wlist->wm_instance) == NULL)
1528 tinstance = "";
1529 if ((tclass = wlist->wm_class) == NULL)
1530 tclass = "";
1531 if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0)
1532 && (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
1533 matchwmhints++;
1535 if (wlist->frame) {
1536 if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
1537 matchworkspace++;
1540 if ((wlist->main_window == wapp->main_window || matchwmhints) &&
1541 matchworkspace) {
1542 #endif
1543 if (wlist->flags.focused)
1544 focused = wlist;
1545 else if (!focused || !focused->flags.focused)
1546 focused = wlist;
1548 if (wlist->flags.miniaturized && wlist->icon) {
1549 if (bringToCurrentWS || wPreferences.sticky_icons
1550 || wlist->frame->workspace == scr->current_workspace) {
1551 if (!wlist->icon->mapped) {
1552 XMapWindow(dpy, wlist->icon->core->window);
1553 wlist->icon->mapped = 1;
1555 wlist->flags.hidden = 0;
1557 UpdateSwitchMenu(scr, wlist, ACTION_CHANGE_STATE);
1559 if (wlist->frame->workspace != scr->current_workspace)
1560 wWindowChangeWorkspace(wlist, scr->current_workspace);
1562 if (miniwindows) {
1563 wDeiconifyWindow(wlist);
1565 } else if (wlist->flags.hidden) {
1566 unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
1567 wapp->app_icon->y_pos, wlist,
1568 !wapp->flags.skip_next_animation,
1569 bringToCurrentWS);
1570 } else {
1571 if (bringToCurrentWS
1572 && wlist->frame->workspace != scr->current_workspace) {
1573 wWindowChangeWorkspace(wlist, scr->current_workspace);
1575 wRaiseFrame(wlist->frame->core);
1578 wlist = next;
1581 wapp->flags.skip_next_animation = 0;
1582 wapp->flags.hidden = 0;
1584 if (focused)
1585 wSetFocusTo(scr, focused);
1586 else if (wapp->last_focused && wapp->last_focused->flags.mapped)
1587 wSetFocusTo(scr, wapp->last_focused);
1588 wapp->last_focused = NULL;
1589 if (wPreferences.auto_arrange_icons) {
1590 wArrangeIcons(scr, True);
1592 #ifdef HIDDENDOT
1593 wAppIconPaint(wapp->app_icon);
1594 #endif
1599 void
1600 wShowAllWindows(WScreen *scr)
1602 WWindow *wwin, *old_foc;
1603 WApplication *wapp;
1605 old_foc = wwin = scr->focused_window;
1606 while (wwin) {
1607 if (!wwin->flags.internal_window &&
1608 (scr->current_workspace == wwin->frame->workspace
1609 || IS_OMNIPRESENT(wwin))) {
1610 if (wwin->flags.miniaturized) {
1611 wwin->flags.skip_next_animation = 1;
1612 wDeiconifyWindow(wwin);
1613 } else if (wwin->flags.hidden) {
1614 wapp = wApplicationOf(wwin->main_window);
1615 if (wapp) {
1616 wUnhideApplication(wapp, False, False);
1617 } else {
1618 wwin->flags.skip_next_animation = 1;
1619 wDeiconifyWindow(wwin);
1623 wwin = wwin->prev;
1625 wSetFocusTo(scr, old_foc);
1626 /*wRaiseFrame(old_foc->frame->core);*/
1630 void
1631 wRefreshDesktop(WScreen *scr)
1633 Window win;
1634 XSetWindowAttributes attr;
1636 attr.backing_store = NotUseful;
1637 attr.save_under = False;
1638 win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width,
1639 scr->scr_height, 0, CopyFromParent, CopyFromParent,
1640 (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
1641 &attr);
1642 XMapRaised(dpy, win);
1643 XDestroyWindow(dpy, win);
1644 XFlush(dpy);
1648 void
1649 wArrangeIcons(WScreen *scr, Bool arrangeAll)
1651 WWindow *wwin;
1652 WAppIcon *aicon;
1653 int pf; /* primary axis */
1654 int sf; /* secondary axis */
1655 int fullW;
1656 int fullH;
1657 int pi, si;
1658 int sx1, sx2, sy1, sy2; /* screen boundary */
1659 int sw, sh;
1660 int xo, yo;
1661 int xs, ys;
1662 int isize = wPreferences.icon_size;
1665 * Find out screen boundaries.
1667 sx1 = 0;
1668 sy1 = 0;
1669 sx2 = scr->scr_width;
1670 sy2 = scr->scr_height;
1671 if (scr->dock) {
1672 if (scr->dock->on_right_side)
1673 sx2 -= isize + DOCK_EXTRA_SPACE;
1674 else
1675 sx1 += isize + DOCK_EXTRA_SPACE;
1678 sw = isize * (scr->scr_width/isize);
1679 sh = isize * (scr->scr_height/isize);
1680 fullW = (sx2-sx1)/isize;
1681 fullH = (sy2-sy1)/isize;
1683 /* icon yard boundaries */
1684 if (wPreferences.icon_yard & IY_VERT) {
1685 pf = fullH;
1686 sf = fullW;
1687 } else {
1688 pf = fullW;
1689 sf = fullH;
1691 if (wPreferences.icon_yard & IY_RIGHT) {
1692 xo = sx2 - isize;
1693 xs = -1;
1694 } else {
1695 xo = sx1;
1696 xs = 1;
1698 if (wPreferences.icon_yard & IY_TOP) {
1699 yo = sy1;
1700 ys = 1;
1701 } else {
1702 yo = sy2 - isize;
1703 ys = -1;
1706 /* arrange icons putting the most recently focused window
1707 * as the last icon */
1708 #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
1709 : xo + xs*(pi*isize))
1710 #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
1711 : yo + ys*(si*isize))
1713 /* arrange application icons */
1714 aicon = scr->app_icon_list;
1715 /* reverse them to avoid unnecessarily sliding of icons */
1716 while (aicon && aicon->next)
1717 aicon = aicon->next;
1719 pi = 0;
1720 si = 0;
1721 while (aicon) {
1722 if (!aicon->docked) {
1723 if (aicon->x_pos != X || aicon->y_pos != Y) {
1724 #ifdef ANIMATIONS
1725 if (!wPreferences.no_animations) {
1726 SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
1727 X, Y);
1729 #endif /* ANIMATIONS */
1731 wAppIconMove(aicon, X, Y);
1732 pi++;
1734 /* we reversed the order so we use prev */
1735 aicon = aicon->prev;
1736 if (pi >= pf) {
1737 pi=0;
1738 si++;
1742 /* arrange miniwindows */
1744 wwin = scr->focused_window;
1745 /* reverse them to avoid unnecessarily shuffling */
1746 while (wwin && wwin->prev)
1747 wwin = wwin->prev;
1749 while (wwin) {
1750 if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
1751 (wwin->frame->workspace==scr->current_workspace ||
1752 IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
1754 if (arrangeAll || !wwin->flags.icon_moved) {
1755 if (wwin->icon_x != X || wwin->icon_y != Y) {
1756 #ifdef ANIMATIONS
1757 if (wPreferences.no_animations) {
1758 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1759 } else {
1760 SlideWindow(wwin->icon->core->window, wwin->icon_x,
1761 wwin->icon_y, X, Y);
1763 #else
1764 XMoveWindow(dpy, wwin->icon->core->window, X, Y);
1765 #endif /* ANIMATIONS */
1767 wwin->icon_x = X;
1768 wwin->icon_y = Y;
1769 pi++;
1772 if (arrangeAll) {
1773 wwin->flags.icon_moved = 0;
1775 /* we reversed the order, so we use next */
1776 wwin = wwin->next;
1777 if (pi >= pf) {
1778 pi=0;
1779 si++;
1785 void
1786 wSelectWindow(WWindow *wwin, Bool flag)
1788 WScreen *scr = wwin->screen_ptr;
1790 if (flag) {
1791 wwin->flags.selected = 1;
1792 XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
1794 if (WFLAGP(wwin, no_border)) {
1795 XSetWindowBorderWidth(dpy, wwin->frame->core->window,
1796 FRAME_BORDER_WIDTH);
1799 if (!scr->selected_windows)
1800 scr->selected_windows = WMCreateBag(4);
1801 WMPutInBag(scr->selected_windows, wwin);
1802 } else {
1803 wwin->flags.selected = 0;
1804 XSetWindowBorder(dpy, wwin->frame->core->window,
1805 scr->frame_border_pixel);
1807 if (WFLAGP(wwin, no_border)) {
1808 XSetWindowBorderWidth(dpy, wwin->frame->core->window, 0);
1811 if (scr->selected_windows) {
1812 WMRemoveFromBag(scr->selected_windows, wwin);
1818 void
1819 wMakeWindowVisible(WWindow *wwin)
1821 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
1822 wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
1824 if (wwin->flags.shaded) {
1825 wUnshadeWindow(wwin);
1827 if (wwin->flags.hidden) {
1828 WApplication *app;
1830 app = wApplicationOf(wwin->main_window);
1831 if (app)
1832 wUnhideApplication(app, False, False);
1833 } else if (wwin->flags.miniaturized) {
1834 wDeiconifyWindow(wwin);
1835 } else {
1836 if (!WFLAGP(wwin, no_focusable))
1837 wSetFocusTo(wwin->screen_ptr, wwin);
1838 wRaiseFrame(wwin->frame->core);