Files
wmaker/src/actions.c
T
Carlos R. Mafra 92eff967a7 Maximus: Consider the full_maximize window attribute
When maximumizing a window which has the full_maximize attribute
set we have to consider two possibilities:

    1. If the new y coordinate is zero it means that no other
       window blocked its maximumization up to the top of the
       screen, so we want to put the titlebar outside.

    2. If the new y coordinate is not zero it means that another
       window in the current workspace blocked its way to y = 0.
       In this case we do nothing with the titlebar.

Note that there is another possible fine tunning which is not
addressed in this patch, which is to consider the resize bar.
2009-09-17 00:46:14 +02:00

2016 lines
50 KiB
C

/* 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 <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
#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();
extern int calcIntersectionLength(int p1, int l1, int p2, int l2);
/******* 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 UNSHADE 0
#define SHADE 1
#define SHADE_STEPS shadePars[(int)wPreferences.shade_speed].steps
#define SHADE_DELAY shadePars[(int)wPreferences.shade_speed].delay
static int compareTimes(Time t1, Time t2)
{
Time diff;
if (t1 == t2)
return 0;
diff = t1 - t2;
return (diff < 60000) ? 1 : -1;
}
/*
*----------------------------------------------------------------------
* 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;
Time timestamp = LastTimestamp;
WApplication *oapp = NULL, *napp = NULL;
int wasfocused;
if (scr->flags.ignore_focus_events || compareTimes(LastFocusChange, timestamp) > 0)
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)
{
if (wwin->flags.shaded)
return;
XLowerWindow(dpy, wwin->client_win);
wSoundPlay(WSOUND_SHADE);
shade_animate(wwin, SHADE);
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)
{
if (!wwin->flags.shaded)
return;
wwin->flags.shaded = 0;
wwin->flags.mapped = 1;
XMapWindow(dpy, wwin->client_win);
wSoundPlay(WSOUND_UNSHADE);
shade_animate(wwin, UNSHADE);
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");
}
/* Set the old coordinates using the current values */
static void save_old_geometry(WWindow *wwin)
{
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;
}
void wMaximizeWindow(WWindow * wwin, int directions)
{
int new_x, new_y;
unsigned int new_width, new_height, half_scr_width;
WArea usableArea, totalArea;
Bool has_border = 1;
int adj_size;
if (!IS_RESIZABLE(wwin))
return;
if (!HAS_BORDER(wwin))
has_border = 0;
/* the size to adjust the geometry */
adj_size = FRAME_BORDER_WIDTH * 2 * has_border;
/* save old coordinates before we change the current values */
save_old_geometry(wwin);
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);
}
/* Only save directions, not kbd or xinerama hints */
directions &= (MAX_HORIZONTAL | MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS);
if (WFLAGP(wwin, full_maximize)) {
usableArea = totalArea;
}
half_scr_width = (usableArea.x2 - usableArea.x1)/2;
if (wwin->flags.shaded) {
wwin->flags.skip_next_animation = 1;
wUnshadeWindow(wwin);
}
if (directions & MAX_HORIZONTAL) {
new_width = usableArea.x2 - usableArea.x1 - adj_size;
new_x = usableArea.x1;
} else if (directions & MAX_LEFTHALF) {
new_width = half_scr_width - adj_size;
new_x = usableArea.x1;
} else if (directions & MAX_RIGHTHALF) {
new_width = half_scr_width - adj_size;
new_x = usableArea.x1 + half_scr_width;
} else {
new_x = wwin->frame_x;
new_width = wwin->frame->core->width;
}
if (directions & MAX_VERTICAL) {
new_height = usableArea.y2 - usableArea.y1 - adj_size;
new_y = usableArea.y1;
if (WFLAGP(wwin, full_maximize)) {
new_y -= wwin->frame->top_width;
new_height += wwin->frame->bottom_width - 1;
}
} 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;
}
if (directions & MAX_MAXIMUS) {
find_Maximus_geometry(wwin, usableArea, &new_x, &new_y, &new_width, &new_height);
if (WFLAGP(wwin, full_maximize) && new_y == 0) {
new_y -= wwin->frame->top_width;
new_height += wwin->frame->top_width - 1;
}
}
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);
/* set maximization state */
wwin->flags.maximized = directions;
}
/*
* Maximus: tiled maximization (maximize without overlapping other windows)
*
* The window to be maximized will be denoted by w_0 (sub-index zero)
* while the windows which will stop the maximization of w_0 are denoted by w_j.
*/
static void find_Maximus_geometry(WWindow *wwin, WArea usableArea, int *new_x, int *new_y,
unsigned int *new_width, unsigned int *new_height)
{
WWindow *tmp;
int x_0 = wwin->frame_x;
int y_0 = wwin->frame_y;
int width_0 = wwin->frame->core->width;
int height_0 = wwin->frame->core->height;
int botton_0 = y_0 + height_0;
int right_border_0 = x_0 + width_0;
int new_x_0, new_y_0, new_botton_0, new_right_border_0, new_height_0;
int x_j, y_j, width_j, height_j, botton_j, top_j, right_border_j;
int x_intsect, y_intsect;
/* Assume that the window w_0 has titlebar etc */
int has_titlebar = 1, has_resizebar = 1, has_border = 1;
int adjust_height, adjust_width;
/* Try to fully maximize first, then readjust later */
new_x_0 = usableArea.x1;
new_y_0 = usableArea.y1;
new_botton_0 = usableArea.y2;
new_right_border_0 = usableArea.x2;
if (!HAS_TITLEBAR(wwin))
has_titlebar = 0;
if (!HAS_RESIZEBAR(wwin))
has_resizebar = 0;
if (!HAS_BORDER(wwin))
has_border = 0;
/* the lengths to be subtracted if w_0 has titlebar, etc */
adjust_height = TITLEBAR_HEIGHT * has_titlebar
+ 2 * FRAME_BORDER_WIDTH * has_border + RESIZEBAR_HEIGHT * has_resizebar;
adjust_width = 2 * FRAME_BORDER_WIDTH * has_border;
tmp = wwin;
/* TODO: Is the focused window always the last in the list? */
while (tmp->prev) {
/* ignore windows in other workspaces or minimized */
if (tmp->prev->frame->workspace != wwin->screen_ptr->current_workspace
|| tmp->prev->flags.miniaturized) {
tmp = tmp->prev;
continue;
}
tmp = tmp->prev;
/* set the w_j window coordinates */
x_j = tmp->frame_x;
y_j = tmp->frame_y;
width_j = tmp->frame->core->width;
height_j = tmp->frame->core->height;
botton_j = y_j + height_j;
top_j = y_j;
right_border_j = x_j + width_j;
/* Try to maximize in the y direction first */
x_intsect = calcIntersectionLength(x_0, width_0, x_j, width_j);
if (x_intsect != 0) {
if (botton_j < y_0 && botton_j > new_y_0) {
/* w_0 is below the botton of w_j */
new_y_0 = botton_j;
}
if (botton_0 < top_j && top_j < new_botton_0) {
/* The botton of w_0 is above the top of w_j */
new_botton_0 = top_j;
}
}
/*
* Use the updated y coordinates from the above step to account
* the possibility that the new value of y_0 will have different
* intersections with w_j
*/
new_height_0 = new_botton_0 - new_y_0 - adjust_height;
y_intsect = calcIntersectionLength(new_y_0, new_height_0, y_j, height_j);
if (y_intsect != 0) {
if (right_border_j < x_0 && right_border_j > new_x_0) {
/* w_0 is completely to the right of w_j */
new_x_0 = right_border_j;
}
if (right_border_0 < x_j && x_j < new_right_border_0) {
/* w_0 is completely to the left of w_j */
new_right_border_0 = x_j;
}
}
}
new_height_0 = new_botton_0 - new_y_0 - adjust_height;
*new_x = new_x_0;
*new_y = new_y_0;
*new_height = new_height_0;
*new_width = new_right_border_0 - new_x_0 - adjust_width;
}
void wUnmaximizeWindow(WWindow * wwin)
{
int x, y, w, h;
WMRect old_geom_rect;
int old_head;
Bool same_head;
if (!wwin->flags.maximized)
return;
if (wwin->flags.shaded) {
wwin->flags.skip_next_animation = 1;
wUnshadeWindow(wwin);
}
/* Use old coordinates if they are set, current values otherwise */
old_geom_rect = wmkrect(wwin->old_geometry.x, wwin->old_geometry.y, wwin->old_geometry.width, wwin->old_geometry.height);
old_head = wGetHeadForRect(wwin->screen_ptr, old_geom_rect);
same_head = (wGetHeadForWindow(wwin) == old_head);
x = (wwin->old_geometry.x && same_head) ? wwin->old_geometry.x : wwin->frame_x;
y = (wwin->old_geometry.y && same_head) ? wwin->old_geometry.y : wwin->frame_y;
w = wwin->old_geometry.width ? wwin->old_geometry.width : wwin->client.width;
h = wwin->old_geometry.height ? wwin->old_geometry.height : wwin->client.height;
wwin->flags.maximized = 0;
wWindowConfigure(wwin, x, y, w, h);
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; j < FRAMES; j++) {
cx[j] = (float)x;
cy[j] = (float)y;
cw[j] = (float)w;
ch[j] = (float)h;
}
XGrabServer(dpy);
for (i = 0; i < steps; i++) {
for (j = 0; j < FRAMES; j++) {
XDrawRectangle(dpy, scr->root_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; j < FRAMES; j++) {
XDrawRectangle(dpy, scr->root_win, scr->frame_gc,
(int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
if (j < FRAMES - 1) {
cx[j] = cx[j + 1];
cy[j] = cy[j + 1];
cw[j] = cw[j + 1];
ch[j] = ch[j + 1];
} else {
cx[j] += xstep;
cy[j] += ystep;
cw[j] += wstep;
ch[j] += hstep;
}
}
}
for (j = 0; j < FRAMES; j++) {
XDrawRectangle(dpy, scr->root_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; j < FRAMES; j++) {
XDrawRectangle(dpy, scr->root_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");
if (wPreferences.auto_arrange_icons)
wArrangeIcons(wwin->screen_ptr, True);
}
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;
int animate;
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;
animate = !wapp->flags.skip_next_animation;
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, animate);
animate = False;
}
}
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;
int animate;
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;
animate = !wapp->flags.skip_next_animation;
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) && wlist->icon) {
if (!wlist->icon->mapped) {
int x, y;
PlaceIcon(scr, &x, &y, wGetHeadForWindow(wlist));
if (wlist->icon_x != x || wlist->icon_y != y) {
XMoveWindow(dpy, wlist->icon->core->window, x, y);
}
wlist->icon_x = x;
wlist->icon_y = y;
XMapWindow(dpy, wlist->icon->core->window);
wlist->icon->mapped = 1;
}
wRaiseFrame(wlist->icon->core);
}
if (bringToCurrentWS)
wWindowChangeWorkspace(wlist, scr->current_workspace);
wlist->flags.hidden = 0;
if (miniwindows && wlist->frame->workspace == scr->current_workspace) {
wDeiconifyWindow(wlist);
}
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, animate, bringToCurrentWS);
animate = False;
} 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 (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);
}
}
/*
* Do the animation while shading (called with what = SHADE)
* or unshading (what = UNSHADE).
*/
#ifdef ANIMATIONS
static void shade_animate(WWindow *wwin, Bool what)
{
int y, s, w, h;
time_t time0 = time(NULL);
if (wwin->flags.skip_next_animation && wPreferences.no_animations)
return;
switch(what) {
case SHADE:
if (!wwin->screen_ptr->flags.startup) {
/* 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);
}
break;
case UNSHADE:
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);
break;
}
}
#else
static void shade_animate(WWindow *wwin, Bool what) { return; }
#endif /* ANIMATIONS */