You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1571 lines
38 KiB
1571 lines
38 KiB
/*
|
|
* Copyright © 2005 Novell, Inc.
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software
|
|
* and its documentation for any purpose is hereby granted without
|
|
* fee, provided that the above copyright notice appear in all copies
|
|
* and that both that copyright notice and this permission notice
|
|
* appear in supporting documentation, and that the name of
|
|
* Novell, Inc. not be used in advertising or publicity pertaining to
|
|
* distribution of the software without specific, written prior permission.
|
|
* Novell, Inc. makes no representations about the suitability of this
|
|
* software for any purpose. It is provided "as is" without express or
|
|
* implied warranty.
|
|
*
|
|
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
|
|
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* Author: David Reveman <davidr@novell.com>
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
#include <X11/cursorfont.h>
|
|
|
|
#include <compiz-core.h>
|
|
|
|
static CompMetadata resizeMetadata;
|
|
|
|
#define ResizeUpMask (1L << 0)
|
|
#define ResizeDownMask (1L << 1)
|
|
#define ResizeLeftMask (1L << 2)
|
|
#define ResizeRightMask (1L << 3)
|
|
|
|
#define RESIZE_MODE_NORMAL 0
|
|
#define RESIZE_MODE_OUTLINE 1
|
|
#define RESIZE_MODE_RECTANGLE 2
|
|
#define RESIZE_MODE_STRETCH 3
|
|
#define RESIZE_MODE_LAST RESIZE_MODE_STRETCH
|
|
|
|
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_NORMAL_KEY 0
|
|
#define RESIZE_DISPLAY_OPTION_INITIATE_OUTLINE_KEY 1
|
|
#define RESIZE_DISPLAY_OPTION_INITIATE_RECTANGLE_KEY 2
|
|
#define RESIZE_DISPLAY_OPTION_INITIATE_STRETCH_KEY 3
|
|
#define RESIZE_DISPLAY_OPTION_INITIATE_BUTTON 4
|
|
#define RESIZE_DISPLAY_OPTION_INITIATE_KEY 5
|
|
#define RESIZE_DISPLAY_OPTION_MODE 6
|
|
#define RESIZE_DISPLAY_OPTION_BORDER_COLOR 7
|
|
#define RESIZE_DISPLAY_OPTION_FILL_COLOR 8
|
|
#define RESIZE_DISPLAY_OPTION_NORMAL_MATCH 9
|
|
#define RESIZE_DISPLAY_OPTION_OUTLINE_MATCH 10
|
|
#define RESIZE_DISPLAY_OPTION_RECTANGLE_MATCH 11
|
|
#define RESIZE_DISPLAY_OPTION_STRETCH_MATCH 12
|
|
#define RESIZE_DISPLAY_OPTION_NUM 13
|
|
|
|
static int displayPrivateIndex;
|
|
|
|
typedef struct _ResizeDisplay {
|
|
CompOption opt[RESIZE_DISPLAY_OPTION_NUM];
|
|
|
|
int screenPrivateIndex;
|
|
HandleEventProc handleEvent;
|
|
|
|
Atom resizeNotifyAtom;
|
|
Atom resizeInformationAtom;
|
|
|
|
CompWindow *w;
|
|
int mode;
|
|
XRectangle savedGeometry;
|
|
XRectangle geometry;
|
|
|
|
int releaseButton;
|
|
unsigned int mask;
|
|
int pointerDx;
|
|
int pointerDy;
|
|
KeyCode key[NUM_KEYS];
|
|
|
|
Bool offWorkAreaConstrained;
|
|
} ResizeDisplay;
|
|
|
|
typedef struct _ResizeScreen {
|
|
int grabIndex;
|
|
|
|
WindowResizeNotifyProc windowResizeNotify;
|
|
PaintOutputProc paintOutput;
|
|
PaintWindowProc paintWindow;
|
|
DamageWindowRectProc damageWindowRect;
|
|
|
|
Cursor leftCursor;
|
|
Cursor rightCursor;
|
|
Cursor upCursor;
|
|
Cursor upLeftCursor;
|
|
Cursor upRightCursor;
|
|
Cursor downCursor;
|
|
Cursor downLeftCursor;
|
|
Cursor downRightCursor;
|
|
Cursor middleCursor;
|
|
Cursor cursor[NUM_KEYS];
|
|
|
|
const XRectangle *grabWindowWorkArea;
|
|
} ResizeScreen;
|
|
|
|
#define GET_RESIZE_DISPLAY(d) \
|
|
((ResizeDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
|
|
|
|
#define RESIZE_DISPLAY(d) \
|
|
ResizeDisplay *rd = GET_RESIZE_DISPLAY (d)
|
|
|
|
#define GET_RESIZE_SCREEN(s, rd) \
|
|
((ResizeScreen *) (s)->base.privates[(rd)->screenPrivateIndex].ptr)
|
|
|
|
#define RESIZE_SCREEN(s) \
|
|
ResizeScreen *rs = GET_RESIZE_SCREEN (s, GET_RESIZE_DISPLAY (s->display))
|
|
|
|
#define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
|
|
|
|
static void
|
|
resizeGetPaintRectangle (CompDisplay *d,
|
|
BoxPtr pBox)
|
|
{
|
|
RESIZE_DISPLAY (d);
|
|
|
|
pBox->x1 = rd->geometry.x - rd->w->input.left;
|
|
pBox->y1 = rd->geometry.y - rd->w->input.top;
|
|
pBox->x2 = rd->geometry.x +
|
|
rd->geometry.width + rd->w->serverBorderWidth * 2 +
|
|
rd->w->input.right;
|
|
|
|
if (rd->w->shaded)
|
|
{
|
|
pBox->y2 = rd->geometry.y + rd->w->height + rd->w->input.bottom;
|
|
}
|
|
else
|
|
{
|
|
pBox->y2 = rd->geometry.y +
|
|
rd->geometry.height + rd->w->serverBorderWidth * 2 +
|
|
rd->w->input.bottom;
|
|
}
|
|
}
|
|
|
|
static void
|
|
resizeGetStretchScale (CompWindow *w,
|
|
BoxPtr pBox,
|
|
float *xScale,
|
|
float *yScale)
|
|
{
|
|
int width, height;
|
|
|
|
width = w->width + w->input.left + w->input.right;
|
|
height = w->height + w->input.top + w->input.bottom;
|
|
|
|
*xScale = (width) ? (pBox->x2 - pBox->x1) / (float) width : 1.0f;
|
|
*yScale = (height) ? (pBox->y2 - pBox->y1) / (float) height : 1.0f;
|
|
}
|
|
|
|
static void
|
|
resizeGetStretchRectangle (CompDisplay *d,
|
|
BoxPtr pBox)
|
|
{
|
|
BoxRec box;
|
|
float xScale, yScale;
|
|
|
|
RESIZE_DISPLAY (d);
|
|
|
|
resizeGetPaintRectangle (d, &box);
|
|
resizeGetStretchScale (rd->w, &box, &xScale, &yScale);
|
|
|
|
pBox->x1 = box.x1 - (rd->w->output.left - rd->w->input.left) * xScale;
|
|
pBox->y1 = box.y1 - (rd->w->output.top - rd->w->input.top) * yScale;
|
|
pBox->x2 = box.x2 + rd->w->output.right * xScale;
|
|
pBox->y2 = box.y2 + rd->w->output.bottom * yScale;
|
|
}
|
|
|
|
static void
|
|
resizeDamageRectangle (CompScreen *s,
|
|
BoxPtr pBox)
|
|
{
|
|
REGION reg;
|
|
|
|
reg.rects = ®.extents;
|
|
reg.numRects = 1;
|
|
|
|
reg.extents = *pBox;
|
|
|
|
reg.extents.x1 -= 1;
|
|
reg.extents.y1 -= 1;
|
|
reg.extents.x2 += 1;
|
|
reg.extents.y2 += 1;
|
|
|
|
damageScreenRegion (s, ®);
|
|
}
|
|
|
|
static Cursor
|
|
resizeCursorFromResizeMask (CompScreen *s,
|
|
unsigned int mask)
|
|
{
|
|
Cursor cursor;
|
|
|
|
RESIZE_SCREEN (s);
|
|
|
|
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;
|
|
}
|
|
|
|
return cursor;
|
|
}
|
|
|
|
static void
|
|
resizeSendResizeNotify (CompDisplay *d)
|
|
{
|
|
XEvent xev;
|
|
|
|
RESIZE_DISPLAY (d);
|
|
xev.xclient.type = ClientMessage;
|
|
xev.xclient.display = d->display;
|
|
xev.xclient.format = 32;
|
|
|
|
xev.xclient.message_type = rd->resizeNotifyAtom;
|
|
xev.xclient.window = rd->w->id;
|
|
|
|
xev.xclient.data.l[0] = rd->geometry.x;
|
|
xev.xclient.data.l[1] = rd->geometry.y;
|
|
xev.xclient.data.l[2] = rd->geometry.width;
|
|
xev.xclient.data.l[3] = rd->geometry.height;
|
|
xev.xclient.data.l[4] = 0;
|
|
|
|
XSendEvent (d->display,
|
|
rd->w->screen->root,
|
|
FALSE,
|
|
SubstructureRedirectMask | SubstructureNotifyMask,
|
|
&xev);
|
|
}
|
|
|
|
static void
|
|
resizeUpdateWindowProperty (CompDisplay *d)
|
|
{
|
|
unsigned long data[4];
|
|
|
|
RESIZE_DISPLAY (d);
|
|
|
|
data[0] = rd->geometry.x;
|
|
data[1] = rd->geometry.y;
|
|
data[2] = rd->geometry.width;
|
|
data[3] = rd->geometry.height;
|
|
|
|
XChangeProperty (d->display, rd->w->id,
|
|
rd->resizeInformationAtom,
|
|
XA_CARDINAL, 32, PropModeReplace,
|
|
(unsigned char*) data, 4);
|
|
}
|
|
|
|
static void
|
|
resizeFinishResizing (CompDisplay *d)
|
|
{
|
|
RESIZE_DISPLAY (d);
|
|
|
|
(*rd->w->screen->windowUngrabNotify) (rd->w);
|
|
|
|
XDeleteProperty (d->display,
|
|
rd->w->id,
|
|
rd->resizeInformationAtom);
|
|
|
|
rd->w = NULL;
|
|
}
|
|
|
|
static Bool
|
|
resizeInitiate (CompDisplay *d,
|
|
CompAction *action,
|
|
CompActionState state,
|
|
CompOption *option,
|
|
int nOption)
|
|
{
|
|
CompWindow *w;
|
|
Window xid;
|
|
|
|
RESIZE_DISPLAY (d);
|
|
|
|
xid = getIntOptionNamed (option, nOption, "window", 0);
|
|
|
|
w = findWindowAtDisplay (d, xid);
|
|
if (w && (w->actions & CompWindowActionResizeMask))
|
|
{
|
|
unsigned int mask;
|
|
int x, y;
|
|
int button;
|
|
int i;
|
|
|
|
RESIZE_SCREEN (w->screen);
|
|
|
|
x = getIntOptionNamed (option, nOption, "x", pointerX);
|
|
y = getIntOptionNamed (option, nOption, "y", pointerY);
|
|
|
|
button = getIntOptionNamed (option, nOption, "button", -1);
|
|
|
|
mask = getIntOptionNamed (option, nOption, "direction", 0);
|
|
|
|
/* Initiate the resize in the direction suggested by the
|
|
* sector 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)
|
|
{
|
|
int sectorSizeX = w->serverWidth / 3;
|
|
int sectorSizeY = w->serverHeight / 3;
|
|
int posX = x - w->serverX;
|
|
int posY = y - w->serverY;
|
|
|
|
if (posX < sectorSizeX)
|
|
mask |= ResizeLeftMask;
|
|
else if (posX > (2 * sectorSizeX))
|
|
mask |= ResizeRightMask;
|
|
|
|
if (posY < sectorSizeY)
|
|
mask |= ResizeUpMask;
|
|
else if (posY > (2 * sectorSizeY))
|
|
mask |= ResizeDownMask;
|
|
|
|
/* if the pointer was in the middle of the window,
|
|
just prevent input to the window */
|
|
if (!mask)
|
|
return TRUE;
|
|
}
|
|
|
|
if (otherScreenGrabExist (w->screen, "resize", NULL))
|
|
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->savedGeometry.x = w->serverX;
|
|
rd->savedGeometry.y = w->serverY;
|
|
rd->savedGeometry.width = w->serverWidth;
|
|
rd->savedGeometry.height = w->serverHeight;
|
|
|
|
rd->geometry = rd->savedGeometry;
|
|
|
|
rd->pointerDx = x - pointerX;
|
|
rd->pointerDy = y - pointerY;
|
|
|
|
if ((w->state & MAXIMIZE_STATE) == MAXIMIZE_STATE)
|
|
{
|
|
/* if the window is fully maximized, showing the outline or
|
|
rectangle would be visually distracting as the window can't
|
|
be resized anyway; so we better don't use them in this case */
|
|
rd->mode = RESIZE_MODE_NORMAL;
|
|
}
|
|
else
|
|
{
|
|
rd->mode = rd->opt[RESIZE_DISPLAY_OPTION_MODE].value.i;
|
|
for (i = 0; i <= RESIZE_MODE_LAST; i++)
|
|
{
|
|
if (action == &rd->opt[i].value.action)
|
|
{
|
|
rd->mode = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i > RESIZE_MODE_LAST)
|
|
{
|
|
int index;
|
|
|
|
for (i = 0; i <= RESIZE_MODE_LAST; i++)
|
|
{
|
|
index = RESIZE_DISPLAY_OPTION_NORMAL_MATCH + i;
|
|
if (matchEval (&rd->opt[index].value.match, w))
|
|
{
|
|
rd->mode = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!rs->grabIndex)
|
|
{
|
|
Cursor cursor;
|
|
|
|
if (state & CompActionStateInitKey)
|
|
{
|
|
cursor = rs->middleCursor;
|
|
}
|
|
else
|
|
{
|
|
cursor = resizeCursorFromResizeMask (w->screen, mask);
|
|
}
|
|
|
|
rs->grabIndex = pushScreenGrab (w->screen, cursor, "resize");
|
|
}
|
|
|
|
if (rs->grabIndex)
|
|
{
|
|
unsigned int grabMask = CompWindowGrabResizeMask |
|
|
CompWindowGrabButtonMask;
|
|
Bool sourceExternalApp = getBoolOptionNamed (option, nOption,
|
|
"external", FALSE);
|
|
|
|
if (sourceExternalApp)
|
|
grabMask |= CompWindowGrabExternalAppMask;
|
|
|
|
BoxRec box;
|
|
|
|
rd->releaseButton = button;
|
|
|
|
(w->screen->windowGrabNotify) (w, x, y, state, grabMask);
|
|
|
|
if (d->opt[COMP_DISPLAY_OPTION_RAISE_ON_CLICK].value.b)
|
|
updateWindowAttributes (w,
|
|
CompStackingUpdateModeAboveFullscreen);
|
|
|
|
/* using the paint rectangle is enough here
|
|
as we don't have any stretch yet */
|
|
resizeGetPaintRectangle (d, &box);
|
|
resizeDamageRectangle (w->screen, &box);
|
|
|
|
if (state & CompActionStateInitKey)
|
|
{
|
|
int xRoot, yRoot;
|
|
|
|
xRoot = w->serverX + (w->serverWidth / 2);
|
|
yRoot = w->serverY + (w->serverHeight / 2);
|
|
|
|
warpPointer (w->screen, xRoot - pointerX, yRoot - pointerY);
|
|
}
|
|
|
|
/* Update offWorkAreaConstrained and workArea at grab time */
|
|
rd->offWorkAreaConstrained = FALSE;
|
|
if (sourceExternalApp)
|
|
{
|
|
int output = outputDeviceForWindow (w);
|
|
|
|
rs->grabWindowWorkArea = &w->screen->outputDev[output].workArea;
|
|
|
|
/* Prevent resizing beyond work area edges when resize is
|
|
initiated externally (e.g. with window frame or menu)
|
|
and not with a key (e.g. alt+button) */
|
|
rd->offWorkAreaConstrained = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static Bool
|
|
resizeTerminate (CompDisplay *d,
|
|
CompAction *action,
|
|
CompActionState state,
|
|
CompOption *option,
|
|
int nOption)
|
|
{
|
|
RESIZE_DISPLAY (d);
|
|
|
|
if (rd->w)
|
|
{
|
|
CompWindow *w = rd->w;
|
|
XWindowChanges xwc;
|
|
unsigned int mask = 0;
|
|
|
|
RESIZE_SCREEN (w->screen);
|
|
|
|
if (rd->mode == RESIZE_MODE_NORMAL)
|
|
{
|
|
if (state & CompActionStateCancel)
|
|
{
|
|
xwc.x = rd->savedGeometry.x;
|
|
xwc.y = rd->savedGeometry.y;
|
|
xwc.width = rd->savedGeometry.width;
|
|
xwc.height = rd->savedGeometry.height;
|
|
|
|
mask = CWX | CWY | CWWidth | CWHeight;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XRectangle geometry;
|
|
|
|
if (state & CompActionStateCancel)
|
|
geometry = rd->savedGeometry;
|
|
else
|
|
geometry = rd->geometry;
|
|
|
|
if (memcmp (&geometry, &rd->savedGeometry, sizeof (geometry)) == 0)
|
|
{
|
|
BoxRec box;
|
|
|
|
if (rd->mode == RESIZE_MODE_STRETCH)
|
|
resizeGetStretchRectangle (d, &box);
|
|
else
|
|
resizeGetPaintRectangle (d, &box);
|
|
|
|
resizeDamageRectangle (w->screen, &box);
|
|
}
|
|
else
|
|
{
|
|
xwc.x = geometry.x;
|
|
xwc.y = geometry.y;
|
|
xwc.width = geometry.width;
|
|
xwc.height = geometry.height;
|
|
|
|
mask = CWX | CWY | CWWidth | CWHeight;
|
|
}
|
|
}
|
|
|
|
if ((mask & CWWidth) && xwc.width == w->serverWidth)
|
|
mask &= ~CWWidth;
|
|
|
|
if ((mask & CWHeight) && xwc.height == w->serverHeight)
|
|
mask &= ~CWHeight;
|
|
|
|
if (mask)
|
|
{
|
|
if (mask & (CWWidth | CWHeight))
|
|
sendSyncRequest (w);
|
|
|
|
configureXWindow (w, mask, &xwc);
|
|
}
|
|
|
|
if (!(mask & (CWWidth | CWHeight)))
|
|
resizeFinishResizing (d);
|
|
|
|
if (rs->grabIndex)
|
|
{
|
|
removeScreenGrab (w->screen, rs->grabIndex, NULL);
|
|
rs->grabIndex = 0;
|
|
}
|
|
|
|
rd->releaseButton = 0;
|
|
}
|
|
|
|
action->state &= ~(CompActionStateTermKey | CompActionStateTermButton);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
resizeUpdateWindowSize (CompDisplay *d)
|
|
{
|
|
RESIZE_DISPLAY (d);
|
|
|
|
if (rd->w->syncWait)
|
|
return;
|
|
|
|
if (rd->w->serverWidth != rd->geometry.width ||
|
|
rd->w->serverHeight != rd->geometry.height)
|
|
{
|
|
XWindowChanges xwc;
|
|
|
|
xwc.x = rd->geometry.x;
|
|
xwc.y = rd->geometry.y;
|
|
xwc.width = rd->geometry.width;
|
|
xwc.height = rd->geometry.height;
|
|
|
|
sendSyncRequest (rd->w);
|
|
|
|
configureXWindow (rd->w,
|
|
CWX | CWY | CWWidth | CWHeight,
|
|
&xwc);
|
|
}
|
|
}
|
|
|
|
static void
|
|
resizeHandleKeyEvent (CompScreen *s,
|
|
KeyCode keycode)
|
|
{
|
|
RESIZE_SCREEN (s);
|
|
RESIZE_DISPLAY (s->display);
|
|
|
|
if (rs->grabIndex && rd->w)
|
|
{
|
|
CompWindow *w = rd->w;
|
|
int widthInc, heightInc, i;
|
|
|
|
widthInc = w->sizeHints.width_inc;
|
|
heightInc = w->sizeHints.height_inc;
|
|
|
|
if (widthInc < MIN_KEY_WIDTH_INC)
|
|
widthInc = MIN_KEY_WIDTH_INC;
|
|
|
|
if (heightInc < MIN_KEY_HEIGHT_INC)
|
|
heightInc = MIN_KEY_HEIGHT_INC;
|
|
|
|
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->serverX - w->input.left;
|
|
top = w->serverY - 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;
|
|
|
|
warpPointer (s, x - pointerX, y - pointerY);
|
|
|
|
rd->mask = rKeys[i].resizeMask;
|
|
|
|
updateScreenGrab (s, rs->grabIndex, rs->cursor[i]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
resizeHandleMotionEvent (CompScreen *s,
|
|
int xRoot,
|
|
int yRoot)
|
|
{
|
|
RESIZE_SCREEN (s);
|
|
|
|
if (rs->grabIndex)
|
|
{
|
|
BoxRec box;
|
|
int w, h;
|
|
|
|
RESIZE_DISPLAY (s->display);
|
|
|
|
w = rd->savedGeometry.width;
|
|
h = rd->savedGeometry.height;
|
|
|
|
if (!rd->mask)
|
|
{
|
|
CompWindow *w = rd->w;
|
|
int xDist, yDist;
|
|
int minPointerOffsetX, minPointerOffsetY;
|
|
|
|
xDist = xRoot - (w->serverX + (w->serverWidth / 2));
|
|
yDist = yRoot - (w->serverY + (w->serverHeight / 2));
|
|
|
|
/* decision threshold is 10% of window size */
|
|
minPointerOffsetX = MIN (20, w->serverWidth / 10);
|
|
minPointerOffsetY = MIN (20, w->serverHeight / 10);
|
|
|
|
/* if we reached the threshold in one direction,
|
|
make the threshold in the other direction smaller
|
|
so there is a chance that this threshold also can
|
|
be reached (by diagonal movement) */
|
|
if (abs (xDist) > minPointerOffsetX)
|
|
minPointerOffsetY /= 2;
|
|
else if (abs (yDist) > minPointerOffsetY)
|
|
minPointerOffsetX /= 2;
|
|
|
|
if (abs (xDist) > minPointerOffsetX)
|
|
{
|
|
if (xDist > 0)
|
|
rd->mask |= ResizeRightMask;
|
|
else
|
|
rd->mask |= ResizeLeftMask;
|
|
}
|
|
|
|
if (abs (yDist) > minPointerOffsetY)
|
|
{
|
|
if (yDist > 0)
|
|
rd->mask |= ResizeDownMask;
|
|
else
|
|
rd->mask |= ResizeUpMask;
|
|
}
|
|
|
|
/* if the pointer movement was enough to determine a
|
|
direction, warp the pointer to the appropriate edge
|
|
and set the right cursor */
|
|
if (rd->mask)
|
|
{
|
|
Cursor cursor;
|
|
CompScreen *s = rd->w->screen;
|
|
CompAction *action;
|
|
int pointerAdjustX = 0;
|
|
int pointerAdjustY = 0;
|
|
int option = RESIZE_DISPLAY_OPTION_INITIATE_KEY;
|
|
|
|
RESIZE_SCREEN (s);
|
|
|
|
action = &rd->opt[option].value.action;
|
|
action->state |= CompActionStateTermButton;
|
|
|
|
if (rd->mask & ResizeRightMask)
|
|
pointerAdjustX = w->serverX + w->serverWidth +
|
|
w->input.right - xRoot;
|
|
else if (rd->mask & ResizeLeftMask)
|
|
pointerAdjustX = w->serverX - w->input.left - xRoot;
|
|
|
|
if (rd->mask & ResizeDownMask)
|
|
pointerAdjustY = w->serverY + w->serverHeight +
|
|
w->input.bottom - yRoot;
|
|
else if (rd->mask & ResizeUpMask)
|
|
pointerAdjustY = w->serverY - w->input.top - yRoot;
|
|
|
|
warpPointer (s, pointerAdjustX, pointerAdjustY);
|
|
|
|
cursor = resizeCursorFromResizeMask (s, rd->mask);
|
|
updateScreenGrab (s, rs->grabIndex, cursor);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* only accumulate pointer movement if a mask is
|
|
already set as we don't have a use for the
|
|
difference information otherwise */
|
|
rd->pointerDx += xRoot - lastPointerX;
|
|
rd->pointerDy += yRoot - lastPointerY;
|
|
}
|
|
|
|
if (rd->mask & ResizeLeftMask)
|
|
w -= rd->pointerDx;
|
|
else if (rd->mask & ResizeRightMask)
|
|
w += rd->pointerDx;
|
|
|
|
if (rd->mask & ResizeUpMask)
|
|
h -= rd->pointerDy;
|
|
else if (rd->mask & ResizeDownMask)
|
|
h += rd->pointerDy;
|
|
|
|
if (rd->w->state & CompWindowStateMaximizedVertMask)
|
|
h = rd->w->serverHeight;
|
|
|
|
if (rd->w->state & CompWindowStateMaximizedHorzMask)
|
|
w = rd->w->serverWidth;
|
|
|
|
constrainNewWindowSize (rd->w, w, h, &w, &h);
|
|
|
|
/* constrain to work area */
|
|
if (rd->offWorkAreaConstrained)
|
|
{
|
|
if (rd->mask & ResizeUpMask)
|
|
{
|
|
int decorTop = rd->savedGeometry.y + rd->savedGeometry.height -
|
|
(h + rd->w->input.top);
|
|
|
|
if (rs->grabWindowWorkArea->y > decorTop)
|
|
h -= rs->grabWindowWorkArea->y - decorTop;
|
|
}
|
|
if (rd->mask & ResizeDownMask)
|
|
{
|
|
int decorBottom = rd->savedGeometry.y + h + rd->w->input.bottom;
|
|
|
|
if (decorBottom >
|
|
rs->grabWindowWorkArea->y + rs->grabWindowWorkArea->height)
|
|
h -= decorBottom - (rs->grabWindowWorkArea->y +
|
|
rs->grabWindowWorkArea->height);
|
|
}
|
|
if (rd->mask & ResizeLeftMask)
|
|
{
|
|
int decorLeft = rd->savedGeometry.x + rd->savedGeometry.width -
|
|
(w + rd->w->input.left);
|
|
|
|
if (rs->grabWindowWorkArea->x > decorLeft)
|
|
w -= rs->grabWindowWorkArea->x - decorLeft;
|
|
}
|
|
if (rd->mask & ResizeRightMask)
|
|
{
|
|
int decorRight = rd->savedGeometry.x + w + rd->w->input.right;
|
|
|
|
if (decorRight >
|
|
rs->grabWindowWorkArea->x + rs->grabWindowWorkArea->width)
|
|
w -= decorRight - (rs->grabWindowWorkArea->x +
|
|
rs->grabWindowWorkArea->width);
|
|
}
|
|
}
|
|
|
|
if (rd->mode != RESIZE_MODE_NORMAL)
|
|
{
|
|
if (rd->mode == RESIZE_MODE_STRETCH)
|
|
resizeGetStretchRectangle (s->display, &box);
|
|
else
|
|
resizeGetPaintRectangle (s->display, &box);
|
|
|
|
resizeDamageRectangle (s, &box);
|
|
}
|
|
|
|
if (rd->mask & ResizeLeftMask)
|
|
rd->geometry.x -= w - rd->geometry.width;
|
|
|
|
if (rd->mask & ResizeUpMask)
|
|
rd->geometry.y -= h - rd->geometry.height;
|
|
|
|
rd->geometry.width = w;
|
|
rd->geometry.height = h;
|
|
|
|
if (rd->mode != RESIZE_MODE_NORMAL)
|
|
{
|
|
if (rd->mode == RESIZE_MODE_STRETCH)
|
|
resizeGetStretchRectangle (s->display, &box);
|
|
else
|
|
resizeGetPaintRectangle (s->display, &box);
|
|
|
|
resizeDamageRectangle (s, &box);
|
|
}
|
|
else
|
|
{
|
|
resizeUpdateWindowSize (s->display);
|
|
}
|
|
|
|
resizeUpdateWindowProperty (s->display);
|
|
resizeSendResizeNotify (s->display);
|
|
}
|
|
}
|
|
|
|
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 ButtonRelease:
|
|
s = findScreenAtDisplay (d, event->xbutton.root);
|
|
if (s)
|
|
{
|
|
RESIZE_SCREEN (s);
|
|
|
|
if (rs->grabIndex)
|
|
{
|
|
if (rd->releaseButton == -1 ||
|
|
event->xbutton.button == rd->releaseButton)
|
|
{
|
|
int opt = RESIZE_DISPLAY_OPTION_INITIATE_BUTTON;
|
|
CompAction *action = &rd->opt[opt].value.action;
|
|
|
|
resizeTerminate (d, action, CompActionStateTermButton,
|
|
NULL, 0);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case MotionNotify:
|
|
s = findScreenAtDisplay (d, event->xmotion.root);
|
|
if (s)
|
|
resizeHandleMotionEvent (s, pointerX, pointerY);
|
|
break;
|
|
case EnterNotify:
|
|
case LeaveNotify:
|
|
s = findScreenAtDisplay (d, event->xcrossing.root);
|
|
if (s)
|
|
resizeHandleMotionEvent (s, pointerX, pointerY);
|
|
break;
|
|
case ClientMessage:
|
|
if (event->xclient.message_type == d->wmMoveResizeAtom)
|
|
{
|
|
CompWindow *w;
|
|
|
|
if (event->xclient.data.l[2] <= WmMoveResizeSizeLeft ||
|
|
event->xclient.data.l[2] == WmMoveResizeSizeKeyboard)
|
|
{
|
|
w = findWindowAtDisplay (d, event->xclient.window);
|
|
if (w)
|
|
{
|
|
CompOption o[7];
|
|
int option;
|
|
|
|
o[0].type = CompOptionTypeInt;
|
|
o[0].name = "window";
|
|
o[0].value.i = event->xclient.window;
|
|
|
|
o[1].type = CompOptionTypeBool;
|
|
o[1].name = "external";
|
|
o[1].value.b = TRUE;
|
|
|
|
if (event->xclient.data.l[2] == WmMoveResizeSizeKeyboard)
|
|
{
|
|
option = RESIZE_DISPLAY_OPTION_INITIATE_KEY;
|
|
|
|
resizeInitiate (d, &rd->opt[option].value.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;
|
|
|
|
option = RESIZE_DISPLAY_OPTION_INITIATE_BUTTON;
|
|
|
|
XQueryPointer (d->display, w->screen->root,
|
|
&root, &child, &xRoot, &yRoot,
|
|
&i, &i, &mods);
|
|
|
|
/* TODO: not only button 1 */
|
|
if (mods & Button1Mask)
|
|
{
|
|
o[2].type = CompOptionTypeInt;
|
|
o[2].name = "modifiers";
|
|
o[2].value.i = mods;
|
|
|
|
o[3].type = CompOptionTypeInt;
|
|
o[3].name = "x";
|
|
o[3].value.i = event->xclient.data.l[0];
|
|
|
|
o[4].type = CompOptionTypeInt;
|
|
o[4].name = "y";
|
|
o[4].value.i = event->xclient.data.l[1];
|
|
|
|
o[5].type = CompOptionTypeInt;
|
|
o[5].name = "direction";
|
|
o[5].value.i = mask[event->xclient.data.l[2]];
|
|
|
|
o[6].type = CompOptionTypeInt;
|
|
o[6].name = "button";
|
|
o[6].value.i = event->xclient.data.l[3] ?
|
|
event->xclient.data.l[3] : -1;
|
|
|
|
resizeInitiate (d,
|
|
&rd->opt[option].value.action,
|
|
CompActionStateInitButton,
|
|
o, 7);
|
|
|
|
resizeHandleMotionEvent (w->screen, xRoot, yRoot);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (rd->w && event->xclient.data.l[2] == WmMoveResizeCancel)
|
|
{
|
|
if (rd->w->id == event->xclient.window)
|
|
{
|
|
int option;
|
|
|
|
option = RESIZE_DISPLAY_OPTION_INITIATE_BUTTON;
|
|
resizeTerminate (d, &rd->opt[option].value.action,
|
|
CompActionStateCancel, NULL, 0);
|
|
option = RESIZE_DISPLAY_OPTION_INITIATE_KEY;
|
|
resizeTerminate (d, &rd->opt[option].value.action,
|
|
CompActionStateCancel, NULL, 0);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case DestroyNotify:
|
|
if (rd->w && rd->w->id == event->xdestroywindow.window)
|
|
{
|
|
int option;
|
|
|
|
option = RESIZE_DISPLAY_OPTION_INITIATE_BUTTON;
|
|
resizeTerminate (d, &rd->opt[option].value.action, 0, NULL, 0);
|
|
option = RESIZE_DISPLAY_OPTION_INITIATE_KEY;
|
|
resizeTerminate (d, &rd->opt[option].value.action, 0, NULL, 0);
|
|
}
|
|
break;
|
|
case UnmapNotify:
|
|
if (rd->w && rd->w->id == event->xunmap.window)
|
|
{
|
|
int option;
|
|
|
|
option = RESIZE_DISPLAY_OPTION_INITIATE_BUTTON;
|
|
resizeTerminate (d, &rd->opt[option].value.action, 0, NULL, 0);
|
|
option = RESIZE_DISPLAY_OPTION_INITIATE_KEY;
|
|
resizeTerminate (d, &rd->opt[option].value.action, 0, NULL, 0);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
UNWRAP (rd, d, handleEvent);
|
|
(*d->handleEvent) (d, event);
|
|
WRAP (rd, d, handleEvent, resizeHandleEvent);
|
|
|
|
if (event->type == d->syncEvent + XSyncAlarmNotify)
|
|
{
|
|
if (rd->w)
|
|
{
|
|
XSyncAlarmNotifyEvent *sa;
|
|
|
|
sa = (XSyncAlarmNotifyEvent *) event;
|
|
|
|
if (rd->w->syncAlarm == sa->alarm)
|
|
resizeUpdateWindowSize (d);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
resizeWindowResizeNotify (CompWindow *w,
|
|
int dx,
|
|
int dy,
|
|
int dwidth,
|
|
int dheight)
|
|
{
|
|
RESIZE_DISPLAY (w->screen->display);
|
|
RESIZE_SCREEN (w->screen);
|
|
|
|
UNWRAP (rs, w->screen, windowResizeNotify);
|
|
(*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight);
|
|
WRAP (rs, w->screen, windowResizeNotify, resizeWindowResizeNotify);
|
|
|
|
if (rd->w == w && !rs->grabIndex)
|
|
resizeFinishResizing (w->screen->display);
|
|
}
|
|
|
|
static void
|
|
resizePaintRectangle (CompScreen *s,
|
|
const ScreenPaintAttrib *sa,
|
|
const CompTransform *transform,
|
|
CompOutput *output,
|
|
unsigned short *borderColor,
|
|
unsigned short *fillColor)
|
|
{
|
|
BoxRec box;
|
|
CompTransform sTransform = *transform;
|
|
|
|
resizeGetPaintRectangle (s->display, &box);
|
|
|
|
glPushMatrix ();
|
|
|
|
transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
|
|
|
|
glLoadMatrixf (sTransform.m);
|
|
|
|
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
|
|
glEnable (GL_BLEND);
|
|
|
|
/* fill rectangle */
|
|
if (fillColor)
|
|
{
|
|
glColor4usv (fillColor);
|
|
glRecti (box.x1, box.y2, box.x2, box.y1);
|
|
}
|
|
|
|
/* draw outline */
|
|
glColor4usv (borderColor);
|
|
glLineWidth (2.0);
|
|
glBegin (GL_LINE_LOOP);
|
|
glVertex2i (box.x1, box.y1);
|
|
glVertex2i (box.x2, box.y1);
|
|
glVertex2i (box.x2, box.y2);
|
|
glVertex2i (box.x1, box.y2);
|
|
glEnd ();
|
|
|
|
/* clean up */
|
|
glColor4usv (defaultColor);
|
|
glDisable (GL_BLEND);
|
|
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
|
|
glPopMatrix ();
|
|
}
|
|
|
|
static Bool
|
|
resizePaintOutput (CompScreen *s,
|
|
const ScreenPaintAttrib *sAttrib,
|
|
const CompTransform *transform,
|
|
Region region,
|
|
CompOutput *output,
|
|
unsigned int mask)
|
|
{
|
|
Bool status;
|
|
|
|
RESIZE_SCREEN (s);
|
|
RESIZE_DISPLAY (s->display);
|
|
|
|
if (rd->w && (s == rd->w->screen))
|
|
{
|
|
if (rd->mode == RESIZE_MODE_STRETCH)
|
|
mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
|
|
}
|
|
|
|
UNWRAP (rs, s, paintOutput);
|
|
status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
|
|
WRAP (rs, s, paintOutput, resizePaintOutput);
|
|
|
|
if (status && rd->w && (s == rd->w->screen))
|
|
{
|
|
unsigned short *border, *fill;
|
|
|
|
border = rd->opt[RESIZE_DISPLAY_OPTION_BORDER_COLOR].value.c;
|
|
fill = rd->opt[RESIZE_DISPLAY_OPTION_FILL_COLOR].value.c;
|
|
|
|
switch (rd->mode) {
|
|
case RESIZE_MODE_OUTLINE:
|
|
resizePaintRectangle (s, sAttrib, transform, output, border, NULL);
|
|
break;
|
|
case RESIZE_MODE_RECTANGLE:
|
|
resizePaintRectangle (s, sAttrib, transform, output, border, fill);
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static Bool
|
|
resizePaintWindow (CompWindow *w,
|
|
const WindowPaintAttrib *attrib,
|
|
const CompTransform *transform,
|
|
Region region,
|
|
unsigned int mask)
|
|
{
|
|
CompScreen *s = w->screen;
|
|
Bool status;
|
|
|
|
RESIZE_SCREEN (s);
|
|
RESIZE_DISPLAY (s->display);
|
|
|
|
if (w == rd->w && rd->mode == RESIZE_MODE_STRETCH)
|
|
{
|
|
FragmentAttrib fragment;
|
|
CompTransform wTransform = *transform;
|
|
BoxRec box;
|
|
float xOrigin, yOrigin;
|
|
float xScale, yScale;
|
|
|
|
if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
|
|
return FALSE;
|
|
|
|
UNWRAP (rs, s, paintWindow);
|
|
status = (*s->paintWindow) (w, attrib, transform, region,
|
|
mask | PAINT_WINDOW_NO_CORE_INSTANCE_MASK);
|
|
WRAP (rs, s, paintWindow, resizePaintWindow);
|
|
|
|
initFragmentAttrib (&fragment, &w->lastPaint);
|
|
|
|
if (w->alpha || fragment.opacity != OPAQUE)
|
|
mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
|
|
|
|
resizeGetPaintRectangle (s->display, &box);
|
|
resizeGetStretchScale (w, &box, &xScale, &yScale);
|
|
|
|
xOrigin = w->attrib.x - w->input.left;
|
|
yOrigin = w->attrib.y - w->input.top;
|
|
|
|
matrixTranslate (&wTransform, xOrigin, yOrigin, 0.0f);
|
|
matrixScale (&wTransform, xScale, yScale, 1.0f);
|
|
matrixTranslate (&wTransform,
|
|
(rd->geometry.x - w->attrib.x) / xScale - xOrigin,
|
|
(rd->geometry.y - w->attrib.y) / yScale - yOrigin,
|
|
0.0f);
|
|
|
|
glPushMatrix ();
|
|
glLoadMatrixf (wTransform.m);
|
|
|
|
(*s->drawWindow) (w, &wTransform, &fragment, region,
|
|
mask | PAINT_WINDOW_TRANSFORMED_MASK);
|
|
|
|
glPopMatrix ();
|
|
}
|
|
else
|
|
{
|
|
UNWRAP (rs, s, paintWindow);
|
|
status = (*s->paintWindow) (w, attrib, transform, region, mask);
|
|
WRAP (rs, s, paintWindow, resizePaintWindow);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static Bool
|
|
resizeDamageWindowRect (CompWindow *w,
|
|
Bool initial,
|
|
BoxPtr rect)
|
|
{
|
|
Bool status = FALSE;
|
|
|
|
RESIZE_SCREEN (w->screen);
|
|
RESIZE_DISPLAY (w->screen->display);
|
|
|
|
if (w == rd->w && rd->mode == RESIZE_MODE_STRETCH)
|
|
{
|
|
BoxRec box;
|
|
|
|
resizeGetStretchRectangle (w->screen->display, &box);
|
|
resizeDamageRectangle (w->screen, &box);
|
|
|
|
status = TRUE;
|
|
}
|
|
|
|
UNWRAP (rs, w->screen, damageWindowRect);
|
|
status |= (*w->screen->damageWindowRect) (w, initial, rect);
|
|
WRAP (rs, w->screen, damageWindowRect, resizeDamageWindowRect);
|
|
|
|
return status;
|
|
}
|
|
|
|
static CompOption *
|
|
resizeGetDisplayOptions (CompPlugin *plugin,
|
|
CompDisplay *display,
|
|
int *count)
|
|
{
|
|
RESIZE_DISPLAY (display);
|
|
|
|
*count = NUM_OPTIONS (rd);
|
|
return rd->opt;
|
|
}
|
|
|
|
static Bool
|
|
resizeSetDisplayOption (CompPlugin *plugin,
|
|
CompDisplay *display,
|
|
const char *name,
|
|
CompOptionValue *value)
|
|
{
|
|
CompOption *o;
|
|
|
|
RESIZE_DISPLAY (display);
|
|
|
|
o = compFindOption (rd->opt, NUM_OPTIONS (rd), name, NULL);
|
|
if (!o)
|
|
return FALSE;
|
|
|
|
return compSetDisplayOption (display, o, value);
|
|
}
|
|
|
|
static const CompMetadataOptionInfo resizeDisplayOptionInfo[] = {
|
|
{ "initiate_normal_key", "key", 0, resizeInitiate, resizeTerminate },
|
|
{ "initiate_outline_key", "key", 0, resizeInitiate, resizeTerminate },
|
|
{ "initiate_rectangle_key", "key", 0, resizeInitiate, resizeTerminate },
|
|
{ "initiate_stretch_key", "key", 0, resizeInitiate, resizeTerminate },
|
|
{ "initiate_button", "button", 0, resizeInitiate, resizeTerminate },
|
|
{ "initiate_key", "key", 0, resizeInitiate, resizeTerminate },
|
|
{ "mode", "int", RESTOSTRING (0, RESIZE_MODE_LAST), 0, 0 },
|
|
{ "border_color", "color", 0, 0, 0 },
|
|
{ "fill_color", "color", 0, 0, 0 },
|
|
{ "normal_match", "match", 0, 0, 0 },
|
|
{ "outline_match", "match", 0, 0, 0 },
|
|
{ "rectangle_match", "match", 0, 0, 0 },
|
|
{ "stretch_match", "match", 0, 0, 0 }
|
|
};
|
|
|
|
static Bool
|
|
resizeInitDisplay (CompPlugin *p,
|
|
CompDisplay *d)
|
|
{
|
|
ResizeDisplay *rd;
|
|
int i;
|
|
|
|
if (!checkPluginABI ("core", CORE_ABIVERSION))
|
|
return FALSE;
|
|
|
|
rd = malloc (sizeof (ResizeDisplay));
|
|
if (!rd)
|
|
return FALSE;
|
|
|
|
if (!compInitDisplayOptionsFromMetadata (d,
|
|
&resizeMetadata,
|
|
resizeDisplayOptionInfo,
|
|
rd->opt,
|
|
RESIZE_DISPLAY_OPTION_NUM))
|
|
{
|
|
free (rd);
|
|
return FALSE;
|
|
}
|
|
|
|
rd->screenPrivateIndex = allocateScreenPrivateIndex (d);
|
|
if (rd->screenPrivateIndex < 0)
|
|
{
|
|
compFiniDisplayOptions (d, rd->opt, RESIZE_DISPLAY_OPTION_NUM);
|
|
free (rd);
|
|
return FALSE;
|
|
}
|
|
|
|
rd->w = 0;
|
|
|
|
rd->releaseButton = 0;
|
|
|
|
rd->resizeNotifyAtom = XInternAtom (d->display,
|
|
"_COMPIZ_RESIZE_NOTIFY", 0);
|
|
rd->resizeInformationAtom = XInternAtom (d->display,
|
|
"_COMPIZ_RESIZE_INFORMATION", 0);
|
|
|
|
for (i = 0; i < NUM_KEYS; i++)
|
|
rd->key[i] = XKeysymToKeycode (d->display,
|
|
XStringToKeysym (rKeys[i].name));
|
|
|
|
rd->offWorkAreaConstrained = TRUE;
|
|
|
|
WRAP (rd, d, handleEvent, resizeHandleEvent);
|
|
|
|
d->base.privates[displayPrivateIndex].ptr = rd;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
resizeFiniDisplay (CompPlugin *p,
|
|
CompDisplay *d)
|
|
{
|
|
RESIZE_DISPLAY (d);
|
|
|
|
freeScreenPrivateIndex (d, rd->screenPrivateIndex);
|
|
|
|
UNWRAP (rd, d, handleEvent);
|
|
|
|
compFiniDisplayOptions (d, rd->opt, RESIZE_DISPLAY_OPTION_NUM);
|
|
|
|
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;
|
|
|
|
rs->grabWindowWorkArea = NULL;
|
|
|
|
WRAP (rs, s, windowResizeNotify, resizeWindowResizeNotify);
|
|
WRAP (rs, s, paintOutput, resizePaintOutput);
|
|
WRAP (rs, s, paintWindow, resizePaintWindow);
|
|
WRAP (rs, s, damageWindowRect, resizeDamageWindowRect);
|
|
|
|
s->base.privates[rd->screenPrivateIndex].ptr = rs;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
resizeFiniScreen (CompPlugin *p,
|
|
CompScreen *s)
|
|
{
|
|
RESIZE_SCREEN (s);
|
|
|
|
if (rs->leftCursor)
|
|
XFreeCursor (s->display->display, rs->leftCursor);
|
|
if (rs->rightCursor)
|
|
XFreeCursor (s->display->display, rs->rightCursor);
|
|
if (rs->upCursor)
|
|
XFreeCursor (s->display->display, rs->upCursor);
|
|
if (rs->downCursor)
|
|
XFreeCursor (s->display->display, rs->downCursor);
|
|
if (rs->middleCursor)
|
|
XFreeCursor (s->display->display, rs->middleCursor);
|
|
if (rs->upLeftCursor)
|
|
XFreeCursor (s->display->display, rs->upLeftCursor);
|
|
if (rs->upRightCursor)
|
|
XFreeCursor (s->display->display, rs->upRightCursor);
|
|
if (rs->downLeftCursor)
|
|
XFreeCursor (s->display->display, rs->downLeftCursor);
|
|
if (rs->downRightCursor)
|
|
XFreeCursor (s->display->display, rs->downRightCursor);
|
|
|
|
UNWRAP (rs, s, windowResizeNotify);
|
|
UNWRAP (rs, s, paintOutput);
|
|
UNWRAP (rs, s, paintWindow);
|
|
UNWRAP (rs, s, damageWindowRect);
|
|
|
|
free (rs);
|
|
}
|
|
|
|
static CompBool
|
|
resizeInitObject (CompPlugin *p,
|
|
CompObject *o)
|
|
{
|
|
static InitPluginObjectProc dispTab[] = {
|
|
(InitPluginObjectProc) 0, /* InitCore */
|
|
(InitPluginObjectProc) resizeInitDisplay,
|
|
(InitPluginObjectProc) resizeInitScreen
|
|
};
|
|
|
|
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
|
|
}
|
|
|
|
static void
|
|
resizeFiniObject (CompPlugin *p,
|
|
CompObject *o)
|
|
{
|
|
static FiniPluginObjectProc dispTab[] = {
|
|
(FiniPluginObjectProc) 0, /* FiniCore */
|
|
(FiniPluginObjectProc) resizeFiniDisplay,
|
|
(FiniPluginObjectProc) resizeFiniScreen
|
|
};
|
|
|
|
DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
|
|
}
|
|
|
|
static CompOption *
|
|
resizeGetObjectOptions (CompPlugin *plugin,
|
|
CompObject *object,
|
|
int *count)
|
|
{
|
|
static GetPluginObjectOptionsProc dispTab[] = {
|
|
(GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
|
|
(GetPluginObjectOptionsProc) resizeGetDisplayOptions
|
|
};
|
|
|
|
*count = 0;
|
|
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
|
|
(void *) count, (plugin, object, count));
|
|
}
|
|
|
|
static CompBool
|
|
resizeSetObjectOption (CompPlugin *plugin,
|
|
CompObject *object,
|
|
const char *name,
|
|
CompOptionValue *value)
|
|
{
|
|
static SetPluginObjectOptionProc dispTab[] = {
|
|
(SetPluginObjectOptionProc) 0, /* SetCoreOption */
|
|
(SetPluginObjectOptionProc) resizeSetDisplayOption
|
|
};
|
|
|
|
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
|
|
(plugin, object, name, value));
|
|
}
|
|
|
|
static Bool
|
|
resizeInit (CompPlugin *p)
|
|
{
|
|
if (!compInitPluginMetadataFromInfo (&resizeMetadata,
|
|
p->vTable->name,
|
|
resizeDisplayOptionInfo,
|
|
RESIZE_DISPLAY_OPTION_NUM,
|
|
0, 0))
|
|
return FALSE;
|
|
|
|
displayPrivateIndex = allocateDisplayPrivateIndex ();
|
|
if (displayPrivateIndex < 0)
|
|
{
|
|
compFiniMetadata (&resizeMetadata);
|
|
return FALSE;
|
|
}
|
|
|
|
compAddMetadataFromFile (&resizeMetadata, p->vTable->name);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
resizeFini (CompPlugin *p)
|
|
{
|
|
freeDisplayPrivateIndex (displayPrivateIndex);
|
|
compFiniMetadata (&resizeMetadata);
|
|
}
|
|
|
|
static CompMetadata *
|
|
resizeGetMetadata (CompPlugin *plugin)
|
|
{
|
|
return &resizeMetadata;
|
|
}
|
|
|
|
CompPluginVTable resizeVTable = {
|
|
"resize",
|
|
resizeGetMetadata,
|
|
resizeInit,
|
|
resizeFini,
|
|
resizeInitObject,
|
|
resizeFiniObject,
|
|
resizeGetObjectOptions,
|
|
resizeSetObjectOption
|
|
};
|
|
|
|
CompPluginVTable *
|
|
getCompPluginInfo20070830 (void)
|
|
{
|
|
return &resizeVTable;
|
|
}
|