/* action.c- misc. window commands (miniaturize, hide etc.) * * Window Maker window manager * * Copyright (c) 1997-2003 Alfredo K. Kojima * Copyright (c) 1998-2003 Dan Pascu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include "wconfig.h" #include #include #include #include #include #include #include #include "WindowMaker.h" #include "wcore.h" #include "framewin.h" #include "window.h" #include "client.h" #include "icon.h" #include "funcs.h" #include "application.h" #include "actions.h" #include "stacking.h" #include "appicon.h" #include "dock.h" #include "appmenu.h" #include "winspector.h" #include "workspace.h" #include "wsound.h" #include "xinerama.h" /****** Global Variables ******/ extern Time LastTimestamp; extern Time LastFocusChange; extern Cursor wCursor[WCUR_LAST]; extern WPreferences wPreferences; extern Atom _XA_WM_TAKE_FOCUS; extern void ProcessPendingEvents(); /******* Local Variables *******/ static struct { int steps; int delay; } shadePars[5] = { {SHADE_STEPS_UF, SHADE_DELAY_UF}, {SHADE_STEPS_F, SHADE_DELAY_F}, {SHADE_STEPS_M, SHADE_DELAY_M}, {SHADE_STEPS_S, SHADE_DELAY_S}, {SHADE_STEPS_US, SHADE_DELAY_US}}; #define SHADE_STEPS shadePars[(int)wPreferences.shade_speed].steps #define SHADE_DELAY shadePars[(int)wPreferences.shade_speed].delay /* *---------------------------------------------------------------------- * wSetFocusTo-- * Changes the window focus to the one passed as argument. * If the window to focus is not already focused, it will be brought * to the head of the list of windows. Previously focused window is * unfocused. * * Side effects: * Window list may be reordered and the window focus is changed. * *---------------------------------------------------------------------- */ void wSetFocusTo(WScreen *scr, WWindow *wwin) { static WScreen *old_scr=NULL; WWindow *old_focused; WWindow *focused=scr->focused_window; int timestamp=LastTimestamp; WApplication *oapp=NULL, *napp=NULL; int wasfocused; if (scr->flags.ignore_focus_events || LastFocusChange > timestamp) return; if (!old_scr) old_scr=scr; old_focused=old_scr->focused_window; LastFocusChange = timestamp; if (old_focused) oapp = wApplicationOf(old_focused->main_window); if (wwin == NULL) { XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime); if (old_focused) { wWindowUnfocus(old_focused); } if (oapp) { wAppMenuUnmap(oapp->menu); #ifdef NEWAPPICON wApplicationDeactivate(oapp); #endif } WMPostNotificationName(WMNChangedFocus, NULL, (void*)True); return; } else if (old_scr != scr && old_focused) { wWindowUnfocus(old_focused); } wasfocused = wwin->flags.focused; napp = wApplicationOf(wwin->main_window); /* remember last workspace where the app has been */ if (napp) { /*napp->last_workspace = wwin->screen_ptr->current_workspace;*/ napp->last_workspace = wwin->frame->workspace; } if (wwin->flags.mapped && !WFLAGP(wwin, no_focusable)) { /* install colormap if colormap mode is lock mode */ if (wPreferences.colormap_mode==WCM_CLICK) wColormapInstallForWindow(scr, wwin); /* set input focus */ switch (wwin->focus_mode) { case WFM_NO_INPUT: XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime); break; case WFM_PASSIVE: case WFM_LOCALLY_ACTIVE: XSetInputFocus(dpy, wwin->client_win, RevertToParent, CurrentTime); break; case WFM_GLOBALLY_ACTIVE: break; } XFlush(dpy); if (wwin->protocols.TAKE_FOCUS) { wClientSendProtocol(wwin, _XA_WM_TAKE_FOCUS, timestamp); } XSync(dpy, False); } else { XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime); } if (WFLAGP(wwin, no_focusable)) return; /* if this is not the focused window focus it */ if (focused!=wwin) { /* change the focus window list order */ if (wwin->prev) wwin->prev->next = wwin->next; if (wwin->next) wwin->next->prev = wwin->prev; wwin->prev = focused; focused->next = wwin; wwin->next = NULL; scr->focused_window = wwin; if (oapp && oapp != napp) { wAppMenuUnmap(oapp->menu); #ifdef NEWAPPICON wApplicationDeactivate(oapp); #endif } } wWindowFocus(wwin, focused); if (napp && !wasfocused) { #ifdef USER_MENU wUserMenuRefreshInstances(napp->menu, wwin); #endif /* USER_MENU */ if (wwin->flags.mapped) wAppMenuMap(napp->menu, wwin); #ifdef NEWAPPICON wApplicationActivate(napp); #endif } XFlush(dpy); old_scr=scr; } void wShadeWindow(WWindow *wwin) { time_t time0; #ifdef ANIMATIONS int y, s, w, h; #endif if (wwin->flags.shaded) return; time0 = time(NULL); XLowerWindow(dpy, wwin->client_win); wSoundPlay(WSOUND_SHADE); #ifdef ANIMATIONS if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation && !wPreferences.no_animations) { /* do the shading animation */ h = wwin->frame->core->height; s = h/SHADE_STEPS; if (s < 1) s=1; w = wwin->frame->core->width; y = wwin->frame->top_width; while (h>wwin->frame->top_width+1) { XMoveWindow(dpy, wwin->client_win, 0, y); XResizeWindow(dpy, wwin->frame->core->window, w, h); XFlush(dpy); if (time(NULL)-time0 > MAX_ANIMATION_TIME) break; if (SHADE_DELAY > 0) { wusleep(SHADE_DELAY*1000L); } else { wusleep(10); } h-=s; y-=s; } XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width); } #endif /* ANIMATIONS */ wwin->flags.skip_next_animation = 0; wwin->flags.shaded = 1; wwin->flags.mapped = 0; /* prevent window withdrawal when getting UnmapNotify */ XSelectInput(dpy, wwin->client_win, wwin->event_mask & ~StructureNotifyMask); XUnmapWindow(dpy, wwin->client_win); XSelectInput(dpy, wwin->client_win, wwin->event_mask); /* for the client it's just like iconification */ wFrameWindowResize(wwin->frame, wwin->frame->core->width, wwin->frame->top_width - 1); wwin->client.y = wwin->frame_y - wwin->client.height + wwin->frame->top_width; wWindowSynthConfigureNotify(wwin); /* wClientSetState(wwin, IconicState, None); */ WMPostNotificationName(WMNChangedState, wwin, "shade"); #ifdef ANIMATIONS if (!wwin->screen_ptr->flags.startup) { /* Catch up with events not processed while animation was running */ ProcessPendingEvents(); } #endif } void wUnshadeWindow(WWindow *wwin) { time_t time0; #ifdef ANIMATIONS int y, s, w, h; #endif /* ANIMATIONS */ if (!wwin->flags.shaded) return; time0 = time(NULL); wwin->flags.shaded = 0; wwin->flags.mapped = 1; XMapWindow(dpy, wwin->client_win); wSoundPlay(WSOUND_UNSHADE); #ifdef ANIMATIONS if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) { /* do the shading animation */ h = wwin->frame->top_width + wwin->frame->bottom_width; y = wwin->frame->top_width - wwin->client.height; s = abs(y)/SHADE_STEPS; if (s<1) s=1; w = wwin->frame->core->width; XMoveWindow(dpy, wwin->client_win, 0, y); if (s>0) { while (h < wwin->client.height + wwin->frame->top_width + wwin->frame->bottom_width) { XResizeWindow(dpy, wwin->frame->core->window, w, h); XMoveWindow(dpy, wwin->client_win, 0, y); XFlush(dpy); if (SHADE_DELAY > 0) { wusleep(SHADE_DELAY*2000L/3); } else { wusleep(10); } h+=s; y+=s; if (time(NULL)-time0 > MAX_ANIMATION_TIME) break; } } XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width); } #endif /* ANIMATIONS */ wwin->flags.skip_next_animation = 0; wFrameWindowResize(wwin->frame, wwin->frame->core->width, wwin->frame->top_width + wwin->client.height + wwin->frame->bottom_width); wwin->client.y = wwin->frame_y + wwin->frame->top_width; wWindowSynthConfigureNotify(wwin); /* wClientSetState(wwin, NormalState, None); */ /* if the window is focused, set the focus again as it was disabled during * shading */ if (wwin->flags.focused) wSetFocusTo(wwin->screen_ptr, wwin); WMPostNotificationName(WMNChangedState, wwin, "shade"); } void wMaximizeWindow(WWindow *wwin, int directions) { int new_width, new_height, new_x, new_y; int changed_h, changed_v, shrink_h, shrink_v; WArea usableArea, totalArea; if (!IS_RESIZABLE(wwin)) return; totalArea.x1 = 0; totalArea.y1 = 0; totalArea.x2 = wwin->screen_ptr->scr_width; totalArea.y2 = wwin->screen_ptr->scr_height; usableArea = totalArea; if (!(directions & MAX_IGNORE_XINERAMA)) { WScreen *scr = wwin->screen_ptr; int head; if (directions & MAX_KEYBOARD) head = wGetHeadForWindow(wwin); else head = wGetHeadForPointerLocation(scr); usableArea = wGetUsableAreaForHead(scr, head, &totalArea, True); } if (WFLAGP(wwin, full_maximize)) { usableArea = totalArea; } if (wwin->flags.shaded) { wwin->flags.skip_next_animation = 1; wUnshadeWindow(wwin); } /* Only save directions, not kbd or xinerama hints */ directions &= (MAX_HORIZONTAL|MAX_VERTICAL); changed_h = ((wwin->flags.maximized ^ directions) & MAX_HORIZONTAL); changed_v = ((wwin->flags.maximized ^ directions) & MAX_VERTICAL); shrink_h = (changed_h && (directions & MAX_HORIZONTAL)==0); shrink_v = (changed_v && (directions & MAX_VERTICAL)==0); if (wwin->flags.maximized) { /* if already maximized in some direction, we only update the * appropriate old x, old y coordinates. This is necessary to * allow succesive maximizations in different directions without * the need to first do an un-maximize (to avoid flicker). */ if (!(wwin->flags.maximized & MAX_HORIZONTAL)) { wwin->old_geometry.x = wwin->frame_x; } if (!(wwin->flags.maximized & MAX_VERTICAL)) { wwin->old_geometry.y = wwin->frame_y; } } else { wwin->old_geometry.width = wwin->client.width; wwin->old_geometry.height = wwin->client.height; wwin->old_geometry.x = wwin->frame_x; wwin->old_geometry.y = wwin->frame_y; } wwin->flags.maximized = directions; if (directions & MAX_HORIZONTAL) { new_width = (usableArea.x2-usableArea.x1)-FRAME_BORDER_WIDTH*2; new_x = usableArea.x1; } else if (shrink_h) { new_x = wwin->old_geometry.x; new_width = wwin->old_geometry.width; } else { new_x = wwin->frame_x; new_width = wwin->frame->core->width; } if (directions & MAX_VERTICAL) { new_height = (usableArea.y2-usableArea.y1)-FRAME_BORDER_WIDTH*2; new_y = usableArea.y1; if (WFLAGP(wwin, full_maximize)) { new_y -= wwin->frame->top_width; new_height += wwin->frame->bottom_width - 1; } } else if (shrink_v) { new_y = wwin->old_geometry.y; new_height = wwin->old_geometry.height; } else { new_y = wwin->frame_y; new_height = wwin->frame->core->height; } if (!WFLAGP(wwin, full_maximize)) { new_height -= wwin->frame->top_width+wwin->frame->bottom_width; } wWindowConstrainSize(wwin, &new_width, &new_height); wWindowCropSize(wwin, usableArea.x2-usableArea.x1, usableArea.y2-usableArea.y1, &new_width, &new_height); wWindowConfigure(wwin, new_x, new_y, new_width, new_height); WMPostNotificationName(WMNChangedState, wwin, "maximize"); wSoundPlay(WSOUND_MAXIMIZE); } void wUnmaximizeWindow(WWindow *wwin) { int restore_x, restore_y; if (!wwin->flags.maximized) return; if (wwin->flags.shaded) { wwin->flags.skip_next_animation = 1; wUnshadeWindow(wwin); } restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ? wwin->old_geometry.x : wwin->frame_x; restore_y = (wwin->flags.maximized & MAX_VERTICAL) ? wwin->old_geometry.y : wwin->frame_y; wwin->flags.maximized = 0; wWindowConfigure(wwin, restore_x, restore_y, wwin->old_geometry.width, wwin->old_geometry.height); WMPostNotificationName(WMNChangedState, wwin, "maximize"); wSoundPlay(WSOUND_UNMAXIMIZE); } void wFullscreenWindow(WWindow *wwin) { int head; WMRect rect; if (wwin->flags.fullscreen) return; wwin->flags.fullscreen = True; wWindowConfigureBorders(wwin); ChangeStackingLevel(wwin->frame->core, WMFullscreenLevel); wwin->bfs_geometry.x = wwin->frame_x; wwin->bfs_geometry.y = wwin->frame_y; wwin->bfs_geometry.width = wwin->frame->core->width; wwin->bfs_geometry.height = wwin->frame->core->height; head = wGetHeadForWindow(wwin); rect = wGetRectForHead(wwin->screen_ptr, head); wWindowConfigure(wwin, rect.pos.x, rect.pos.y, rect.size.width, rect.size.height); WMPostNotificationName(WMNChangedState, wwin, "fullscreen"); } void wUnfullscreenWindow(WWindow *wwin) { if (!wwin->flags.fullscreen) return; wwin->flags.fullscreen = False; if (wwin->frame->core->stacking->window_level == WMFullscreenLevel) { if (WFLAGP(wwin, sunken)) { ChangeStackingLevel(wwin->frame->core, WMSunkenLevel); } else if (WFLAGP(wwin, floating)) { ChangeStackingLevel(wwin->frame->core, WMFloatingLevel); } else { ChangeStackingLevel(wwin->frame->core, WMNormalLevel); } } wWindowConfigure(wwin, wwin->bfs_geometry.x, wwin->bfs_geometry.y, wwin->bfs_geometry.width, wwin->bfs_geometry.height); wWindowConfigureBorders(wwin); /* // seems unnecessary, but also harmless (doesn't generate flicker) -Dan wFrameWindowPaint(wwin->frame); */ WMPostNotificationName(WMNChangedState, wwin, "fullscreen"); } #ifdef ANIMATIONS static void animateResizeFlip(WScreen *scr, int x, int y, int w, int h, int fx, int fy, int fw, int fh, int steps) { #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F) float cx, cy, cw, ch; float xstep, ystep, wstep, hstep; XPoint points[5]; float dx, dch, midy; float angle, final_angle, delta; xstep = (float)(fx-x)/steps; ystep = (float)(fy-y)/steps; wstep = (float)(fw-w)/steps; hstep = (float)(fh-h)/steps; cx = (float)x; cy = (float)y; cw = (float)w; ch = (float)h; final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F; delta = (float)(final_angle/FRAMES); for (angle=0;; angle+=delta) { if (angle > final_angle) angle = final_angle; dx = (cw/10) - ((cw/5) * sin(angle)); dch = (ch/2) * cos(angle); midy = cy + (ch/2); points[0].x = cx + dx; points[0].y = midy - dch; points[1].x = cx + cw - dx; points[1].y = points[0].y; points[2].x = cx + cw + dx; points[2].y = midy + dch; points[3].x = cx - dx; points[3].y = points[2].y; points[4].x = points[0].x; points[4].y = points[0].y; XGrabServer(dpy); XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin); XFlush(dpy); #if (MINIATURIZE_ANIMATION_DELAY_F > 0) wusleep(MINIATURIZE_ANIMATION_DELAY_F); #else wusleep(10); #endif XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin); XUngrabServer(dpy); cx+=xstep; cy+=ystep; cw+=wstep; ch+=hstep; if (angle >= final_angle) break; } XFlush(dpy); } #undef FRAMES static void animateResizeTwist(WScreen *scr, int x, int y, int w, int h, int fx, int fy, int fw, int fh, int steps) { #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T) float cx, cy, cw, ch; float xstep, ystep, wstep, hstep; XPoint points[5]; float angle, final_angle, a, d, delta; x += w/2; y += h/2; fx += fw/2; fy += fh/2; xstep = (float)(fx-x)/steps; ystep = (float)(fy-y)/steps; wstep = (float)(fw-w)/steps; hstep = (float)(fh-h)/steps; cx = (float)x; cy = (float)y; cw = (float)w; ch = (float)h; final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T; delta = (float)(final_angle/FRAMES); for (angle=0;; angle+=delta) { if (angle > final_angle) angle = final_angle; a = atan(ch/cw); d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2)); points[0].x = cx+cos(angle-a)*d; points[0].y = cy+sin(angle-a)*d; points[1].x = cx+cos(angle+a)*d; points[1].y = cy+sin(angle+a)*d; points[2].x = cx+cos(angle-a+WM_PI)*d; points[2].y = cy+sin(angle-a+WM_PI)*d; points[3].x = cx+cos(angle+a+WM_PI)*d; points[3].y = cy+sin(angle+a+WM_PI)*d; points[4].x = cx+cos(angle-a)*d; points[4].y = cy+sin(angle-a)*d; XGrabServer(dpy); XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin); XFlush(dpy); #if (MINIATURIZE_ANIMATION_DELAY_T > 0) wusleep(MINIATURIZE_ANIMATION_DELAY_T); #else wusleep(10); #endif XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin); XUngrabServer(dpy); cx+=xstep; cy+=ystep; cw+=wstep; ch+=hstep; if (angle >= final_angle) break; } XFlush(dpy); } #undef FRAMES static void animateResizeZoom(WScreen *scr, int x, int y, int w, int h, int fx, int fy, int fw, int fh, int steps) { #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z) float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES]; float xstep, ystep, wstep, hstep; int i, j; xstep = (float)(fx-x)/steps; ystep = (float)(fy-y)/steps; wstep = (float)(fw-w)/steps; hstep = (float)(fh-h)/steps; for (j=0; jroot_win, scr->frame_gc, (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]); } XFlush(dpy); #if (MINIATURIZE_ANIMATION_DELAY_Z > 0) wusleep(MINIATURIZE_ANIMATION_DELAY_Z); #else wusleep(10); #endif for (j=0; jroot_win, scr->frame_gc, (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]); if (jroot_win, scr->frame_gc, (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]); } XFlush(dpy); #if (MINIATURIZE_ANIMATION_DELAY_Z > 0) wusleep(MINIATURIZE_ANIMATION_DELAY_Z); #else wusleep(10); #endif for (j=0; jroot_win, scr->frame_gc, (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]); } XUngrabServer(dpy); } #undef FRAMES void animateResize(WScreen *scr, int x, int y, int w, int h, int fx, int fy, int fw, int fh, int hiding) { int style = wPreferences.iconification_style; /* Catch the value */ int steps, k; if (style == WIS_NONE) return; if (style == WIS_RANDOM) { style = rand()%3; } k = (hiding ? 2 : 3); switch(style) { case WIS_TWIST: steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3; if (steps>0) animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps); break; case WIS_FLIP: steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3; if (steps>0) animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps); break; case WIS_ZOOM: default: steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3; if (steps>0) animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps); break; } } #endif /* ANIMATIONS */ static void flushExpose() { XEvent tmpev; while (XCheckTypedEvent(dpy, Expose, &tmpev)) WMHandleEvent(&tmpev); XSync(dpy, 0); } static void unmapTransientsFor(WWindow *wwin) { WWindow *tmp; tmp = wwin->screen_ptr->focused_window; while (tmp) { /* unmap the transients for this transient */ if (tmp!=wwin && tmp->transient_for == wwin->client_win && (tmp->flags.mapped || wwin->screen_ptr->flags.startup || tmp->flags.shaded)) { unmapTransientsFor(tmp); tmp->flags.miniaturized = 1; if (!tmp->flags.shaded) { wWindowUnmap(tmp); } else { XUnmapWindow(dpy, tmp->frame->core->window); } /* if (!tmp->flags.shaded) */ wClientSetState(tmp, IconicState, None); WMPostNotificationName(WMNChangedState, tmp, "iconify-transient"); } tmp = tmp->prev; } } static void mapTransientsFor(WWindow *wwin) { WWindow *tmp; tmp = wwin->screen_ptr->focused_window; while (tmp) { /* recursively map the transients for this transient */ if (tmp!=wwin && tmp->transient_for == wwin->client_win && /*!tmp->flags.mapped*/ tmp->flags.miniaturized && tmp->icon==NULL) { mapTransientsFor(tmp); tmp->flags.miniaturized = 0; if (!tmp->flags.shaded) { wWindowMap(tmp); } else { XMapWindow(dpy, tmp->frame->core->window); } tmp->flags.semi_focused = 0; /* if (!tmp->flags.shaded) */ wClientSetState(tmp, NormalState, None); WMPostNotificationName(WMNChangedState, tmp, "iconify-transient"); } tmp = tmp->prev; } } #if 0 static void setupIconGrabs(WIcon *icon) { /* setup passive grabs on the icon */ XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True, ButtonPressMask, GrabModeSync, GrabModeAsync, None, None); XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True, ButtonPressMask, GrabModeSync, GrabModeAsync, None, None); XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True, ButtonPressMask, GrabModeSync, GrabModeAsync, None, None); XSync(dpy, 0); } #endif static WWindow* recursiveTransientFor(WWindow *wwin) { int i; if (!wwin) return None; /* hackish way to detect transient_for cycle */ i = wwin->screen_ptr->window_count+1; while (wwin && wwin->transient_for != None && i>0) { wwin = wWindowFor(wwin->transient_for); i--; } if (i==0 && wwin) { wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.", wwin->frame->title); return NULL; } return wwin; } #if 0 static void removeIconGrabs(WIcon *icon) { /* remove passive grabs on the icon */ XUngrabButton(dpy, Button1, AnyModifier, icon->core->window); XUngrabButton(dpy, Button2, AnyModifier, icon->core->window); XUngrabButton(dpy, Button3, AnyModifier, icon->core->window); XSync(dpy, 0); } #endif void wIconifyWindow(WWindow *wwin) { XWindowAttributes attribs; int present; if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) { /* the window doesn't exist anymore */ return; } if (wwin->flags.miniaturized) { return; } if (wwin->transient_for!=None && wwin->transient_for!=wwin->screen_ptr->root_win) { WWindow *owner = wWindowFor(wwin->transient_for); if (owner && owner->flags.miniaturized) return; } present = wwin->frame->workspace==wwin->screen_ptr->current_workspace; /* if the window is in another workspace, simplify process */ if (present) { /* icon creation may take a while */ XGrabPointer(dpy, wwin->screen_ptr->root_win, False, ButtonMotionMask|ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); } if (!wPreferences.disable_miniwindows #ifdef NETWM_HINTS && !wwin->flags.net_handle_icon #endif ) { if (!wwin->flags.icon_moved) { PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y, wGetHeadForWindow(wwin)); } wwin->icon = wIconCreate(wwin); wwin->icon->mapped = 1; } wwin->flags.miniaturized = 1; wwin->flags.mapped = 0; /* unmap transients */ unmapTransientsFor(wwin); if (present) { wSoundPlay(WSOUND_ICONIFY); XUngrabPointer(dpy, CurrentTime); wWindowUnmap(wwin); /* let all Expose events arrive so that we can repaint * something before the animation starts (and the server is grabbed) */ XSync(dpy, 0); if (wPreferences.disable_miniwindows #ifdef NETWM_HINTS || wwin->flags.net_handle_icon #endif ) wClientSetState(wwin, IconicState, None); else wClientSetState(wwin, IconicState, wwin->icon->icon_win); flushExpose(); #ifdef ANIMATIONS if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation && !wPreferences.no_animations) { int ix, iy, iw, ih; if (!wPreferences.disable_miniwindows #ifdef NETWM_HINTS && !wwin->flags.net_handle_icon #endif ) { ix = wwin->icon_x; iy = wwin->icon_y; iw = wwin->icon->core->width; ih = wwin->icon->core->height; } else { #ifdef NETWM_HINTS if (wwin->flags.net_handle_icon) { ix = wwin->icon_x; iy = wwin->icon_y; iw = wwin->icon_w; ih = wwin->icon_h; } else #endif { ix = 0; iy = 0; iw = wwin->screen_ptr->scr_width; ih = wwin->screen_ptr->scr_height; } } animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y, wwin->frame->core->width, wwin->frame->core->height, ix, iy, iw, ih, False); } #endif } wwin->flags.skip_next_animation = 0; if (!wPreferences.disable_miniwindows #ifdef NETWM_HINTS && !wwin->flags.net_handle_icon #endif ) { if (wwin->screen_ptr->current_workspace==wwin->frame->workspace || IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons) XMapWindow(dpy, wwin->icon->core->window); AddToStackList(wwin->icon->core); wLowerFrame(wwin->icon->core); } if (present) { WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window); /* * It doesn't seem to be working and causes button event hangup * when deiconifying a transient window. setupIconGrabs(wwin->icon); */ if ((wwin->flags.focused || (owner && wwin->client_win == owner->client_win)) && wPreferences.focus_mode==WKF_CLICK) { WWindow *tmp; tmp = wwin->prev; while (tmp) { if (!WFLAGP(tmp, no_focusable) && !(tmp->flags.hidden||tmp->flags.miniaturized) && (wwin->frame->workspace == tmp->frame->workspace)) break; tmp = tmp->prev; } wSetFocusTo(wwin->screen_ptr, tmp); } else if (wPreferences.focus_mode!=WKF_CLICK) { wSetFocusTo(wwin->screen_ptr, NULL); } #ifdef ANIMATIONS if (!wwin->screen_ptr->flags.startup) { /* Catch up with events not processed while animation was running */ Window clientwin = wwin->client_win; ProcessPendingEvents(); /* the window can disappear while ProcessPendingEvents() runs */ if (!wWindowFor(clientwin)) { return; } } #endif } /* maybe we want to do this regardless of net_handle_icon * it seems to me we might break behaviour this way. */ if (wwin->flags.selected && !wPreferences.disable_miniwindows #ifdef NETWM_HINTS && !wwin->flags.net_handle_icon #endif ) wIconSelect(wwin->icon); WMPostNotificationName(WMNChangedState, wwin, "iconify"); } void wDeiconifyWindow(WWindow *wwin) { #ifdef NETWM_HINTS /* we're hiding for show_desktop */ int netwm_hidden = wwin->flags.net_show_desktop && wwin->frame->workspace!=wwin->screen_ptr->current_workspace; #else int netwm_hidden = False; #endif if (!netwm_hidden) wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace); if (!wwin->flags.miniaturized) return; if (wwin->transient_for != None && wwin->transient_for != wwin->screen_ptr->root_win) { WWindow *owner = recursiveTransientFor(wwin); if (owner && owner->flags.miniaturized) { wDeiconifyWindow(owner); wSetFocusTo(wwin->screen_ptr, wwin); wRaiseFrame(wwin->frame->core); return; } } wwin->flags.miniaturized = 0; if (!netwm_hidden && !wwin->flags.shaded) { wwin->flags.mapped = 1; } if (!netwm_hidden || wPreferences.sticky_icons) { /* maybe we want to do this regardless of net_handle_icon * it seems to me we might break behaviour this way. */ if (!wPreferences.disable_miniwindows #ifdef NETWM_HINTS && !wwin->flags.net_handle_icon #endif && wwin->icon != NULL) { if (wwin->icon->selected) wIconSelect(wwin->icon); XUnmapWindow(dpy, wwin->icon->core->window); } } if (!netwm_hidden) wSoundPlay(WSOUND_DEICONIFY); /* if the window is in another workspace, do it silently */ if (!netwm_hidden) { #ifdef ANIMATIONS if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations && !wwin->flags.skip_next_animation && wwin->icon != NULL) { int ix, iy, iw, ih; if (!wPreferences.disable_miniwindows #ifdef NETWM_HINTS && !wwin->flags.net_handle_icon #endif ) { ix = wwin->icon_x; iy = wwin->icon_y; iw = wwin->icon->core->width; ih = wwin->icon->core->height; } else { #ifdef NETWM_HINTS if (wwin->flags.net_handle_icon) { ix = wwin->icon_x; iy = wwin->icon_y; iw = wwin->icon_w; ih = wwin->icon_h; } else #endif { ix = 0; iy = 0; iw = wwin->screen_ptr->scr_width; ih = wwin->screen_ptr->scr_height; } } animateResize(wwin->screen_ptr, ix, iy, iw, ih, wwin->frame_x, wwin->frame_y, wwin->frame->core->width, wwin->frame->core->height, False); } #endif /* ANIMATIONS */ wwin->flags.skip_next_animation = 0; XGrabServer(dpy); if (!wwin->flags.shaded) { XMapWindow(dpy, wwin->client_win); } XMapWindow(dpy, wwin->frame->core->window); wRaiseFrame(wwin->frame->core); if (!wwin->flags.shaded) { wClientSetState(wwin, NormalState, None); } mapTransientsFor(wwin); } if (!wPreferences.disable_miniwindows && wwin->icon != NULL #ifdef NETWM_HINTS && !wwin->flags.net_handle_icon #endif ) { RemoveFromStackList(wwin->icon->core); /* removeIconGrabs(wwin->icon);*/ wIconDestroy(wwin->icon); wwin->icon = NULL; } if (!netwm_hidden) { XUngrabServer(dpy); wSetFocusTo(wwin->screen_ptr, wwin); #ifdef ANIMATIONS if (!wwin->screen_ptr->flags.startup) { /* Catch up with events not processed while animation was running */ Window clientwin = wwin->client_win; ProcessPendingEvents(); /* the window can disappear while ProcessPendingEvents() runs */ if (!wWindowFor(clientwin)) { return; } } #endif } if (wPreferences.auto_arrange_icons) { wArrangeIcons(wwin->screen_ptr, True); } WMPostNotificationName(WMNChangedState, wwin, "iconify"); /* In case we were shaded and iconified, also unshade */ if (!netwm_hidden) wUnshadeWindow(wwin); } static void hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate) { if (wwin->flags.miniaturized) { if (wwin->icon) { XUnmapWindow(dpy, wwin->icon->core->window); wwin->icon->mapped = 0; } wwin->flags.hidden = 1; WMPostNotificationName(WMNChangedState, wwin, "hide"); return; } if (wwin->flags.inspector_open) { wHideInspectorForWindow(wwin); } wwin->flags.hidden = 1; wWindowUnmap(wwin); wClientSetState(wwin, IconicState, icon->icon_win); flushExpose(); wSoundPlay(WSOUND_HIDE); #ifdef ANIMATIONS if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations && !wwin->flags.skip_next_animation && animate) { animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y, wwin->frame->core->width, wwin->frame->core->height, icon_x, icon_y, icon->core->width, icon->core->height, True); } #endif wwin->flags.skip_next_animation = 0; WMPostNotificationName(WMNChangedState, wwin, "hide"); } void wHideOtherApplications(WWindow *awin) { WWindow *wwin; WApplication *tapp; if (!awin) return; wwin = awin->screen_ptr->focused_window; while (wwin) { if (wwin!=awin && wwin->frame->workspace == awin->screen_ptr->current_workspace && !(wwin->flags.miniaturized||wwin->flags.hidden) && !wwin->flags.internal_window && wGetWindowOfInspectorForWindow(wwin) != awin && !WFLAGP(wwin, no_hide_others)) { if (wwin->main_window==None || WFLAGP(wwin, no_appicon)) { if (!WFLAGP(wwin, no_miniaturizable)) { wwin->flags.skip_next_animation = 1; wIconifyWindow(wwin); } } else if (wwin->main_window!=None && awin->main_window != wwin->main_window) { tapp = wApplicationOf(wwin->main_window); if (tapp) { tapp->flags.skip_next_animation = 1; wHideApplication(tapp); } else { if (!WFLAGP(wwin, no_miniaturizable)) { wwin->flags.skip_next_animation = 1; wIconifyWindow(wwin); } } } } wwin = wwin->prev; } /* wSetFocusTo(awin->screen_ptr, awin); */ } void wHideApplication(WApplication *wapp) { WScreen *scr; WWindow *wlist; int hadfocus; if (!wapp) { wwarning("trying to hide a non grouped window"); return; } if (!wapp->main_window_desc) { wwarning("group leader not found for window group"); return; } scr = wapp->main_window_desc->screen_ptr; hadfocus = 0; wlist = scr->focused_window; if (!wlist) return; if (wlist->main_window == wapp->main_window) wapp->last_focused = wlist; else wapp->last_focused = NULL; while (wlist) { if (wlist->main_window == wapp->main_window) { if (wlist->flags.focused) { hadfocus = 1; } if (wapp->app_icon) hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos, wapp->app_icon->y_pos, wlist, !wapp->flags.skip_next_animation); } wlist = wlist->prev; } wapp->flags.skip_next_animation = 0; if (hadfocus) { if (wPreferences.focus_mode==WKF_CLICK) { wlist = scr->focused_window; while (wlist) { if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden && (wlist->flags.mapped || wlist->flags.shaded)) break; wlist = wlist->prev; } wSetFocusTo(scr, wlist); } else { wSetFocusTo(scr, NULL); } } wapp->flags.hidden = 1; if(wPreferences.auto_arrange_icons) { wArrangeIcons(scr, True); } #ifdef HIDDENDOT if (wapp->app_icon) wAppIconPaint(wapp->app_icon); #endif } static void unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate, int bringToCurrentWS) { if (bringToCurrentWS) wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace); wwin->flags.hidden=0; wSoundPlay(WSOUND_UNHIDE); #ifdef ANIMATIONS if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations && animate) { animateResize(wwin->screen_ptr, icon_x, icon_y, icon->core->width, icon->core->height, wwin->frame_x, wwin->frame_y, wwin->frame->core->width, wwin->frame->core->height, True); } #endif wwin->flags.skip_next_animation = 0; if (wwin->screen_ptr->current_workspace == wwin->frame->workspace) { XMapWindow(dpy, wwin->client_win); XMapWindow(dpy, wwin->frame->core->window); wClientSetState(wwin, NormalState, None); wwin->flags.mapped=1; wRaiseFrame(wwin->frame->core); } if (wwin->flags.inspector_open) { wUnhideInspectorForWindow(wwin); } WMPostNotificationName(WMNChangedState, wwin, "hide"); } void wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS) { WScreen *scr; WWindow *wlist, *next; WWindow *focused=NULL; Bool shouldArrangeIcons = False; if (!wapp) return; scr = wapp->main_window_desc->screen_ptr; wlist = scr->focused_window; if (!wlist) return; /* goto beginning of list */ while (wlist->prev) wlist = wlist->prev; while (wlist) { next = wlist->next; if (wlist->main_window == wapp->main_window) { if (wlist->flags.focused) focused = wlist; else if (!focused || !focused->flags.focused) focused = wlist; if (wlist->flags.miniaturized) { if (bringToCurrentWS || wPreferences.sticky_icons || wlist->frame->workspace == scr->current_workspace) { if (wlist->icon && !wlist->icon->mapped) { XMapWindow(dpy, wlist->icon->core->window); wlist->icon->mapped = 1; } } if (bringToCurrentWS) wWindowChangeWorkspace(wlist, scr->current_workspace); wlist->flags.hidden = 0; if (miniwindows && wlist->frame->workspace == scr->current_workspace) { wDeiconifyWindow(wlist); } shouldArrangeIcons = True; WMPostNotificationName(WMNChangedState, wlist, "hide"); } else if (wlist->flags.shaded) { if (bringToCurrentWS) wWindowChangeWorkspace(wlist, scr->current_workspace); wlist->flags.hidden = 0; if (wlist->frame->workspace == scr->current_workspace) { XMapWindow(dpy, wlist->frame->core->window); if (miniwindows) { wUnshadeWindow(wlist); wRaiseFrame(wlist->frame->core); } } WMPostNotificationName(WMNChangedState, wlist, "hide"); } else if (wlist->flags.hidden) { unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos, wapp->app_icon->y_pos, wlist, !wapp->flags.skip_next_animation, bringToCurrentWS); } else { if (bringToCurrentWS && wlist->frame->workspace != scr->current_workspace) { wWindowChangeWorkspace(wlist, scr->current_workspace); } wRaiseFrame(wlist->frame->core); } } wlist = next; } wapp->flags.skip_next_animation = 0; wapp->flags.hidden = 0; if (wapp->last_focused && wapp->last_focused->flags.mapped) { wRaiseFrame(wapp->last_focused->frame->core); wSetFocusTo(scr, wapp->last_focused); } else if (focused) { wSetFocusTo(scr, focused); } wapp->last_focused = NULL; if (shouldArrangeIcons || wPreferences.auto_arrange_icons) { wArrangeIcons(scr, True); } #ifdef HIDDENDOT wAppIconPaint(wapp->app_icon); #endif } void wShowAllWindows(WScreen *scr) { WWindow *wwin, *old_foc; WApplication *wapp; old_foc = wwin = scr->focused_window; while (wwin) { if (!wwin->flags.internal_window && (scr->current_workspace == wwin->frame->workspace || IS_OMNIPRESENT(wwin))) { if (wwin->flags.miniaturized) { wwin->flags.skip_next_animation = 1; wDeiconifyWindow(wwin); } else if (wwin->flags.hidden) { wapp = wApplicationOf(wwin->main_window); if (wapp) { wUnhideApplication(wapp, False, False); } else { wwin->flags.skip_next_animation = 1; wDeiconifyWindow(wwin); } } } wwin = wwin->prev; } wSetFocusTo(scr, old_foc); /*wRaiseFrame(old_foc->frame->core);*/ } void wRefreshDesktop(WScreen *scr) { Window win; XSetWindowAttributes attr; attr.backing_store = NotUseful; attr.save_under = False; win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width, scr->scr_height, 0, CopyFromParent, CopyFromParent, (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder, &attr); XMapRaised(dpy, win); XDestroyWindow(dpy, win); XFlush(dpy); } void wArrangeIcons(WScreen *scr, Bool arrangeAll) { WWindow *wwin; WAppIcon *aicon; int head; const int heads = wXineramaHeads(scr); struct HeadVars { int pf; /* primary axis */ int sf; /* secondary axis */ int fullW; int fullH; int pi, si; int sx1, sx2, sy1, sy2; /* screen boundary */ int sw, sh; int xo, yo; int xs, ys; } *vars; int isize = wPreferences.icon_size; vars = (struct HeadVars*)wmalloc(sizeof(struct HeadVars)*heads); for (head = 0; head < heads; ++head) { #if 0 WMRect rect = wGetRectForHead(scr, head); #else WArea area = wGetUsableAreaForHead(scr, head, NULL, False); WMRect rect = wmkrect(area.x1, area.y1, area.x2-area.x1, area.y2-area.y1); #endif vars[head].pi = vars[head].si = 0; vars[head].sx1 = rect.pos.x; vars[head].sy1 = rect.pos.y; vars[head].sw = rect.size.width; vars[head].sh = rect.size.height; vars[head].sx2 = vars[head].sx1 + vars[head].sw; vars[head].sy2 = vars[head].sy1 + vars[head].sh; #if 0 if (scr->dock) { if (scr->dock->on_right_side) vars[head].sx2 -= isize + DOCK_EXTRA_SPACE; else vars[head].sx1 += isize + DOCK_EXTRA_SPACE; } #endif vars[head].sw = isize * (vars[head].sw/isize); vars[head].sh = isize * (vars[head].sh/isize); vars[head].fullW = (vars[head].sx2-vars[head].sx1)/isize; vars[head].fullH = (vars[head].sy2-vars[head].sy1)/isize; /* icon yard boundaries */ if (wPreferences.icon_yard & IY_VERT) { vars[head].pf = vars[head].fullH; vars[head].sf = vars[head].fullW; } else { vars[head].pf = vars[head].fullW; vars[head].sf = vars[head].fullH; } if (wPreferences.icon_yard & IY_RIGHT) { vars[head].xo = vars[head].sx2 - isize; vars[head].xs = -1; } else { vars[head].xo = vars[head].sx1; vars[head].xs = 1; } if (wPreferences.icon_yard & IY_TOP) { vars[head].yo = vars[head].sy1; vars[head].ys = 1; } else { vars[head].yo = vars[head].sy2 - isize; vars[head].ys = -1; } } #define X ((wPreferences.icon_yard & IY_VERT) \ ? vars[head].xo + vars[head].xs*(vars[head].si*isize) \ : vars[head].xo + vars[head].xs*(vars[head].pi*isize)) #define Y ((wPreferences.icon_yard & IY_VERT) \ ? vars[head].yo + vars[head].ys*(vars[head].pi*isize) \ : vars[head].yo + vars[head].ys*(vars[head].si*isize)) /* arrange application icons */ aicon = scr->app_icon_list; /* reverse them to avoid unnecessarily sliding of icons */ while (aicon && aicon->next) aicon = aicon->next; while (aicon) { if (!aicon->docked) { /* CHECK: can icon be NULL here ? */ /* The intention here is to place the AppIcon on the head that * contains most of the applications _main_ window. */ head = wGetHeadForWindow(aicon->icon->owner); if (aicon->x_pos != X || aicon->y_pos != Y) { #ifdef ANIMATIONS if (!wPreferences.no_animations) { SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos, X, Y); } #endif /* ANIMATIONS */ } wAppIconMove(aicon, X, Y); vars[head].pi++; if (vars[head].pi >= vars[head].pf) { vars[head].pi = 0; vars[head].si++; } } aicon = aicon->prev; } /* arrange miniwindows */ wwin = scr->focused_window; /* reverse them to avoid unnecessarily shuffling */ while (wwin && wwin->prev) wwin = wwin->prev; while (wwin) { if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden && (wwin->frame->workspace==scr->current_workspace || IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) { head = wGetHeadForWindow(wwin); if (arrangeAll || !wwin->flags.icon_moved) { if (wwin->icon_x != X || wwin->icon_y != Y) { #ifdef ANIMATIONS if (wPreferences.no_animations) { XMoveWindow(dpy, wwin->icon->core->window, X, Y); } else { SlideWindow(wwin->icon->core->window, wwin->icon_x, wwin->icon_y, X, Y); } #else XMoveWindow(dpy, wwin->icon->core->window, X, Y); #endif /* ANIMATIONS */ } wwin->icon_x = X; wwin->icon_y = Y; vars[head].pi++; if (vars[head].pi >= vars[head].pf) { vars[head].pi = 0; vars[head].si++; } } } if (arrangeAll) { wwin->flags.icon_moved = 0; } /* we reversed the order, so we use next */ wwin = wwin->next; } wfree(vars); } #if 0 void wArrangeIcons(WScreen *scr, Bool arrangeAll) { WWindow *wwin; WAppIcon *aicon; int pf; /* primary axis */ int sf; /* secondary axis */ int fullW; int fullH; int pi, si; int sx1, sx2, sy1, sy2; /* screen boundary */ int sw, sh; int xo, yo; int xs, ys; int isize = wPreferences.icon_size; /* * Find out screen boundaries. */ /* * Allows each head to have miniwindows */ WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr)); sx1 = rect.pos.x; sy1 = rect.pos.y; sw = rect.size.width; sh = rect.size.height; sx2 = sx1 + sw; sy2 = sy1 + sh; if (scr->dock) { if (scr->dock->on_right_side) sx2 -= isize + DOCK_EXTRA_SPACE; else sx1 += isize + DOCK_EXTRA_SPACE; } #if 0 sw = isize * (scr->scr_width/isize); sh = isize * (scr->scr_height/isize); #else sw = isize * (sw/isize); sh = isize * (sh/isize); #endif fullW = (sx2-sx1)/isize; fullH = (sy2-sy1)/isize; /* icon yard boundaries */ if (wPreferences.icon_yard & IY_VERT) { pf = fullH; sf = fullW; } else { pf = fullW; sf = fullH; } if (wPreferences.icon_yard & IY_RIGHT) { xo = sx2 - isize; xs = -1; } else { xo = sx1; xs = 1; } if (wPreferences.icon_yard & IY_TOP) { yo = sy1; ys = 1; } else { yo = sy2 - isize; ys = -1; } /* arrange icons putting the most recently focused window * as the last icon */ #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\ : xo + xs*(pi*isize)) #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\ : yo + ys*(si*isize)) /* arrange application icons */ aicon = scr->app_icon_list; /* reverse them to avoid unnecessarily sliding of icons */ while (aicon && aicon->next) aicon = aicon->next; pi = 0; si = 0; while (aicon) { if (!aicon->docked) { if (aicon->x_pos != X || aicon->y_pos != Y) { #ifdef ANIMATIONS if (!wPreferences.no_animations) { SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos, X, Y); } #endif /* ANIMATIONS */ } wAppIconMove(aicon, X, Y); pi++; } /* we reversed the order so we use prev */ aicon = aicon->prev; if (pi >= pf) { pi=0; si++; } } /* arrange miniwindows */ wwin = scr->focused_window; /* reverse them to avoid unnecessarily shuffling */ while (wwin && wwin->prev) wwin = wwin->prev; while (wwin) { if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden && (wwin->frame->workspace==scr->current_workspace || IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) { if (arrangeAll || !wwin->flags.icon_moved) { if (wwin->icon_x != X || wwin->icon_y != Y) { #ifdef ANIMATIONS if (wPreferences.no_animations) { XMoveWindow(dpy, wwin->icon->core->window, X, Y); } else { SlideWindow(wwin->icon->core->window, wwin->icon_x, wwin->icon_y, X, Y); } #else XMoveWindow(dpy, wwin->icon->core->window, X, Y); #endif /* ANIMATIONS */ } wwin->icon_x = X; wwin->icon_y = Y; pi++; } } if (arrangeAll) { wwin->flags.icon_moved = 0; } /* we reversed the order, so we use next */ wwin = wwin->next; if (pi >= pf) { pi=0; si++; } } } #endif void wSelectWindow(WWindow *wwin, Bool flag) { WScreen *scr = wwin->screen_ptr; if (flag) { wwin->flags.selected = 1; XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel); if (!HAS_BORDER(wwin)) { XSetWindowBorderWidth(dpy, wwin->frame->core->window, FRAME_BORDER_WIDTH); } if (!scr->selected_windows) scr->selected_windows = WMCreateArray(4); WMAddToArray(scr->selected_windows, wwin); } else { wwin->flags.selected = 0; XSetWindowBorder(dpy, wwin->frame->core->window, scr->frame_border_pixel); if (!HAS_BORDER(wwin)) { XSetWindowBorderWidth(dpy, wwin->frame->core->window, 0); } if (scr->selected_windows) { WMRemoveFromArray(scr->selected_windows, wwin); } } } void wMakeWindowVisible(WWindow *wwin) { if (wwin->frame->workspace != wwin->screen_ptr->current_workspace) wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace); if (wwin->flags.shaded) { wUnshadeWindow(wwin); } if (wwin->flags.hidden) { WApplication *app; app = wApplicationOf(wwin->main_window); if (app) { /* trick to get focus to this window */ app->last_focused = wwin; wUnhideApplication(app, False, False); } } if (wwin->flags.miniaturized) { wDeiconifyWindow(wwin); } else { if (!WFLAGP(wwin, no_focusable)) wSetFocusTo(wwin->screen_ptr, wwin); wRaiseFrame(wwin->frame->core); } }