mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-19 12:28:22 +01:00
This patch is updating the coding style based on checkpatch output and as suggested by Rodolfo it also inverts the condition test in getAnimationGeometry fct to return earlier when possible.
2000 lines
53 KiB
C
2000 lines
53 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
|
|
* Copyright (c) 2014 Window Maker Team
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "framewin.h"
|
|
#include "window.h"
|
|
#include "client.h"
|
|
#include "icon.h"
|
|
#include "colormap.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 "xinerama.h"
|
|
#include "usermenu.h"
|
|
#include "placement.h"
|
|
#include "misc.h"
|
|
#include "event.h"
|
|
|
|
|
|
static void find_Maximus_geometry(WWindow *wwin, WArea usableArea, int *new_x, int *new_y,
|
|
unsigned int *new_width, unsigned int *new_height);
|
|
static void save_old_geometry(WWindow *wwin, int directions);
|
|
|
|
/******* 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;
|
|
}
|
|
|
|
#ifdef ANIMATIONS
|
|
static void shade_animate(WWindow *wwin, Bool what);
|
|
#else
|
|
static inline void shade_animate(WWindow *wwin, Bool what)
|
|
{
|
|
/*
|
|
* This function is empty on purpose, so tell the compiler
|
|
* to not warn about parameters being not used
|
|
*/
|
|
(void) wwin;
|
|
(void) what;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
* 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 = w_global.timestamp.last_event;
|
|
WApplication *oapp = NULL, *napp = NULL;
|
|
int wasfocused;
|
|
|
|
if (scr->flags.ignore_focus_events || compareTimes(w_global.timestamp.focus_change, timestamp) > 0)
|
|
return;
|
|
|
|
if (!old_scr)
|
|
old_scr = scr;
|
|
|
|
old_focused = old_scr->focused_window;
|
|
|
|
w_global.timestamp.focus_change = 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);
|
|
if (wPreferences.highlight_active_app)
|
|
wApplicationDeactivate(oapp);
|
|
}
|
|
|
|
WMPostNotificationName(WMNChangedFocus, NULL, (void *)True);
|
|
return;
|
|
}
|
|
|
|
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->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, w_global.atom.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);
|
|
if (wPreferences.highlight_active_app)
|
|
wApplicationDeactivate(oapp);
|
|
}
|
|
}
|
|
|
|
wWindowFocus(wwin, focused);
|
|
|
|
if (napp && !wasfocused) {
|
|
#ifdef USER_MENU
|
|
wUserMenuRefreshInstances(napp->menu, wwin);
|
|
#endif /* USER_MENU */
|
|
|
|
if (wwin->flags.mapped)
|
|
wAppMenuMap(napp->menu, wwin);
|
|
}
|
|
if (napp && wPreferences.highlight_active_app)
|
|
wApplicationActivate(napp);
|
|
|
|
XFlush(dpy);
|
|
old_scr = scr;
|
|
}
|
|
|
|
void wShadeWindow(WWindow *wwin)
|
|
{
|
|
|
|
if (wwin->flags.shaded)
|
|
return;
|
|
|
|
XLowerWindow(dpy, wwin->client_win);
|
|
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);
|
|
|
|
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);
|
|
|
|
/* 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, int directions)
|
|
{
|
|
/* never been saved? */
|
|
if (!wwin->old_geometry.width)
|
|
directions |= SAVE_GEOMETRY_X | SAVE_GEOMETRY_WIDTH;
|
|
if (!wwin->old_geometry.height)
|
|
directions |= SAVE_GEOMETRY_Y | SAVE_GEOMETRY_HEIGHT;
|
|
|
|
if (directions & SAVE_GEOMETRY_X)
|
|
wwin->old_geometry.x = wwin->frame_x;
|
|
if (directions & SAVE_GEOMETRY_Y)
|
|
wwin->old_geometry.y = wwin->frame_y;
|
|
if (directions & SAVE_GEOMETRY_WIDTH)
|
|
wwin->old_geometry.width = wwin->client.width;
|
|
if (directions & SAVE_GEOMETRY_HEIGHT)
|
|
wwin->old_geometry.height = wwin->client.height;
|
|
}
|
|
|
|
static void remember_geometry(WWindow *wwin, int *x, int *y, int *w, int *h)
|
|
{
|
|
WMRect old_geom_rect;
|
|
int old_head;
|
|
Bool same_head;
|
|
|
|
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 || wwin->old_geometry.width) && same_head) ? wwin->old_geometry.x : wwin->frame_x;
|
|
*y = ((wwin->old_geometry.y || wwin->old_geometry.height) && 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;
|
|
}
|
|
|
|
/* Remember geometry for unmaximizing */
|
|
void update_saved_geometry(WWindow *wwin)
|
|
{
|
|
/* NOT if we aren't already maximized
|
|
* we'll save geometry when maximizing */
|
|
if (!wwin->flags.maximized)
|
|
return;
|
|
|
|
/* NOT if we are fully maximized */
|
|
if ((wwin->flags.maximized & MAX_MAXIMUS) ||
|
|
((wwin->flags.maximized & MAX_HORIZONTAL) &&
|
|
(wwin->flags.maximized & MAX_VERTICAL)))
|
|
return;
|
|
|
|
/* save the co-ordinate in the axis in which we AREN'T maximized */
|
|
if (wwin->flags.maximized & MAX_HORIZONTAL)
|
|
save_old_geometry(wwin, SAVE_GEOMETRY_Y);
|
|
if (wwin->flags.maximized & MAX_VERTICAL)
|
|
save_old_geometry(wwin, SAVE_GEOMETRY_X);
|
|
}
|
|
|
|
void wMaximizeWindow(WWindow *wwin, int directions)
|
|
{
|
|
unsigned int new_width, new_height, half_scr_width, half_scr_height;
|
|
int new_x = 0;
|
|
int new_y = 0;
|
|
int maximus_x = 0;
|
|
int maximus_y = 0;
|
|
unsigned int maximus_width = 0;
|
|
unsigned int maximus_height = 0;
|
|
WArea usableArea, totalArea;
|
|
Bool has_border = 1;
|
|
int adj_size;
|
|
WScreen *scr = wwin->screen_ptr;
|
|
|
|
if (!IS_RESIZABLE(wwin))
|
|
return;
|
|
|
|
if (!HAS_BORDER(wwin))
|
|
has_border = 0;
|
|
|
|
/* the size to adjust the geometry */
|
|
adj_size = scr->frame_border_width * 2 * has_border;
|
|
|
|
/* save old coordinates before we change the current values */
|
|
if (!wwin->flags.maximized)
|
|
save_old_geometry(wwin, SAVE_GEOMETRY_ALL);
|
|
|
|
totalArea.x2 = scr->scr_width;
|
|
totalArea.y2 = scr->scr_height;
|
|
totalArea.x1 = 0;
|
|
totalArea.y1 = 0;
|
|
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_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS);
|
|
|
|
if (WFLAGP(wwin, full_maximize))
|
|
usableArea = totalArea;
|
|
half_scr_width = (usableArea.x2 - usableArea.x1)/2;
|
|
half_scr_height = (usableArea.y2 - usableArea.y1)/2;
|
|
|
|
if (wwin->flags.shaded) {
|
|
wwin->flags.skip_next_animation = 1;
|
|
wUnshadeWindow(wwin);
|
|
}
|
|
|
|
if (directions & MAX_MAXIMUS) {
|
|
find_Maximus_geometry(wwin, usableArea, &maximus_x, &maximus_y, &maximus_width, &maximus_height);
|
|
new_width = maximus_width - adj_size;
|
|
new_height = maximus_height - adj_size;
|
|
new_x = maximus_x;
|
|
new_y = maximus_y;
|
|
if (WFLAGP(wwin, full_maximize) && (new_y == 0)) {
|
|
new_height += wwin->frame->bottom_width - 1;
|
|
new_y -= wwin->frame->top_width;
|
|
}
|
|
|
|
wwin->maximus_x = new_x;
|
|
wwin->maximus_y = new_y;
|
|
wwin->flags.old_maximized |= MAX_MAXIMUS;
|
|
} else {
|
|
/* set default values if no option set then */
|
|
if (!(directions & (MAX_HORIZONTAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS))) {
|
|
new_width = (wwin->old_geometry.width) ? wwin->old_geometry.width : wwin->frame->core->width;
|
|
new_x = (wwin->old_geometry.x) ? wwin->old_geometry.x : wwin->frame_x;
|
|
}
|
|
if (!(directions & (MAX_VERTICAL | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS))) {
|
|
new_height = (wwin->old_geometry.height) ? wwin->old_geometry.height : wwin->frame->core->height;
|
|
new_y = (wwin->old_geometry.y) ? wwin->old_geometry.y : wwin->frame_y;
|
|
}
|
|
|
|
/* left|right position */
|
|
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;
|
|
}
|
|
/* top|bottom position */
|
|
if (directions & MAX_TOPHALF) {
|
|
new_height = half_scr_height - adj_size;
|
|
new_y = usableArea.y1;
|
|
} else if (directions & MAX_BOTTOMHALF) {
|
|
new_height = half_scr_height - adj_size;
|
|
new_y = usableArea.y1 + half_scr_height;
|
|
}
|
|
|
|
/* vertical|horizontal position */
|
|
if (directions & MAX_HORIZONTAL) {
|
|
new_width = usableArea.x2 - usableArea.x1 - adj_size;
|
|
new_x = usableArea.x1;
|
|
}
|
|
if (directions & MAX_VERTICAL) {
|
|
new_height = usableArea.y2 - usableArea.y1 - adj_size;
|
|
new_y = usableArea.y1;
|
|
if (WFLAGP(wwin, full_maximize) && (new_y == 0))
|
|
new_y -= wwin->frame->top_width;
|
|
}
|
|
}
|
|
|
|
if (!WFLAGP(wwin, full_maximize) && !(directions == MAX_MAXIMUS || directions == MAX_HORIZONTAL))
|
|
new_height -= wwin->frame->top_width + wwin->frame->bottom_width;
|
|
|
|
/* set maximization state */
|
|
wwin->flags.maximized = directions;
|
|
if ((wwin->flags.old_maximized & MAX_MAXIMUS) && !wwin->flags.maximized)
|
|
wwin->flags.maximized = MAX_MAXIMUS;
|
|
|
|
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);
|
|
wWindowSynthConfigureNotify(wwin);
|
|
|
|
WMPostNotificationName(WMNChangedState, wwin, "maximize");
|
|
}
|
|
|
|
/* generic (un)maximizer */
|
|
void handleMaximize(WWindow *wwin, int directions)
|
|
{
|
|
int current = wwin->flags.maximized;
|
|
int requested = directions & (MAX_HORIZONTAL | MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS);
|
|
int effective = requested ^ current;
|
|
int flags = directions & ~requested;
|
|
|
|
if (!effective) {
|
|
/* allow wMaximizeWindow to restore the Maximusized size */
|
|
if ((wwin->flags.old_maximized & MAX_MAXIMUS) &&
|
|
!(requested & MAX_MAXIMUS))
|
|
wMaximizeWindow(wwin, MAX_MAXIMUS | flags);
|
|
else
|
|
wUnmaximizeWindow(wwin);
|
|
/* these alone mean vertical|horizontal toggle */
|
|
} else if ((effective == MAX_LEFTHALF) ||
|
|
(effective == MAX_RIGHTHALF) ||
|
|
(effective == MAX_TOPHALF) ||
|
|
(effective == MAX_BOTTOMHALF))
|
|
wUnmaximizeWindow(wwin);
|
|
else {
|
|
if ((requested == (MAX_HORIZONTAL | MAX_VERTICAL)) ||
|
|
(requested == MAX_MAXIMUS))
|
|
effective = requested;
|
|
else {
|
|
if (requested & MAX_LEFTHALF) {
|
|
if (!(requested & (MAX_TOPHALF | MAX_BOTTOMHALF)))
|
|
effective |= MAX_VERTICAL;
|
|
else
|
|
effective |= requested & (MAX_TOPHALF | MAX_BOTTOMHALF);
|
|
effective |= MAX_LEFTHALF;
|
|
effective &= ~(MAX_HORIZONTAL | MAX_RIGHTHALF);
|
|
} else if (requested & MAX_RIGHTHALF) {
|
|
if (!(requested & (MAX_TOPHALF | MAX_BOTTOMHALF)))
|
|
effective |= MAX_VERTICAL;
|
|
else
|
|
effective |= requested & (MAX_TOPHALF | MAX_BOTTOMHALF);
|
|
effective |= MAX_RIGHTHALF;
|
|
effective &= ~(MAX_HORIZONTAL | MAX_LEFTHALF);
|
|
}
|
|
if (requested & MAX_TOPHALF) {
|
|
if (!(requested & (MAX_LEFTHALF | MAX_RIGHTHALF)))
|
|
effective |= MAX_HORIZONTAL;
|
|
else
|
|
effective |= requested & (MAX_LEFTHALF | MAX_RIGHTHALF);
|
|
effective |= MAX_TOPHALF;
|
|
effective &= ~(MAX_VERTICAL | MAX_BOTTOMHALF);
|
|
} else if (requested & MAX_BOTTOMHALF) {
|
|
if (!(requested & (MAX_LEFTHALF | MAX_RIGHTHALF)))
|
|
effective |= MAX_HORIZONTAL;
|
|
else
|
|
effective |= requested & (MAX_LEFTHALF | MAX_RIGHTHALF);
|
|
effective |= MAX_BOTTOMHALF;
|
|
effective &= ~(MAX_VERTICAL | MAX_TOPHALF);
|
|
}
|
|
if (requested & MAX_HORIZONTAL)
|
|
effective &= ~(MAX_LEFTHALF | MAX_RIGHTHALF);
|
|
if (requested & MAX_VERTICAL)
|
|
effective &= ~(MAX_TOPHALF | MAX_BOTTOMHALF);
|
|
effective &= ~MAX_MAXIMUS;
|
|
}
|
|
wMaximizeWindow(wwin, effective | flags);
|
|
}
|
|
}
|
|
|
|
/* the window boundary coordinates */
|
|
typedef struct {
|
|
int left;
|
|
int right;
|
|
int bottom;
|
|
int top;
|
|
int width;
|
|
int height;
|
|
} win_coords;
|
|
|
|
static void set_window_coords(WWindow *wwin, win_coords *obs)
|
|
{
|
|
obs->left = wwin->frame_x;
|
|
obs->top = wwin->frame_y;
|
|
obs->width = wwin->frame->core->width;
|
|
obs->height = wwin->frame->core->height;
|
|
obs->bottom = obs->top + obs->height;
|
|
obs->right = obs->left + obs->width;
|
|
}
|
|
|
|
/*
|
|
* Maximus: tiled maximization (maximize without overlapping other windows)
|
|
*
|
|
* The original window 'orig' will be maximized to new coordinates 'new'.
|
|
* The windows obstructing the maximization of 'orig' are denoted 'obs'.
|
|
*/
|
|
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;
|
|
short int tbar_height_0 = 0, rbar_height_0 = 0, bd_width_0 = 0;
|
|
short int adjust_height;
|
|
int x_intsect, y_intsect;
|
|
/* the obstructing, original and new windows */
|
|
win_coords obs, orig, new;
|
|
|
|
/* set the original coordinate positions of the window to be Maximumized */
|
|
if (wwin->flags.maximized) {
|
|
/* window is already maximized; consider original geometry */
|
|
remember_geometry(wwin, &orig.left, &orig.top, &orig.width, &orig.height);
|
|
orig.bottom = orig.top + orig.height;
|
|
orig.right = orig.left + orig.width;
|
|
} else
|
|
set_window_coords(wwin, &orig);
|
|
|
|
/* Try to fully maximize first, then readjust later */
|
|
new.left = usableArea.x1;
|
|
new.right = usableArea.x2;
|
|
new.top = usableArea.y1;
|
|
new.bottom = usableArea.y2;
|
|
|
|
if (HAS_TITLEBAR(wwin))
|
|
tbar_height_0 = TITLEBAR_HEIGHT;
|
|
if (HAS_RESIZEBAR(wwin))
|
|
rbar_height_0 = RESIZEBAR_HEIGHT;
|
|
if (HAS_BORDER(wwin))
|
|
bd_width_0 = wwin->screen_ptr->frame_border_width;
|
|
|
|
/* the length to be subtracted if the window has titlebar, etc */
|
|
adjust_height = tbar_height_0 + 2 * bd_width_0 + rbar_height_0;
|
|
|
|
tmp = wwin;
|
|
/* The focused window is always the last in the list */
|
|
while (tmp->prev) {
|
|
/* ignore windows in other workspaces etc */
|
|
if (tmp->prev->frame->workspace != w_global.workspace.current ||
|
|
tmp->prev->flags.miniaturized || tmp->prev->flags.hidden) {
|
|
tmp = tmp->prev;
|
|
continue;
|
|
}
|
|
tmp = tmp->prev;
|
|
|
|
/* Set the coordinates of obstructing window */
|
|
set_window_coords(tmp, &obs);
|
|
|
|
/* Try to maximize in the y direction first */
|
|
x_intsect = calcIntersectionLength(orig.left, orig.width, obs.left, obs.width);
|
|
if (x_intsect != 0) {
|
|
/* TODO: Consider the case when coords are equal */
|
|
if (obs.bottom < orig.top && obs.bottom > new.top) {
|
|
/* w_0 is below the bottom of w_j */
|
|
new.top = obs.bottom + 1;
|
|
}
|
|
if (orig.bottom < obs.top && obs.top < new.bottom) {
|
|
/* The bottom of w_0 is above the top of w_j */
|
|
new.bottom = obs.top - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
tmp = wwin;
|
|
while (tmp->prev) {
|
|
if (tmp->prev->frame->workspace != w_global.workspace.current ||
|
|
tmp->prev->flags.miniaturized || tmp->prev->flags.hidden) {
|
|
tmp = tmp->prev;
|
|
continue;
|
|
}
|
|
tmp = tmp->prev;
|
|
|
|
set_window_coords(tmp, &obs);
|
|
|
|
/*
|
|
* Use the new.top and new.height instead of original values
|
|
* as they may have different intersections with the obstructing windows
|
|
*/
|
|
new.height = new.bottom - new.top - adjust_height;
|
|
y_intsect = calcIntersectionLength(new.top, new.height, obs.top, obs.height);
|
|
if (y_intsect != 0) {
|
|
if (obs.right < orig.left && obs.right > new.left) {
|
|
/* w_0 is completely to the right of w_j */
|
|
new.left = obs.right + 1;
|
|
}
|
|
if (orig.right < obs.left && obs.left < new.right) {
|
|
/* w_0 is completely to the left of w_j */
|
|
new.right = obs.left - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
*new_x = new.left;
|
|
*new_y = new.top;
|
|
/* xcalc needs -7 here, but other apps don't */
|
|
*new_height = new.bottom - new.top - adjust_height - 1;
|
|
*new_width = new.right - new.left;
|
|
}
|
|
|
|
void wUnmaximizeWindow(WWindow *wwin)
|
|
{
|
|
int x, y, w, h;
|
|
|
|
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 */
|
|
remember_geometry(wwin, &x, &y, &w, &h);
|
|
|
|
/* unMaximusize relative to original position */
|
|
if (wwin->flags.maximized & MAX_MAXIMUS) {
|
|
x += wwin->frame_x - wwin->maximus_x;
|
|
y += wwin->frame_y - wwin->maximus_y;
|
|
}
|
|
|
|
wwin->flags.maximized = 0;
|
|
wwin->flags.old_maximized = 0;
|
|
wWindowConfigure(wwin, x, y, w, h);
|
|
wWindowSynthConfigureNotify(wwin);
|
|
|
|
WMPostNotificationName(WMNChangedState, wwin, "maximize");
|
|
}
|
|
|
|
void wFullscreenWindow(WWindow *wwin)
|
|
{
|
|
int head;
|
|
WMRect rect;
|
|
|
|
if (wwin->flags.fullscreen)
|
|
return;
|
|
|
|
wwin->flags.fullscreen = True;
|
|
|
|
wWindowConfigureBorders(wwin);
|
|
|
|
ChangeStackingLevel(wwin->frame->core, WMNormalLevel);
|
|
wRaiseFrame(wwin->frame->core);
|
|
|
|
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);
|
|
|
|
wwin->screen_ptr->bfs_focused_window = wwin->screen_ptr->focused_window;
|
|
wSetFocusTo(wwin->screen_ptr, wwin);
|
|
|
|
WMPostNotificationName(WMNChangedState, wwin, "fullscreen");
|
|
}
|
|
|
|
void wUnfullscreenWindow(WWindow *wwin)
|
|
{
|
|
if (!wwin->flags.fullscreen)
|
|
return;
|
|
|
|
wwin->flags.fullscreen = False;
|
|
|
|
if (WFLAGP(wwin, sunken))
|
|
ChangeStackingLevel(wwin->frame->core, WMSunkenLevel);
|
|
else if (WFLAGP(wwin, floating))
|
|
ChangeStackingLevel(wwin->frame->core, WMFloatingLevel);
|
|
|
|
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");
|
|
|
|
if (wwin->screen_ptr->bfs_focused_window) {
|
|
wSetFocusTo(wwin->screen_ptr, wwin->screen_ptr->bfs_focused_window);
|
|
wwin->screen_ptr->bfs_focused_window = NULL;
|
|
}
|
|
}
|
|
|
|
#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);
|
|
wusleep(MINIATURIZE_ANIMATION_DELAY_F);
|
|
|
|
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);
|
|
wusleep(MINIATURIZE_ANIMATION_DELAY_T);
|
|
|
|
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);
|
|
wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
|
|
|
|
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);
|
|
wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
|
|
|
|
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 style = wPreferences.iconification_style; /* Catch the value */
|
|
int steps;
|
|
|
|
if (style == WIS_NONE)
|
|
return;
|
|
|
|
if (style == WIS_RANDOM)
|
|
style = rand() % 3;
|
|
|
|
switch (style) {
|
|
case WIS_TWIST:
|
|
steps = MINIATURIZE_ANIMATION_STEPS_T;
|
|
if (steps > 0)
|
|
animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
|
|
break;
|
|
case WIS_FLIP:
|
|
steps = MINIATURIZE_ANIMATION_STEPS_F;
|
|
if (steps > 0)
|
|
animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
|
|
break;
|
|
case WIS_ZOOM:
|
|
default:
|
|
steps = MINIATURIZE_ANIMATION_STEPS_Z;
|
|
if (steps > 0)
|
|
animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
|
|
break;
|
|
}
|
|
}
|
|
#endif /* ANIMATIONS */
|
|
|
|
static void flushExpose(void)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static int getAnimationGeometry(WWindow *wwin, int *ix, int *iy, int *iw, int *ih)
|
|
{
|
|
if (wwin->screen_ptr->flags.startup || wPreferences.no_animations
|
|
|| wwin->flags.skip_next_animation || wwin->icon == NULL)
|
|
return 0;
|
|
|
|
if (!wPreferences.disable_miniwindows && !wwin->flags.net_handle_icon) {
|
|
*ix = wwin->icon_x;
|
|
*iy = wwin->icon_y;
|
|
*iw = wwin->icon->core->width;
|
|
*ih = wwin->icon->core->height;
|
|
} else {
|
|
if (wwin->flags.net_handle_icon) {
|
|
*ix = wwin->icon_x;
|
|
*iy = wwin->icon_y;
|
|
*iw = wwin->icon_w;
|
|
*ih = wwin->icon_h;
|
|
} else {
|
|
*ix = 0;
|
|
*iy = 0;
|
|
*iw = wwin->screen_ptr->scr_width;
|
|
*ih = wwin->screen_ptr->scr_height;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void wIconifyWindow(WWindow *wwin)
|
|
{
|
|
XWindowAttributes attribs;
|
|
int present;
|
|
|
|
if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs))
|
|
return; /* the window doesn't exist anymore */
|
|
|
|
if (wwin->flags.miniaturized)
|
|
return; /* already miniaturized */
|
|
|
|
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 == w_global.workspace.current;
|
|
|
|
/* 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 && !wwin->flags.net_handle_icon) {
|
|
if (!wwin->flags.icon_moved)
|
|
PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y, wGetHeadForWindow(wwin));
|
|
|
|
wwin->icon = icon_create_for_wwindow(wwin);
|
|
wwin->icon->mapped = 1;
|
|
|
|
/* extract the window screenshot everytime, as the option can be enable anytime */
|
|
if (wwin->client_win && wwin->flags.mapped) {
|
|
RImage *apercu;
|
|
XImage *pimg;
|
|
unsigned int w, h;
|
|
int x, y;
|
|
Window baz;
|
|
|
|
XRaiseWindow(dpy, wwin->frame->core->window);
|
|
XTranslateCoordinates(dpy, wwin->client_win, wwin->screen_ptr->root_win, 0, 0, &x, &y, &baz);
|
|
|
|
w = attribs.width;
|
|
h = attribs.height;
|
|
|
|
if (x - attribs.x + attribs.width > wwin->screen_ptr->scr_width)
|
|
w = wwin->screen_ptr->scr_width - x + attribs.x;
|
|
|
|
if (y - attribs.y + attribs.height > wwin->screen_ptr->scr_height)
|
|
h = wwin->screen_ptr->scr_height - y + attribs.y;
|
|
|
|
pimg = XGetImage(dpy, wwin->client_win, 0, 0, w, h, AllPlanes, ZPixmap);
|
|
if (pimg) {
|
|
apercu = RCreateImageFromXImage(wwin->screen_ptr->rcontext, pimg, NULL);
|
|
XDestroyImage(pimg);
|
|
|
|
if (apercu) {
|
|
set_icon_apercu(wwin->icon, apercu);
|
|
RReleaseImage(apercu);
|
|
} else {
|
|
wwarning("window apercu creation failed");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wwin->flags.miniaturized = 1;
|
|
wwin->flags.mapped = 0;
|
|
|
|
/* unmap transients */
|
|
unmapTransientsFor(wwin);
|
|
|
|
if (present) {
|
|
#ifdef ANIMATIONS
|
|
int ix, iy, iw, ih;
|
|
#endif
|
|
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 || wwin->flags.net_handle_icon)
|
|
wClientSetState(wwin, IconicState, None);
|
|
else
|
|
wClientSetState(wwin, IconicState, wwin->icon->icon_win);
|
|
|
|
flushExpose();
|
|
#ifdef ANIMATIONS
|
|
if (getAnimationGeometry(wwin, &ix, &iy, &iw, &ih))
|
|
animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y,
|
|
wwin->frame->core->width, wwin->frame->core->height, ix, iy, iw, ih);
|
|
#endif
|
|
}
|
|
|
|
wwin->flags.skip_next_animation = 0;
|
|
|
|
if (!wPreferences.disable_miniwindows && !wwin->flags.net_handle_icon) {
|
|
if (w_global.workspace.current == 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
|
|
&& !wwin->flags.net_handle_icon)
|
|
wIconSelect(wwin->icon);
|
|
|
|
WMPostNotificationName(WMNChangedState, wwin, "iconify");
|
|
|
|
if (wPreferences.auto_arrange_icons)
|
|
wArrangeIcons(wwin->screen_ptr, True);
|
|
}
|
|
|
|
void wDeiconifyWindow(WWindow *wwin)
|
|
{
|
|
/* Let's avoid changing workspace while deiconifying */
|
|
w_global.workspace.ignore_change = True;
|
|
|
|
/* we're hiding for show_desktop */
|
|
int netwm_hidden = wwin->flags.net_show_desktop &&
|
|
wwin->frame->workspace != w_global.workspace.current;
|
|
|
|
if (!netwm_hidden)
|
|
wWindowChangeWorkspace(wwin, w_global.workspace.current);
|
|
|
|
if (!wwin->flags.miniaturized) {
|
|
w_global.workspace.ignore_change = False;
|
|
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);
|
|
w_global.workspace.ignore_change = False;
|
|
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 && !wwin->flags.net_handle_icon
|
|
&& wwin->icon != NULL) {
|
|
if (wwin->icon->selected)
|
|
wIconSelect(wwin->icon);
|
|
|
|
XUnmapWindow(dpy, wwin->icon->core->window);
|
|
}
|
|
}
|
|
|
|
/* if the window is in another workspace, do it silently */
|
|
if (!netwm_hidden) {
|
|
#ifdef ANIMATIONS
|
|
int ix, iy, iw, ih;
|
|
if (getAnimationGeometry(wwin, &ix, &iy, &iw, &ih))
|
|
animateResize(wwin->screen_ptr, ix, iy, iw, ih,
|
|
wwin->frame_x, wwin->frame_y,
|
|
wwin->frame->core->width, wwin->frame->core->height);
|
|
#endif
|
|
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
|
|
&& !wwin->flags.net_handle_icon) {
|
|
RemoveFromStackList(wwin->icon->core);
|
|
wSetFocusTo(wwin->screen_ptr, wwin);
|
|
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)) {
|
|
w_global.workspace.ignore_change = False;
|
|
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);
|
|
|
|
w_global.workspace.ignore_change = False;
|
|
}
|
|
|
|
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();
|
|
|
|
#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);
|
|
}
|
|
#endif
|
|
wwin->flags.skip_next_animation = 0;
|
|
|
|
WMPostNotificationName(WMNChangedState, wwin, "hide");
|
|
}
|
|
|
|
void wHideAll(WScreen *scr)
|
|
{
|
|
WWindow *wwin;
|
|
WWindow **windows;
|
|
WMenu *menu;
|
|
unsigned int wcount = 0;
|
|
int i;
|
|
|
|
if (!scr)
|
|
return;
|
|
|
|
menu = scr->switch_menu;
|
|
|
|
windows = wmalloc(sizeof(WWindow *));
|
|
|
|
if (menu != NULL) {
|
|
for (i = 0; i < menu->entry_no; i++) {
|
|
windows[wcount] = (WWindow *) menu->entries[i]->clientdata;
|
|
wcount++;
|
|
windows = wrealloc(windows, sizeof(WWindow *) * (wcount + 1));
|
|
}
|
|
} else {
|
|
wwin = scr->focused_window;
|
|
|
|
while (wwin) {
|
|
windows[wcount] = wwin;
|
|
wcount++;
|
|
windows = wrealloc(windows, sizeof(WWindow *) * (wcount + 1));
|
|
wwin = wwin->prev;
|
|
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < wcount; i++) {
|
|
wwin = windows[i];
|
|
if (wwin->frame->workspace == w_global.workspace.current
|
|
&& !(wwin->flags.miniaturized || wwin->flags.hidden)
|
|
&& !wwin->flags.internal_window
|
|
&& !WFLAGP(wwin, no_miniaturizable)
|
|
) {
|
|
wwin->flags.skip_next_animation = 1;
|
|
wIconifyWindow(wwin);
|
|
}
|
|
}
|
|
|
|
wfree(windows);
|
|
}
|
|
|
|
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 == w_global.workspace.current
|
|
&& !(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, w_global.workspace.current);
|
|
|
|
wwin->flags.hidden = 0;
|
|
|
|
#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);
|
|
}
|
|
#endif
|
|
wwin->flags.skip_next_animation = 0;
|
|
if (w_global.workspace.current == 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 == w_global.workspace.current) && 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, w_global.workspace.current);
|
|
wlist->flags.hidden = 0;
|
|
if (miniwindows && wlist->frame->workspace == w_global.workspace.current)
|
|
wDeiconifyWindow(wlist);
|
|
WMPostNotificationName(WMNChangedState, wlist, "hide");
|
|
} else if (wlist->flags.shaded) {
|
|
if (bringToCurrentWS)
|
|
wWindowChangeWorkspace(wlist, w_global.workspace.current);
|
|
wlist->flags.hidden = 0;
|
|
wRaiseFrame(wlist->frame->core);
|
|
if (wlist->frame->workspace == w_global.workspace.current) {
|
|
XMapWindow(dpy, wlist->frame->core->window);
|
|
if (miniwindows)
|
|
wUnshadeWindow(wlist);
|
|
}
|
|
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 != w_global.workspace.current)
|
|
wWindowChangeWorkspace(wlist, w_global.workspace.current);
|
|
|
|
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 &&
|
|
(w_global.workspace.current == 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) {
|
|
WArea area = wGetUsableAreaForHead(scr, head, NULL, False);
|
|
WMRect rect;
|
|
|
|
if (scr->dock) {
|
|
int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
|
|
|
|
if (scr->dock->on_right_side)
|
|
area.x2 -= offset;
|
|
else
|
|
area.x1 += offset;
|
|
}
|
|
|
|
rect = wmkrect(area.x1, area.y1, area.x2 - area.x1, area.y2 - area.y1);
|
|
|
|
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;
|
|
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 = w_global.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 == w_global.workspace.current ||
|
|
IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
|
|
|
|
head = wGetHeadForWindow(wwin);
|
|
|
|
if (arrangeAll || !wwin->flags.icon_moved) {
|
|
if (wwin->icon_x != X || wwin->icon_y != Y)
|
|
move_window(wwin->icon->core->window, wwin->icon_x, wwin->icon_y, X, Y);
|
|
|
|
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);
|
|
}
|
|
|
|
void wSelectWindow(WWindow *wwin, Bool flag)
|
|
{
|
|
WScreen *scr = wwin->screen_ptr;
|
|
|
|
if (flag) {
|
|
wwin->flags.selected = 1;
|
|
if (wwin->frame->selected_border_pixel)
|
|
XSetWindowBorder(dpy, wwin->frame->core->window, *wwin->frame->selected_border_pixel);
|
|
else
|
|
XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
|
|
|
|
if (!HAS_BORDER(wwin))
|
|
XSetWindowBorderWidth(dpy, wwin->frame->core->window, wwin->screen_ptr->frame_border_width);
|
|
|
|
if (!scr->selected_windows)
|
|
scr->selected_windows = WMCreateArray(4);
|
|
WMAddToArray(scr->selected_windows, wwin);
|
|
} else {
|
|
wwin->flags.selected = 0;
|
|
if (wwin->flags.focused) {
|
|
if (wwin->frame->focused_border_pixel)
|
|
XSetWindowBorder(dpy, wwin->frame->core->window, *wwin->frame->focused_border_pixel);
|
|
else
|
|
XSetWindowBorder(dpy, wwin->frame->core->window, scr->frame_focused_border_pixel);
|
|
} else {
|
|
if (wwin->frame->border_pixel)
|
|
XSetWindowBorder(dpy, wwin->frame->core->window, *wwin->frame->border_pixel);
|
|
else
|
|
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 != w_global.workspace.current)
|
|
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;
|
|
}
|
|
}
|
|
#endif
|