/*
* Copyright © 2005 Novell, Inc.
*
* 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.
*
* Author: David Reveman <davidr@novell.com>
* Reworked by Nigel Cunningham <nigel@suspend2.net>
* Fixes to outline painting and constraining
* code by Danny Baumann <maniac@beryl-project.org>
*
* Parts of this code are taken from metacity and written by
* Eliah Newren, Rob Adams and others
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/cursorfont.h>
#include <beryl.h>
#define ResizeUpMask (1L << 0)
#define ResizeDownMask (1L << 1)
#define ResizeLeftMask (1L << 2)
#define ResizeRightMask (1L << 3)
#define RESIZE_INITIATE_BUTTON_DEFAULT Button2
#define RESIZE_INITIATE_BUTTON_MODIFIERS_DEFAULT CompAltMask
#define RESIZE_OPACITY_DEFAULT 100
#define RESIZE_OPACITY_MIN 1
#define RESIZE_OPACITY_MAX 100
#define RESIZE_OPACIFY_NON_OPAQUE_DEFAULT FALSE
#define RESIZE_OPACITY_DEFAULT 100
#define RESIZE_OPACITY_MIN 1
#define RESIZE_OPACITY_MAX 100
#define RESIZE_OPACIFY_MIN_OPACITY_DEFAULT 80
#define RESIZE_OPACIFY_MIN_OPACITY_MIN 1
#define RESIZE_OPACIFY_MIN_OPACITY_MAX 100
#define RESIZE_SYNC_WINDOW_DEFAULT FALSE
#define RESIZE_WARP_POINTER_DEFAULT FALSE
#define RESIZE_INITIATE_KEY_DEFAULT "F8"
#define RESIZE_INITIATE_KEY_MODIFIERS_DEFAULT CompAltMask
struct _ResizeKeys
{
char *name;
int dx;
int dy;
unsigned int warpMask;
unsigned int resizeMask;
} rKeys[] =
{
{"Left", -1, 0, ResizeLeftMask | ResizeRightMask, ResizeLeftMask},
{"Right", 1, 0, ResizeLeftMask | ResizeRightMask, ResizeRightMask},
{"Up", 0, -1, ResizeUpMask | ResizeDownMask, ResizeUpMask},
{"Down", 0, 1, ResizeUpMask | ResizeDownMask, ResizeDownMask}
};
#define NUM_KEYS (sizeof (rKeys) / sizeof (rKeys[0]))
#define MIN_KEY_WIDTH_INC 24
#define MIN_KEY_HEIGHT_INC 24
#define RESIZE_DISPLAY_OPTION_INITIATE 0
#define RESIZE_DISPLAY_OPTION_OPACITY 1
#define RESIZE_DISPLAY_OPTION_OPACIFY_MIN_OPACITY 2
#define RESIZE_DISPLAY_OPTION_SYNC_WINDOW 3
#define RESIZE_DISPLAY_OPTION_WARP_POINTER 4
#define RESIZE_DISPLAY_OPTION_MODE 5
#define RESIZE_DISPLAY_OPTION_BORDER_COLOR 6
#define RESIZE_DISPLAY_OPTION_FILL_COLOR 7
#define RESIZE_DISPLAY_OPTION_NUM 8
static int displayPrivateIndex;
/* Order is important. In code, we check for > Stretch. */
typedef enum _ResizeMode
{
ResizeModeNormal,
ResizeModeStretch,
ResizeModeOutline,
ResizeModeFilled,
} ResizeMode;
char *resizeModes[] = {
N_("Normal"),
N_("Stretch"),
N_("Outline"),
N_("Filled Outline")
};
#define RESIZE_MODE_DEFAULT ResizeModeNormal
#define NUM_RESIZE_MODES 4
/* Ignore the NumLock and CapsLock keys. */
#define WARP_IGNORE_MASK (~(LockMask | Mod2Mask))
typedef struct _ResizeDisplay
{
CompOption opt[RESIZE_DISPLAY_OPTION_NUM];
int screenPrivateIndex;
HandleEventProc handleEvent;
CompWindow *w;
XWindowAttributes savedAttrib;
int releaseButton;
unsigned int mask;
int width;
int height;
KeyCode key[NUM_KEYS];
int lastWidth;
int lastHeight;
int currentWidth;
int currentHeight;
int currentX;
int currentY;
int xdelta, ydelta; /* Offset when resize started */
int dx_to_apply, dy_to_apply, width_to_apply, height_to_apply;
int right_edge, bottom_edge;
GLushort resizeOpacity;
GLushort opacifyMinOpacity;
int resizeMode;
Bool ungrabPending;
GLushort border[4];
GLushort fill[4];
} ResizeDisplay;
typedef struct _ResizeScreen
{
int grabIndex;
Bool painted;
int x, y;
PaintWindowProc paintWindow;
PreparePaintScreenProc preparePaintScreen;
PaintScreenProc paintScreen;
PaintTransformedScreenProc paintTransformedScreen;
DonePaintScreenProc donePaintScreen;
Cursor leftCursor;
Cursor rightCursor;
Cursor upCursor;
Cursor upLeftCursor;
Cursor upRightCursor;
Cursor downCursor;
Cursor downLeftCursor;
Cursor downRightCursor;
Cursor middleCursor;
Cursor cursor[NUM_KEYS];
} ResizeScreen;
#define GET_RESIZE_DISPLAY(d) \
((ResizeDisplay *) (d)->privates[displayPrivateIndex].ptr)
#define RESIZE_DISPLAY(d) \
ResizeDisplay *rd = GET_RESIZE_DISPLAY (d)
#define GET_RESIZE_SCREEN(s) \
((ResizeScreen *) (s)->privates[(GET_RESIZE_DISPLAY(s->display))->screenPrivateIndex].ptr)
#define RESIZE_SCREEN(s) ResizeScreen *rs = GET_RESIZE_SCREEN(s)
#define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
static void resizeUpdateWindowRealSize(CompDisplay * d, int move_only)
{
RESIZE_DISPLAY(d);
XWindowChanges xwc;
unsigned int xwcm = 0;
if (!rd->w || rd->w->syncWait)
return;
if (move_only)
{
moveWindow(rd->w, rd->currentX - rd->w->attrib.x,
rd->currentY - rd->w->attrib.y, TRUE, TRUE);
syncWindowPosition(rd->w);
}
else
{
if (rd->currentX != rd->w->serverX)
xwcm |= CWX;
if (rd->currentY != rd->w->serverY)
xwcm |= CWY;
if (rd->currentWidth != rd->w->serverWidth)
xwcm |= CWWidth;
if (rd->currentHeight != rd->w->serverHeight)
xwcm |= CWHeight;
xwc.x = rd->currentX;
xwc.y = rd->currentY;
xwc.width = rd->currentWidth;
xwc.height = rd->currentHeight;
if (rd->resizeMode == ResizeModeNormal
&& rd->opt[RESIZE_DISPLAY_OPTION_SYNC_WINDOW].value.b)
sendSyncRequest(rd->w);
configureXWindow(rd->w, xwcm, &xwc);
}
}
#define CLAMP(v, min, max) ((v) <= (min) ? (min) : (v) >= (max) ? (max) : (v))
static void
resizeConstrainMinMax(CompWindow * w,
int width, int height, int *newWidth, int *newHeight)
{
const XSizeHints *hints = &w->sizeHints;
int min_width = 0;
int min_height = 0;
int max_width = MAXSHORT;
int max_height = MAXSHORT;
if ((hints->flags & PBaseSize) && (hints->flags & PMinSize))
{
min_width = hints->min_width;
min_height = hints->min_height;
}
else if (hints->flags & PBaseSize)
{
min_width = hints->base_width;
min_height = hints->base_height;
}
else if (hints->flags & PMinSize)
{
min_width = hints->min_width;
min_height = hints->min_height;
}
if (hints->flags & PMaxSize)
{
max_width = hints->max_width;
max_height = hints->max_height;
}
/* clamp width and height to min and max values */
width = CLAMP(width, min_width, max_width);
height = CLAMP(height, min_height, max_height);
*newWidth = width;
*newHeight = height;
}
static void
resizeConstrainResizeIncrement(CompWindow * w, int width, int height, int *newWidth, int *newHeight)
{
int baseWidth, baseHeight;
const XSizeHints *hints = &w->sizeHints;
if (hints->flags & PResizeInc) {
if (hints->flags & PBaseSize) {
baseWidth = hints->base_width;
baseHeight = hints->base_height;
} else {
baseWidth = 0;
baseHeight = 0;
}
if ((width - baseWidth) % hints->width_inc)
width = baseWidth + (((width - baseWidth) / hints->width_inc) * hints->width_inc);
if ((height - baseHeight) % hints->height_inc)
height = baseHeight + (((height - baseHeight) / hints->height_inc) * hints->height_inc);
}
*newWidth = width;
*newHeight = height;
}
/* this code has its origin in metacity's boxes.c - thanks! */
static void
resizeFindLinePointClosestToPoint (double x1, double y1,
double x2, double y2, double px, double py, double *valx, double *valy)
{
/* I'll use the shorthand rx, ry for the return values, valx & valy.
* Now, we need (rx,ry) to be on the line between (x1,y1) and (x2,y2).
* For that to happen, we first need the slope of the line from (x1,y1)
* to (rx,ry) must match the slope of (x1,y1) to (x2,y2), i.e.:
* (ry-y1) (y2-y1)
* ------- = -------
* (rx-x1) (x2-x1)
* If x1==x2, though, this gives divide by zero errors, so we want to
* rewrite the equation by multiplying both sides by (rx-x1)*(x2-x1):
* (ry-y1)(x2-x1) = (y2-y1)(rx-x1)
* This is a valid requirement even when x1==x2 (when x1==x2, this latter
* equation will basically just mean that rx must be equal to both x1 and
* x2)
*
* The other requirement that we have is that the line from (rx,ry) to
* (px,py) must be perpendicular to the line from (x1,y1) to (x2,y2). So
* we just need to get a vector in the direction of each line, take the
* dot product of the two, and ensure that the result is 0:
* (rx-px)*(x2-x1) + (ry-py)*(y2-y1) = 0.
*
* This gives us two equations and two unknowns:
*
* (ry-y1)(x2-x1) = (y2-y1)(rx-x1)
* (rx-px)*(x2-x1) + (ry-py)*(y2-y1) = 0.
*
* This particular pair of equations is always solvable so long as
* (x1,y1) and (x2,y2) are not the same point (and note that anyone who
* calls this function that way is braindead because it means that they
* really didn't specify a line after all). However, the caller should
* be careful to avoid making (x1,y1) and (x2,y2) too close (e.g. like
* 10^{-8} apart in each coordinate), otherwise roundoff error could
* cause issues. Solving these equations by hand (or using Maple(TM) or
* Mathematica(TM) or whatever) results in slightly messy expressions,
* but that's all the below few lines do.
*/
double diffx, diffy, den;
diffx = x2 - x1;
diffy = y2 - y1;
den = diffx * diffx + diffy * diffy;
*valx = (py * diffx * diffy + px * diffx * diffx +
y2 * x1 * diffy - y1 * x2 * diffy) / den;
*valy = (px * diffx * diffy + py * diffy * diffy +
x2 * y1 * diffx - x1 * y2 * diffx) / den;
}
/* this function is heavily inspired by metacity's
constrain_aspect_ratio - thanks another time! */
static Bool
resizeConstrainAspectRatio(CompWindow * w, int width, int height, int *retWidth, int *retHeight)
{
RESIZE_DISPLAY(w->screen->display);
const XSizeHints *hints = &w->sizeHints;
double minRatio, maxRatio;
int newWidth, newHeight;
double altWidth, altHeight;
double bestWidth, bestHeight;
int tolerance = 1;
Bool resizeLeftRight = FALSE;
Bool resizeUpDown = FALSE;
newWidth = width;
newHeight = height;
if (hints->flags & PAspect) {
minRatio = hints->min_aspect.x / (double) hints->min_aspect.y;
maxRatio = hints->max_aspect.x / (double) hints->max_aspect.y;
if (minRatio > maxRatio)
return FALSE;
resizeLeftRight = (rd->mask == (rd->mask & ResizeLeftMask)) ||
(rd->mask == (rd->mask & ResizeRightMask));
resizeUpDown = (rd->mask == (rd->mask & ResizeUpMask)) ||
(rd->mask == (rd->mask & ResizeDownMask));
if (resizeLeftRight || resizeUpDown)
tolerance = 2;
/* return if constraint already is satisfied */
if (((width - (height * minRatio)) > (-minRatio * tolerance)) &&
((width - (height * maxRatio)) < (maxRatio * tolerance)))
{
return FALSE;
}
if (resizeLeftRight)
newHeight = CLAMP (newHeight, newWidth / maxRatio, newWidth / minRatio);
else if (resizeUpDown)
newWidth = CLAMP (newWidth, newHeight * minRatio, newHeight * maxRatio);
else {
altWidth = CLAMP (newWidth, newHeight * minRatio, newHeight * maxRatio);
altHeight = CLAMP (newHeight, newWidth / maxRatio, newWidth / minRatio);
resizeFindLinePointClosestToPoint(altWidth, newHeight, newWidth, altHeight,
newWidth, newHeight, &bestWidth, &bestHeight);
newWidth = bestWidth;
newHeight = bestHeight;
}
}
*retWidth = newWidth;
*retHeight = newHeight;
return TRUE;
}
#undef CLAMP
static void resizeApply(CompDisplay * d)
{
int move_only = 0, cw, ch;
RESIZE_DISPLAY(d);
if ((!rd->dx_to_apply && !rd->dy_to_apply) || rd->w->syncWait)
return;
/* Move window by delta if resizing from left/top */
if (rd->mask & ResizeLeftMask && rd->width_to_apply != rd->currentWidth)
rd->currentX += rd->dx_to_apply;
if (rd->mask & ResizeUpMask && rd->height_to_apply != rd->currentHeight)
rd->currentY += rd->dy_to_apply;
cw = rd->currentWidth = rd->width_to_apply;
ch = rd->currentHeight = rd->height_to_apply;
rd->dx_to_apply = rd->dy_to_apply = 0;
constrainNewWindowSize(rd->w, rd->currentWidth, rd->currentHeight,
&cw, &ch);
if (rd->mask & ResizeLeftMask)
rd->currentX = rd->right_edge - cw;
if (rd->mask & ResizeUpMask)
rd->currentY = rd->bottom_edge - ch;
rd->currentWidth = cw;
rd->currentHeight = ch;
switch (rd->resizeMode)
{
case ResizeModeStretch:
move_only = 1;
case ResizeModeNormal:
resizeUpdateWindowRealSize(d, move_only);
}
if (rd->resizeMode != ResizeModeNormal)
resizeWindowPreview (rd->w, rd->currentX, rd->currentY,
rd->currentWidth, rd->currentHeight);
}
static void resizeUpdateWindowSize(CompDisplay * d, int dx, int dy)
{
int w, h, new_height, new_width;
RESIZE_DISPLAY(d);
if (!rd->w)
return;
if (rd->resizeMode != ResizeModeNormal)
damageScreen(rd->w->screen);
if (rd->w->state & CompWindowStateMaximizedVertMask)
rd->currentHeight = rd->w->serverHeight;
if (rd->w->state & CompWindowStateMaximizedHorzMask)
rd->currentWidth = rd->w->serverWidth;
if (rd->w->state & CompWindowStateMaximizedVertMask &&
rd->w->state & CompWindowStateMaximizedHorzMask)
return;
w = rd->currentWidth;
h = rd->currentHeight;
/* Ensure we don't push the window if constraints stop it being
* resized. */
if (!(rd->mask & (ResizeLeftMask | ResizeRightMask)))
dx = 0;
if (!(rd->mask & (ResizeUpMask | ResizeDownMask)))
dy = 0;
/* Apply the width/height modifications */
if (rd->mask & ResizeLeftMask)
w -= dx;
else if (rd->mask & ResizeRightMask)
w += dx;
if (rd->mask & ResizeUpMask)
h -= dy;
else if (rd->mask & ResizeDownMask)
h += dy;
/* Apply constraints */
resizeConstrainResizeIncrement(rd->w, w, h, &w, &h);
new_width = w;
new_height = h;
resizeConstrainAspectRatio(rd->w, w, h, &new_width, &new_height);
resizeConstrainMinMax(rd->w, new_width, new_height, &new_width, &new_height);
if ((w != new_width) || (h != new_height))
{
/* if the resizing hit constraints, move the mouse
pointer to the new border to avoid desynchronization */
int pointerAdjustX = 0, pointerAdjustY = 0;
if (rd->mask & ResizeRightMask)
pointerAdjustX = new_width - w;
else if (rd->mask & ResizeLeftMask)
pointerAdjustX = w - new_width;
if (rd->mask & ResizeDownMask)
pointerAdjustY = new_height - h;
else if (rd->mask & ResizeUpMask)
pointerAdjustY = h - new_height;
warpPointer(d, pointerAdjustX, pointerAdjustY);
}
dx -= new_width - w;
dy -= new_height - h;
/* Avoid annoying jiggling if we try to move 1 pixel */
if (abs(dx) < 2)
dx = 0;
if (abs(dy) < 2)
dy = 0;
/* If no resizing, drop out now. */
if (!dx && !dy)
return;
rd->dx_to_apply = dx;
rd->dy_to_apply = dy;
rd->width_to_apply = new_width;
rd->height_to_apply = new_height;
resizeApply(d);
}
static Bool
resizeInitiate(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompWindow *w;
ResizeScreen *rs;
Window xid;
unsigned int mods;
unsigned int mask;
int x, y;
int button;
RESIZE_DISPLAY(d);
xid = getIntOptionNamed(option, nOption, "window", 0);
w = findWindowAtDisplay(d, xid);
if (!w)
return FALSE;
rs = GET_RESIZE_SCREEN(w->screen);
rd->dx_to_apply = rd->dy_to_apply = 0;
mods = getIntOptionNamed(option, nOption, "modifiers", 0);
x = getIntOptionNamed(option, nOption, "x", w->attrib.x + (w->width / 2));
y = getIntOptionNamed(option, nOption, "y",
w->attrib.y + (w->height / 2));
button = getIntOptionNamed(option, nOption, "button", -1);
mask = getIntOptionNamed(option, nOption, "direction", 0);
/* Initiate the resize in the direction suggested by the
* quarter of the window the mouse is in, eg drag in top left
* will resize up and to the left. Keyboard resize starts out
* with the cursor in the middle of the window and then starts
* resizing the edge corresponding to the next key press. */
if (state & CompActionStateInitKey)
mask = 0;
else if (!mask)
{
mask |= ((x - w->attrib.x) < (w->width / 2)) ?
ResizeLeftMask : ResizeRightMask;
mask |= ((y - w->attrib.y) < (w->height / 2)) ?
ResizeUpMask : ResizeDownMask;
}
if (otherScreenGrabExist(w->screen, "resize", 0))
return FALSE;
if (rd->w)
return FALSE;
if (w->type & (CompWindowTypeDesktopMask |
CompWindowTypeDockMask | CompWindowTypeFullscreenMask))
return FALSE;
if (w->attrib.override_redirect)
return FALSE;
if (state & CompActionStateInitButton)
action->state |= CompActionStateTermButton;
if (w->shaded)
mask &= ~(ResizeUpMask | ResizeDownMask);
rd->w = w;
rd->mask = mask;
rd->currentWidth = rd->width = w->serverWidth;
rd->currentHeight = rd->height = w->serverHeight;
rd->currentX = w->attrib.x;
rd->currentY = w->attrib.y;
rd->savedAttrib = w->attrib;
rd->right_edge = rd->currentX + rd->currentWidth;
rd->bottom_edge = rd->currentY + rd->currentHeight;
rd->xdelta = rd->ydelta = 0;
if (rd->resizeMode != ResizeModeNormal)
rd->lastWidth = rd->lastHeight = 0.0f;
else
addWindowDamage(rd->w);
d->lastPointerX = x;
d->lastPointerY = y;
if (!rs->grabIndex)
{
Cursor cursor;
if (state & CompActionStateInitKey)
cursor = rs->middleCursor;
else if (mask & ResizeLeftMask)
{
if (mask & ResizeDownMask)
cursor = rs->downLeftCursor;
else if (mask & ResizeUpMask)
cursor = rs->upLeftCursor;
else
cursor = rs->leftCursor;
}
else if (mask & ResizeRightMask)
{
if (mask & ResizeDownMask)
cursor = rs->downRightCursor;
else if (mask & ResizeUpMask)
cursor = rs->upRightCursor;
else
cursor = rs->rightCursor;
}
else if (mask & ResizeUpMask)
cursor = rs->upCursor;
else
cursor = rs->downCursor;
rs->grabIndex = pushScreenGrab(w->screen, cursor, "resize");
}
if (rs->grabIndex)
{
int mods_sought = virtualToRealModMask(d,
rd->
opt
[RESIZE_DISPLAY_OPTION_INITIATE].
value.action.button.modifiers);
int button_sought =
rd->opt[RESIZE_DISPLAY_OPTION_INITIATE].value.action.
button.button;
rd->releaseButton = button;
/* FIXME: we use CompWindowGrabButtonMask only for the normal mode
to prevent wobbling for the other modes
this is fine for now, but may break the API (documentation would be nice...) */
Bool wobbleDesired = (rd->resizeMode == ResizeModeNormal);
wobbleDesired |= (!(mask & ~(ResizeUpMask | ResizeDownMask))) &&
(w->state & CompWindowStateMaximizedVertMask);
wobbleDesired |= (!(mask & ~(ResizeLeftMask | ResizeRightMask))) &&
(w->state & CompWindowStateMaximizedHorzMask);
(w->screen->windowGrabNotify) (w, x, y, state,
CompWindowGrabResizeMask |
(wobbleDesired ?
CompWindowGrabButtonMask : 0));
if (state & CompActionStateInitKey)
{
x = w->attrib.x + (w->width / 2);
y = w->attrib.y + (w->height / 2);
warpPointer(d, x - d->pointerX, y - d->pointerY);
}
else if ((mods & WARP_IGNORE_MASK) == mods_sought &&
button == button_sought &&
rd->opt[RESIZE_DISPLAY_OPTION_WARP_POINTER].value.b)
{
/* May warp if initiated with mouse combo */
x = w->attrib.x - w->input.left +
((mask & ResizeLeftMask) ? 0 : rd->width +
w->input.left + w->input.right);
y = w->attrib.y - w->input.top +
((mask & ResizeUpMask) ? 0 : rd->height +
w->input.top + w->input.bottom);
warpPointer(d, x - d->pointerX, y - d->pointerY);
}
rd->xdelta = (x - rd->currentX);
if (rd->mask & ResizeRightMask)
rd->xdelta = rd->width - rd->xdelta;
rd->ydelta = (y - rd->currentY);
if (rd->mask & ResizeDownMask)
rd->ydelta = rd->height - rd->ydelta;
}
return FALSE;
}
static Bool
resizeTerminate(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
RESIZE_DISPLAY(d);
ResizeScreen *rs;
action->state &= ~(CompActionStateTermKey | CompActionStateTermButton);
if (!rd->w)
return FALSE;
rs = GET_RESIZE_SCREEN(rd->w->screen);
if (state & CompActionStateCancel)
{
XWindowChanges xwc;
sendSyncRequest(rd->w);
xwc.x = rd->savedAttrib.x;
xwc.y = rd->savedAttrib.y;
xwc.width = rd->savedAttrib.width;
xwc.height = rd->savedAttrib.height;
if ((xwc.x != rd->w->serverX) || (xwc.y != rd->w->serverY) ||
(xwc.width != rd->w->serverWidth) || (xwc.height != rd->w->serverHeight))
{
rd->ungrabPending = TRUE;
} else {
(rd->w->screen->windowUngrabNotify) (rd->w);
}
configureXWindow(rd->w, CWX | CWY | CWWidth | CWHeight, &xwc);
} else if (rd->resizeMode != ResizeModeNormal
&& (rd->currentX != rd->w->serverX
|| rd->currentY != rd->w->serverY
|| rd->currentWidth != rd->w->serverWidth
|| rd->currentHeight != rd->w->serverHeight)) {
rd->ungrabPending = TRUE;
resizeUpdateWindowRealSize(d, 0);
} else {
syncWindowPosition(rd->w);
(rd->w->screen->windowUngrabNotify) (rd->w);
}
if (rs->grabIndex)
{
removeScreenGrab(rd->w->screen, rs->grabIndex, NULL);
rs->grabIndex = 0;
}
addWindowDamage(rd->w);
if (rd->resizeMode != ResizeModeNormal)
damageScreen(rd->w->screen);
if (!rd->ungrabPending)
rd->w = NULL;
rd->releaseButton = 0;
return FALSE;
}
static void resizeHandleKeyEvent(CompScreen * s, KeyCode keycode)
{
RESIZE_SCREEN(s);
RESIZE_DISPLAY(s->display);
if (rs->grabIndex && rd->w)
{
CompWindow *w;
int i, widthInc, heightInc;
w = rd->w;
widthInc = w->sizeHints.width_inc;
heightInc = w->sizeHints.height_inc;
/* if the resize increment hint is smaller than our
minimum amount, then resize by the next multiple
of the hint value large than our minimum */
if (widthInc < MIN_KEY_WIDTH_INC)
widthInc = ((MIN_KEY_WIDTH_INC / widthInc) + 1) * widthInc;
if (heightInc < MIN_KEY_HEIGHT_INC)
heightInc = ((MIN_KEY_HEIGHT_INC / heightInc) + 1) * heightInc;
for (i = 0; i < NUM_KEYS; i++)
{
if (keycode != rd->key[i])
continue;
if (rd->mask & rKeys[i].warpMask)
XWarpPointer(s->display->display, None,
None, 0, 0, 0, 0,
rKeys[i].dx * widthInc, rKeys[i].dy * heightInc);
else
{
int x, y, left, top, width, height;
left = w->attrib.x - w->input.left;
top = w->attrib.y - w->input.top;
width = w->input.left + w->serverWidth + w->input.right;
height = w->input.top + w->serverHeight + w->input.bottom;
x = left + width * (rKeys[i].dx + 1) / 2;
y = top + height * (rKeys[i].dy + 1) / 2;
rd->mask = rKeys[i].resizeMask;
/* recalculate delta */
rd->xdelta = (x - rd->currentX);
if (rd->mask & ResizeRightMask)
rd->xdelta = rd->width - rd->xdelta;
rd->ydelta = (y - rd->currentY);
if (rd->mask & ResizeDownMask)
rd->ydelta = rd->height - rd->ydelta;
warpPointer(s->display,
x - s->display->pointerX,
y - s->display->pointerY);
updateScreenGrab(s, rs->grabIndex, rs->cursor[i]);
}
break;
}
}
}
static void resizeHandleMotionEvent(CompScreen * s, int xRoot, int yRoot)
{
int pointerDx, pointerDy;
RESIZE_SCREEN(s);
RESIZE_DISPLAY(s->display);
if (!rs->grabIndex)
return;
if (rd->mask == 0 && rd->w)
{
rd->mask =
((xRoot - rd->w->attrib.x) <
(rd->w->width / 2)) ? ResizeLeftMask : ResizeRightMask;
rd->mask |=
((yRoot - rd->w->attrib.y) <
(rd->w->height / 2)) ? ResizeUpMask : ResizeDownMask;
}
pointerDx = xRoot - rd->currentX;
pointerDy = yRoot - rd->currentY;
if (rd->mask & ResizeRightMask)
pointerDx -= (rd->currentWidth - rd->xdelta);
if (rd->mask & ResizeLeftMask)
pointerDx -= rd->xdelta;
if (rd->mask & ResizeDownMask)
pointerDy -= (rd->currentHeight - rd->ydelta);
if (rd->mask & ResizeUpMask)
pointerDy -= rd->ydelta;
/* Any motion? */
if (!pointerDx && !pointerDy)
return;
resizeUpdateWindowSize(s->display, pointerDx, pointerDy);
}
static void resizeHandleMoveResizeMessage(CompDisplay * d, XEvent * event)
{
CompWindow *w;
CompOption o[6];
CompAction *action;
RESIZE_DISPLAY(d);
if (event->xclient.data.l[2] > WmMoveResizeSizeLeft &&
event->xclient.data.l[2] != WmMoveResizeSizeKeyboard)
return;
w = findWindowAtDisplay(d, event->xclient.window);
if (!w)
return;
action = &rd->opt[RESIZE_DISPLAY_OPTION_INITIATE].value.action;
o[0].type = CompOptionTypeInt;
o[0].name = "window";
o[0].value.i = event->xclient.window;
if (event->xclient.data.l[2] == WmMoveResizeSizeKeyboard)
{
o[1].type = CompOptionTypeInt;
o[1].name = "button";
o[1].value.i = 0;
resizeInitiate(d, action, CompActionStateInitKey, o, 2);
}
else
{
static unsigned int mask[] = {
ResizeUpMask | ResizeLeftMask,
ResizeUpMask,
ResizeUpMask | ResizeRightMask,
ResizeRightMask,
ResizeDownMask | ResizeRightMask,
ResizeDownMask,
ResizeDownMask | ResizeLeftMask,
ResizeLeftMask,
};
unsigned int mods;
Window root, child;
int xRoot, yRoot, i;
XQueryPointer(d->display, w->screen->root,
&root, &child, &xRoot, &yRoot, &i, &i, &mods);
/* TODO: not only button 1 */
if (mods & Button1Mask)
{
o[1].type = CompOptionTypeInt;
o[1].name = "modifiers";
o[1].value.i = mods;
o[2].type = CompOptionTypeInt;
o[2].name = "x";
o[2].value.i = event->xclient.data.l[0];
o[3].type = CompOptionTypeInt;
o[3].name = "y";
o[3].value.i = event->xclient.data.l[1];
o[4].type = CompOptionTypeInt;
o[4].name = "direction";
o[4].value.i = mask[event->xclient.data.l[2]];
o[5].type = CompOptionTypeInt;
o[5].name = "button";
o[5].value.i = event->xclient.data.l[3] ?
event->xclient.data.l[3] : -1;
resizeInitiate(d, action, CompActionStateInitButton, o, 6);
resizeHandleMotionEvent(w->screen, xRoot, yRoot);
}
}
}
static void resizeHandleEvent(CompDisplay * d, XEvent * event)
{
CompScreen *s;
RESIZE_DISPLAY(d);
switch (event->type)
{
case KeyPress:
s = findScreenAtDisplay(d, event->xkey.root);
if (s)
resizeHandleKeyEvent(s, event->xkey.keycode);
break;
case KeyRelease:
break;
case ButtonPress:
s = findScreenAtDisplay(d, event->xbutton.root);
if (s)
{
RESIZE_SCREEN(s);
if (rs->grabIndex)
{
resizeTerminate(d,
&rd->
opt
[RESIZE_DISPLAY_OPTION_INITIATE].
value.action, 0, NULL, 0);
}
}
break;
case ButtonRelease:
{
CompAction *action =
&rd->opt[RESIZE_DISPLAY_OPTION_INITIATE].value.action;
if (action->state & CompActionStateTermButton &&
(rd->releaseButton == -1 ||
event->xbutton.button == rd->releaseButton))
resizeTerminate(d, action, CompActionStateTermButton, NULL, 0);
}
break;
case MotionNotify:
s = findScreenAtDisplay(d, event->xmotion.root);
if (s)
resizeHandleMotionEvent(s, d->pointerX, d->pointerY);
break;
case EnterNotify:
case LeaveNotify:
s = findScreenAtDisplay(d, event->xcrossing.root);
if (s)
resizeHandleMotionEvent(s, d->pointerX, d->pointerY);
break;
case ClientMessage:
if (event->xclient.message_type == d->wmMoveResizeAtom)
resizeHandleMoveResizeMessage(d, event);
break;
case DestroyNotify:
if (rd->w && rd->w->id == event->xdestroywindow.window)
{
CompAction *action =
&rd->opt[RESIZE_DISPLAY_OPTION_INITIATE].value.action;
resizeTerminate(d, action, 0, NULL, 0);
}
break;
case UnmapNotify:
if (rd->w && rd->w->id == event->xunmap.window)
{
CompAction *action =
&rd->opt[RESIZE_DISPLAY_OPTION_INITIATE].value.action;
resizeTerminate(d, action, 0, NULL, 0);
}
break;
default:
if (event->type == d->syncEvent + XSyncAlarmNotify && rd->w)
{
XSyncAlarmNotifyEvent *sa;
sa = (XSyncAlarmNotifyEvent *) event;
if (rd->w->syncAlarm == sa->alarm)
resizeApply(d);
}
break;
}
UNWRAP(rd, d, handleEvent);
(*d->handleEvent) (d, event);
WRAP(rd, d, handleEvent, resizeHandleEvent);
switch (event->type) {
case ConfigureNotify:
if (rd->ungrabPending) {
if (rd->w && (rd->w->id == event->xconfigure.window)) {
(rd->w->screen->windowUngrabNotify) (rd->w);
syncWindowPosition(rd->w);
rd->w = NULL;
}
rd->ungrabPending = FALSE;
}
break;
default:
break;
}
}
static void resizePreparePaintScreen(CompScreen * s, int msSinceLastPaint)
{
RESIZE_SCREEN(s);
RESIZE_DISPLAY(s->display);
if (rd->w && rd->resizeMode > ResizeModeNormal &&
rs->grabIndex &&
(rd->lastWidth != rd->currentWidth ||
rd->lastHeight != rd->currentHeight))
{
damageScreen(s);
}
UNWRAP(rs, s, preparePaintScreen);
(*s->preparePaintScreen) (s, msSinceLastPaint);
WRAP(rs, s, preparePaintScreen, resizePreparePaintScreen);
}
static Bool
resizePaintWindow(CompWindow * w,
const WindowPaintAttrib * attrib,
Region region, unsigned int mask)
{
WindowPaintAttrib sAttrib;
CompScreen *s = w->screen;
Bool status;
RESIZE_SCREEN(s);
RESIZE_DISPLAY(s->display);
if ((rs->grabIndex || rd->ungrabPending) && (rd->w == w))
{
sAttrib = *attrib;
if (rd->resizeMode != ResizeModeNormal)
mask |= PAINT_WINDOW_TRANSFORMED_MASK;
if (rd->resizeMode == ResizeModeStretch)
{
sAttrib.xScale =
(float)(rd->currentWidth) /
(float)(rd->w->attrib.width);
sAttrib.yScale =
(float)(rd->currentHeight) /
(float)(rd->w->attrib.height);
}
if (rd->resizeOpacity != OPAQUE
&& sAttrib.opacity >= rd->opacifyMinOpacity)
{
sAttrib.opacity = (sAttrib.opacity * rd->resizeOpacity) >> 16;
}
attrib = &sAttrib;
}
UNWRAP(rs, s, paintWindow);
status = (*s->paintWindow) (w, attrib, region, mask);
WRAP(rs, s, paintWindow, resizePaintWindow);
return status;
}
static void
resizePaintOutline(CompScreen * s, const ScreenPaintAttrib * sa, int output,
Bool transformed)
{
int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
RESIZE_SCREEN(s);
RESIZE_DISPLAY(s->display);
if (rd->resizeMode > ResizeModeStretch && rd->w &&
!(rd->w->state & MAXIMIZE_STATE) && rs->grabIndex)
{
x1 = rd->currentX - rd->w->input.left;
x2 = rd->currentX + rd->currentWidth + rd->w->input.right;
y1 = rd->currentY - rd->w->input.top;
y2 = rd->currentY +
(rd->w->shaded ? rd->w->height : rd->currentHeight) +
rd->w->input.bottom;
glPushMatrix();
if (transformed)
{
glLoadIdentity();
(s->applyScreenTransform) (s, sa, output);
}
prepareXCoords(s, output,
transformed ? -sa->zTranslate : -DEFAULT_Z_CAMERA);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_BLEND);
if (rd->resizeMode == ResizeModeFilled)
{
glColor4usv(rd->opt[RESIZE_DISPLAY_OPTION_FILL_COLOR].value.c);
glRecti(x1, y2, x2, y1);
}
/* This section draws the outline */
glColor4usv(rd->opt[RESIZE_DISPLAY_OPTION_BORDER_COLOR].value.c);
glLineWidth(2.0);
glBegin(GL_LINE_LOOP);
glVertex2i(x1, y1);
glVertex2i(x2, y1);
glVertex2i(x2, y2);
glVertex2i(x1, y2);
glEnd();
/* Clean up */
glColor4usv(defaultColor);
glDisable(GL_BLEND);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
}
}
static Bool
resizePaintScreen(CompScreen * s,
const ScreenPaintAttrib * sAttrib,
Region region, int output, unsigned int mask)
{
Bool status = FALSE;
RESIZE_SCREEN(s);
RESIZE_DISPLAY(s->display);
rs->painted = FALSE;
rs->x = s->x;
rs->y = s->y;
if (rd->w && rs->grabIndex && rd->resizeMode == ResizeModeStretch)
mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
UNWRAP(rs, s, paintScreen);
status = (*s->paintScreen) (s, sAttrib, region, output, mask);
WRAP(rs, s, paintScreen, resizePaintScreen);
if (status && !rs->painted)
resizePaintOutline(s, sAttrib, output, FALSE);
return status;
}
static void
resizePaintTransformedScreen(CompScreen * s, const ScreenPaintAttrib * sa,
Region region, int output, unsigned int mask)
{
RESIZE_SCREEN(s);
UNWRAP(rs, s, paintTransformedScreen);
(*s->paintTransformedScreen) (s, sa, region, output, mask);
WRAP(rs, s, paintTransformedScreen, resizePaintTransformedScreen);
if ((rs->x == s->x) && (rs->y == s->y)) {
rs->painted = TRUE;
resizePaintOutline(s, sa, output, TRUE);
}
}
static void resizeDonePaintScreen(CompScreen * s)
{
RESIZE_SCREEN(s);
RESIZE_DISPLAY(s->display);
if (rd->resizeMode != ResizeModeNormal && rd->w && rs->grabIndex)
{
rd->lastWidth = rd->currentWidth;
rd->lastHeight = rd->currentHeight;
}
UNWRAP(rs, s, donePaintScreen);
(*s->donePaintScreen) (s);
WRAP(rs, s, donePaintScreen, resizeDonePaintScreen);
}
static Bool
resizeSetDisplayOption(CompDisplay * display,
char *name, CompOptionValue * value)
{
CompOption *o;
int index;
RESIZE_DISPLAY(display);
o = compFindOption(rd->opt, NUM_OPTIONS(rd), name, &index);
if (!o)
return FALSE;
switch (index)
{
case RESIZE_DISPLAY_OPTION_INITIATE:
if (setDisplayAction(display, o, value))
return TRUE;
break;
case RESIZE_DISPLAY_OPTION_OPACITY:
if (compSetIntOption(o, value))
{
rd->resizeOpacity = (o->value.i * OPAQUE) / 100;
return TRUE;
}
break;
case RESIZE_DISPLAY_OPTION_OPACIFY_MIN_OPACITY:
if (compSetIntOption(o, value))
{
rd->opacifyMinOpacity = (o->value.i * OPAQUE) / 100;
return TRUE;
}
break;
case RESIZE_DISPLAY_OPTION_SYNC_WINDOW:
case RESIZE_DISPLAY_OPTION_WARP_POINTER:
if (compSetBoolOption(o, value))
return TRUE;
break;
case RESIZE_DISPLAY_OPTION_MODE:
if (compSetStringOption(o, value))
{
int i;
for (i = 0; i < o->rest.s.nString; i++)
if (strcmp(resizeModes[i], o->value.s) == 0)
rd->resizeMode = (ResizeMode) i;
return TRUE;
}
break;
case RESIZE_DISPLAY_OPTION_BORDER_COLOR:
case RESIZE_DISPLAY_OPTION_FILL_COLOR:
if (compSetColorOption(o, value))
return TRUE;
break;
default:
break;
}
return FALSE;
}
static void resizeDisplayInitOptions(ResizeDisplay * rd)
{
CompOption *o;
o = &rd->opt[RESIZE_DISPLAY_OPTION_INITIATE];
o->advanced = False;
o->name = "initiate";
o->group = N_("Binding");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Initiate Window Resize");
o->longDesc = N_("Start Resizing a Window.");
o->type = CompOptionTypeAction;
o->value.action.initiate = resizeInitiate;
o->value.action.terminate = resizeTerminate;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.type = CompBindingTypeButton;
o->value.action.state = CompActionStateInitButton;
o->value.action.button.modifiers =
RESIZE_INITIATE_BUTTON_MODIFIERS_DEFAULT;
o->value.action.button.button = RESIZE_INITIATE_BUTTON_DEFAULT;
o->value.action.type |= CompBindingTypeKey;
o->value.action.state |= CompActionStateInitKey;
o->value.action.key.modifiers = RESIZE_INITIATE_KEY_MODIFIERS_DEFAULT;
o->value.action.key.keysym = XStringToKeysym(RESIZE_INITIATE_KEY_DEFAULT);
o = &rd->opt[RESIZE_DISPLAY_OPTION_WARP_POINTER];
o->advanced = False;
o->name = "warp_pointer";
o->group = N_("Behaviour");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc =
N_
("Warp Pointer When Starting a Resize With Mouse Initiate Combo.");
o->longDesc =
N_("If this is set, the Pointer will be Warped to the "
"closest corner when you start a Resize.");
o->type = CompOptionTypeBool;
o->value.b = RESIZE_WARP_POINTER_DEFAULT;
o = &rd->opt[RESIZE_DISPLAY_OPTION_OPACITY];
o->advanced = False;
o->name = "opacity";
o->group = N_("Appearance");
o->subGroup = N_("Opacity");
o->displayHints = "";
o->shortDesc = N_("Opacity");
o->longDesc = N_("Opacity level of resizing windows.");
o->type = CompOptionTypeInt;
o->value.i = RESIZE_OPACITY_DEFAULT;
o->rest.i.min = RESIZE_OPACITY_MIN;
o->rest.i.max = RESIZE_OPACITY_MAX;
o = &rd->opt[RESIZE_DISPLAY_OPTION_OPACIFY_MIN_OPACITY];
o->advanced = False;
o->name = "opacify_min_opacity";
o->group = N_("Appearance");
o->subGroup = N_("Opacity");
o->displayHints = "";
o->shortDesc = N_("Minimum Opacity for Opacify");
o->longDesc =
N_
("Opacify only Windows whose Opacity is higher than this value.");
o->type = CompOptionTypeInt;
o->value.i = RESIZE_OPACIFY_MIN_OPACITY_DEFAULT;
o->rest.i.min = RESIZE_OPACIFY_MIN_OPACITY_MIN;
o->rest.i.max = RESIZE_OPACIFY_MIN_OPACITY_MAX;
o = &rd->opt[RESIZE_DISPLAY_OPTION_SYNC_WINDOW];
o->advanced = False;
o->name = "sync_window";
o->group = N_("Behaviour");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Repaints the Window on Each Resize Step");
o->longDesc =
N_("If this is set to true the Window will Repaint itself "
"during Resize, which may cause some lag.");
o->type = CompOptionTypeBool;
o->value.b = RESIZE_SYNC_WINDOW_DEFAULT;
o = &rd->opt[RESIZE_DISPLAY_OPTION_MODE];
o->advanced = False;
o->name = "resize_mode";
o->group = N_("Behaviour");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Resize Display Mode");
o->longDesc =
N_
("Select between 'Normal', 'Stretched Texture', "
"'Outline and Filled' outline modes.");
o->type = CompOptionTypeString;
o->value.s = strdup(resizeModes[RESIZE_MODE_DEFAULT]);
o->rest.s.string = resizeModes;
o->rest.s.nString = NUM_RESIZE_MODES;
o = &rd->opt[RESIZE_DISPLAY_OPTION_BORDER_COLOR];
o->advanced = False;
o->name = "border_color";
o->group = N_("Appearance");
o->subGroup = N_("Outline Mode");
o->displayHints = "";
o->shortDesc = N_("Outline Color");
o->longDesc = N_("Outline Color for Outline and Filled Outline modes.");
o->type = CompOptionTypeColor;
o->value.c[0] = 0x2fff;
o->value.c[1] = 0x2fff;
o->value.c[2] = 0x4fff;
o->value.c[3] = 0x9fff;
o = &rd->opt[RESIZE_DISPLAY_OPTION_FILL_COLOR];
o->advanced = False;
o->name = "fill_color";
o->group = N_("Appearance");
o->subGroup = N_("Outline Mode");
o->displayHints = "";
o->shortDesc = N_("Fill Color");
o->longDesc = N_("Fill Color for Filled Outline mode.");
o->type = CompOptionTypeColor;
o->value.c[0] = 0x2fff;
o->value.c[1] = 0x2fff;
o->value.c[2] = 0x4fff;
o->value.c[3] = 0x4fff;
}
static CompOption *resizeGetDisplayOptions(CompDisplay * display, int *count)
{
if (display)
{
RESIZE_DISPLAY(display);
*count = NUM_OPTIONS(rd);
return rd->opt;
}
else
{
ResizeDisplay *rd = malloc(sizeof(ResizeDisplay));
resizeDisplayInitOptions(rd);
*count = NUM_OPTIONS(rd);
return rd->opt;
}
}
static Bool resizeInitDisplay(CompPlugin * p, CompDisplay * d)
{
ResizeDisplay *rd;
int i;
rd = malloc(sizeof(ResizeDisplay));
if (!rd)
return FALSE;
rd->screenPrivateIndex = allocateScreenPrivateIndex(d);
if (rd->screenPrivateIndex < 0)
{
free(rd);
return FALSE;
}
rd->resizeMode = ResizeModeNormal;
rd->resizeOpacity = (RESIZE_OPACITY_DEFAULT * OPAQUE) / 100;
rd->opacifyMinOpacity =
(RESIZE_OPACIFY_MIN_OPACITY_DEFAULT * OPAQUE) / 100;
resizeDisplayInitOptions(rd);
rd->w = 0;
rd->ungrabPending = FALSE;
rd->releaseButton = 0;
for (i = 0; i < NUM_KEYS; i++)
rd->key[i] = XKeysymToKeycode(d->display,
XStringToKeysym(rKeys[i].name));
WRAP(rd, d, handleEvent, resizeHandleEvent);
d->privates[displayPrivateIndex].ptr = rd;
return TRUE;
}
static void resizeFiniDisplay(CompPlugin * p, CompDisplay * d)
{
RESIZE_DISPLAY(d);
freeScreenPrivateIndex(d, rd->screenPrivateIndex);
UNWRAP(rd, d, handleEvent);
free(rd);
}
static Bool resizeInitScreen(CompPlugin * p, CompScreen * s)
{
ResizeScreen *rs;
RESIZE_DISPLAY(s->display);
rs = malloc(sizeof(ResizeScreen));
if (!rs)
return FALSE;
rs->grabIndex = 0;
rs->leftCursor = XCreateFontCursor(s->display->display, XC_left_side);
rs->rightCursor = XCreateFontCursor(s->display->display, XC_right_side);
rs->upCursor = XCreateFontCursor(s->display->display, XC_top_side);
rs->upLeftCursor = XCreateFontCursor(s->display->display,
XC_top_left_corner);
rs->upRightCursor = XCreateFontCursor(s->display->display,
XC_top_right_corner);
rs->downCursor = XCreateFontCursor(s->display->display, XC_bottom_side);
rs->downLeftCursor = XCreateFontCursor(s->display->display,
XC_bottom_left_corner);
rs->downRightCursor = XCreateFontCursor(s->display->display,
XC_bottom_right_corner);
rs->middleCursor = XCreateFontCursor(s->display->display, XC_fleur);
rs->cursor[0] = rs->leftCursor;
rs->cursor[1] = rs->rightCursor;
rs->cursor[2] = rs->upCursor;
rs->cursor[3] = rs->downCursor;
addScreenAction(s, &rd->opt[RESIZE_DISPLAY_OPTION_INITIATE].value.action);
WRAP(rs, s, paintWindow, resizePaintWindow);
WRAP(rs, s, preparePaintScreen, resizePreparePaintScreen);
WRAP(rs, s, paintScreen, resizePaintScreen);
WRAP(rs, s, paintTransformedScreen, resizePaintTransformedScreen);
WRAP(rs, s, donePaintScreen, resizeDonePaintScreen);
s->privates[rd->screenPrivateIndex].ptr = rs;
return TRUE;
}
static void resizeFiniScreen(CompPlugin * p, CompScreen * s)
{
RESIZE_SCREEN(s);
RESIZE_DISPLAY(s->display);
UNWRAP(rs, s, paintWindow);
UNWRAP(rs, s, preparePaintScreen);
UNWRAP(rs, s, paintScreen);
UNWRAP(rs, s, paintTransformedScreen);
UNWRAP(rs, s, donePaintScreen);
removeScreenAction(s,
&rd->opt[RESIZE_DISPLAY_OPTION_INITIATE].value.action);
XFreeCursor(s->display->display, rs->leftCursor);
XFreeCursor(s->display->display, rs->rightCursor);
XFreeCursor(s->display->display, rs->upCursor);
XFreeCursor(s->display->display, rs->upLeftCursor);
XFreeCursor(s->display->display, rs->upRightCursor);
XFreeCursor(s->display->display, rs->downCursor);
XFreeCursor(s->display->display, rs->downLeftCursor);
XFreeCursor(s->display->display, rs->downRightCursor);
XFreeCursor(s->display->display, rs->middleCursor);
free(rs);
}
static Bool resizeInit(CompPlugin * p)
{
displayPrivateIndex = allocateDisplayPrivateIndex();
if (displayPrivateIndex < 0)
return FALSE;
return TRUE;
}
static void resizeFini(CompPlugin * p)
{
if (displayPrivateIndex >= 0)
freeDisplayPrivateIndex(displayPrivateIndex);
}
CompPluginFeature resizeFeatures[] = {
{"resize"}
};
CompPluginVTable resizeVTable = {
"resize",
N_("Resize Window"),
N_("Resize window"),
resizeInit,
resizeFini,
resizeInitDisplay,
resizeFiniDisplay,
resizeInitScreen,
resizeFiniScreen,
0, /* InitWindow */
0, /* FiniWindow */
resizeGetDisplayOptions,
resizeSetDisplayOption,
0, /* GetScreenOptions */
0, /* SetScreenOption */
NULL,
0,
resizeFeatures,
sizeof(resizeFeatures) / sizeof(resizeFeatures[0]),
BERYL_ABI_INFO,
"beryl-plugins",
"wm",
0,
0,
True,
};
CompPluginVTable *getCompPluginInfo(void)
{
return &resizeVTable;
}
syntax highlighted by Code2HTML, v. 0.9.1