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.
1068 lines
24 KiB
1068 lines
24 KiB
4 years ago
|
/*
|
||
|
* 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/cursorfont.h>
|
||
|
|
||
|
#include <compiz-core.h>
|
||
|
|
||
|
static CompMetadata moveMetadata;
|
||
|
|
||
|
struct _MoveKeys {
|
||
|
char *name;
|
||
|
int dx;
|
||
|
int dy;
|
||
|
} mKeys[] = {
|
||
|
{ "Left", -1, 0 },
|
||
|
{ "Right", 1, 0 },
|
||
|
{ "Up", 0, -1 },
|
||
|
{ "Down", 0, 1 }
|
||
|
};
|
||
|
|
||
|
#define NUM_KEYS (sizeof (mKeys) / sizeof (mKeys[0]))
|
||
|
|
||
|
#define KEY_MOVE_INC 24
|
||
|
|
||
|
#define SNAP_BACK 20
|
||
|
#define SNAP_OFF 100
|
||
|
|
||
|
static int displayPrivateIndex;
|
||
|
|
||
|
#define MOVE_DISPLAY_OPTION_INITIATE_BUTTON 0
|
||
|
#define MOVE_DISPLAY_OPTION_INITIATE_KEY 1
|
||
|
#define MOVE_DISPLAY_OPTION_OPACITY 2
|
||
|
#define MOVE_DISPLAY_OPTION_CONSTRAIN_Y 3
|
||
|
#define MOVE_DISPLAY_OPTION_SNAPOFF_MAXIMIZED 4
|
||
|
#define MOVE_DISPLAY_OPTION_LAZY_POSITIONING 5
|
||
|
#define MOVE_DISPLAY_OPTION_NUM 6
|
||
|
|
||
|
typedef struct _MoveDisplay {
|
||
|
int screenPrivateIndex;
|
||
|
HandleEventProc handleEvent;
|
||
|
|
||
|
CompOption opt[MOVE_DISPLAY_OPTION_NUM];
|
||
|
|
||
|
CompWindow *w;
|
||
|
int savedX;
|
||
|
int savedY;
|
||
|
int x;
|
||
|
int y;
|
||
|
Region region;
|
||
|
int status;
|
||
|
Bool constrainY;
|
||
|
KeyCode key[NUM_KEYS];
|
||
|
|
||
|
int releaseButton;
|
||
|
|
||
|
GLushort moveOpacity;
|
||
|
} MoveDisplay;
|
||
|
|
||
|
typedef struct _MoveScreen {
|
||
|
PaintWindowProc paintWindow;
|
||
|
|
||
|
int grabIndex;
|
||
|
|
||
|
Cursor moveCursor;
|
||
|
|
||
|
unsigned int origState;
|
||
|
|
||
|
int snapOffY;
|
||
|
int snapBackY;
|
||
|
} MoveScreen;
|
||
|
|
||
|
#define GET_MOVE_DISPLAY(d) \
|
||
|
((MoveDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
|
||
|
|
||
|
#define MOVE_DISPLAY(d) \
|
||
|
MoveDisplay *md = GET_MOVE_DISPLAY (d)
|
||
|
|
||
|
#define GET_MOVE_SCREEN(s, md) \
|
||
|
((MoveScreen *) (s)->base.privates[(md)->screenPrivateIndex].ptr)
|
||
|
|
||
|
#define MOVE_SCREEN(s) \
|
||
|
MoveScreen *ms = GET_MOVE_SCREEN (s, GET_MOVE_DISPLAY (s->display))
|
||
|
|
||
|
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
|
||
|
|
||
|
static Bool
|
||
|
moveInitiate (CompDisplay *d,
|
||
|
CompAction *action,
|
||
|
CompActionState state,
|
||
|
CompOption *option,
|
||
|
int nOption)
|
||
|
{
|
||
|
CompWindow *w;
|
||
|
Window xid;
|
||
|
|
||
|
MOVE_DISPLAY (d);
|
||
|
|
||
|
xid = getIntOptionNamed (option, nOption, "window", 0);
|
||
|
|
||
|
w = findWindowAtDisplay (d, xid);
|
||
|
if (w && (w->actions & CompWindowActionMoveMask))
|
||
|
{
|
||
|
XRectangle workArea;
|
||
|
unsigned int mods;
|
||
|
int x, y, button;
|
||
|
Bool sourceExternalApp;
|
||
|
|
||
|
MOVE_SCREEN (w->screen);
|
||
|
|
||
|
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);
|
||
|
|
||
|
if (otherScreenGrabExist (w->screen, "move", NULL))
|
||
|
return FALSE;
|
||
|
|
||
|
if (md->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 (md->region)
|
||
|
{
|
||
|
XDestroyRegion (md->region);
|
||
|
md->region = NULL;
|
||
|
}
|
||
|
|
||
|
md->status = RectangleOut;
|
||
|
|
||
|
md->savedX = w->serverX;
|
||
|
md->savedY = w->serverY;
|
||
|
|
||
|
md->x = 0;
|
||
|
md->y = 0;
|
||
|
|
||
|
sourceExternalApp = getBoolOptionNamed (option, nOption, "external",
|
||
|
FALSE);
|
||
|
md->constrainY = sourceExternalApp &&
|
||
|
md->opt[MOVE_DISPLAY_OPTION_CONSTRAIN_Y].value.b;
|
||
|
|
||
|
lastPointerX = x;
|
||
|
lastPointerY = y;
|
||
|
|
||
|
ms->origState = w->state;
|
||
|
|
||
|
getWorkareaForOutput (w->screen,
|
||
|
outputDeviceForWindow (w),
|
||
|
&workArea);
|
||
|
|
||
|
ms->snapBackY = w->serverY - workArea.y;
|
||
|
ms->snapOffY = y - workArea.y;
|
||
|
|
||
|
if (!ms->grabIndex)
|
||
|
ms->grabIndex = pushScreenGrab (w->screen, ms->moveCursor, "move");
|
||
|
|
||
|
if (ms->grabIndex)
|
||
|
{
|
||
|
unsigned int grabMask = CompWindowGrabMoveMask |
|
||
|
CompWindowGrabButtonMask;
|
||
|
|
||
|
if (sourceExternalApp)
|
||
|
grabMask |= CompWindowGrabExternalAppMask;
|
||
|
|
||
|
md->w = w;
|
||
|
|
||
|
md->releaseButton = button;
|
||
|
|
||
|
(w->screen->windowGrabNotify) (w, x, y, mods, grabMask);
|
||
|
|
||
|
if (d->opt[COMP_DISPLAY_OPTION_RAISE_ON_CLICK].value.b)
|
||
|
updateWindowAttributes (w,
|
||
|
CompStackingUpdateModeAboveFullscreen);
|
||
|
|
||
|
if (state & CompActionStateInitKey)
|
||
|
{
|
||
|
int xRoot, yRoot;
|
||
|
|
||
|
xRoot = w->attrib.x + (w->width / 2);
|
||
|
yRoot = w->attrib.y + (w->height / 2);
|
||
|
|
||
|
warpPointer (w->screen, xRoot - pointerX, yRoot - pointerY);
|
||
|
}
|
||
|
|
||
|
if (md->moveOpacity != OPAQUE)
|
||
|
addWindowDamage (w);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
moveTerminate (CompDisplay *d,
|
||
|
CompAction *action,
|
||
|
CompActionState state,
|
||
|
CompOption *option,
|
||
|
int nOption)
|
||
|
{
|
||
|
MOVE_DISPLAY (d);
|
||
|
|
||
|
if (md->w)
|
||
|
{
|
||
|
MOVE_SCREEN (md->w->screen);
|
||
|
|
||
|
if (state & CompActionStateCancel)
|
||
|
moveWindow (md->w,
|
||
|
md->savedX - md->w->attrib.x,
|
||
|
md->savedY - md->w->attrib.y,
|
||
|
TRUE, FALSE);
|
||
|
|
||
|
syncWindowPosition (md->w);
|
||
|
|
||
|
/* update window attributes as window constraints may have
|
||
|
changed - needed e.g. if a maximized window was moved
|
||
|
to another output device */
|
||
|
updateWindowAttributes (md->w, CompStackingUpdateModeNone);
|
||
|
|
||
|
(md->w->screen->windowUngrabNotify) (md->w);
|
||
|
|
||
|
if (ms->grabIndex)
|
||
|
{
|
||
|
removeScreenGrab (md->w->screen, ms->grabIndex, NULL);
|
||
|
ms->grabIndex = 0;
|
||
|
}
|
||
|
|
||
|
if (md->moveOpacity != OPAQUE)
|
||
|
addWindowDamage (md->w);
|
||
|
|
||
|
md->w = 0;
|
||
|
md->releaseButton = 0;
|
||
|
}
|
||
|
|
||
|
action->state &= ~(CompActionStateTermKey | CompActionStateTermButton);
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/* creates a region containing top and bottom struts. only struts that are
|
||
|
outside the screen workarea are considered. */
|
||
|
static Region
|
||
|
moveGetYConstrainRegion (CompScreen *s)
|
||
|
{
|
||
|
CompWindow *w;
|
||
|
Region region;
|
||
|
REGION r;
|
||
|
XRectangle workArea;
|
||
|
BoxRec extents;
|
||
|
int i;
|
||
|
|
||
|
region = XCreateRegion ();
|
||
|
if (!region)
|
||
|
return NULL;
|
||
|
|
||
|
r.rects = &r.extents;
|
||
|
r.numRects = r.size = 1;
|
||
|
|
||
|
r.extents.x1 = MINSHORT;
|
||
|
r.extents.y1 = 0;
|
||
|
r.extents.x2 = 0;
|
||
|
r.extents.y2 = s->height;
|
||
|
|
||
|
XUnionRegion (&r, region, region);
|
||
|
|
||
|
r.extents.x1 = s->width;
|
||
|
r.extents.x2 = MAXSHORT;
|
||
|
|
||
|
XUnionRegion (&r, region, region);
|
||
|
|
||
|
for (i = 0; i < s->nOutputDev; i++)
|
||
|
{
|
||
|
XUnionRegion (&s->outputDev[i].region, region, region);
|
||
|
|
||
|
getWorkareaForOutput (s, i, &workArea);
|
||
|
extents = s->outputDev[i].region.extents;
|
||
|
|
||
|
for (w = s->windows; w; w = w->next)
|
||
|
{
|
||
|
if (!w->mapNum)
|
||
|
continue;
|
||
|
|
||
|
if (w->struts)
|
||
|
{
|
||
|
r.extents.x1 = w->struts->top.x;
|
||
|
r.extents.y1 = w->struts->top.y;
|
||
|
r.extents.x2 = r.extents.x1 + w->struts->top.width;
|
||
|
r.extents.y2 = r.extents.y1 + w->struts->top.height;
|
||
|
|
||
|
if (r.extents.x1 < extents.x1)
|
||
|
r.extents.x1 = extents.x1;
|
||
|
if (r.extents.x2 > extents.x2)
|
||
|
r.extents.x2 = extents.x2;
|
||
|
if (r.extents.y1 < extents.y1)
|
||
|
r.extents.y1 = extents.y1;
|
||
|
if (r.extents.y2 > extents.y2)
|
||
|
r.extents.y2 = extents.y2;
|
||
|
|
||
|
if (r.extents.x1 < r.extents.x2 && r.extents.y1 < r.extents.y2)
|
||
|
{
|
||
|
if (r.extents.y2 <= workArea.y)
|
||
|
XSubtractRegion (region, &r, region);
|
||
|
}
|
||
|
|
||
|
r.extents.x1 = w->struts->bottom.x;
|
||
|
r.extents.y1 = w->struts->bottom.y;
|
||
|
r.extents.x2 = r.extents.x1 + w->struts->bottom.width;
|
||
|
r.extents.y2 = r.extents.y1 + w->struts->bottom.height;
|
||
|
|
||
|
if (r.extents.x1 < extents.x1)
|
||
|
r.extents.x1 = extents.x1;
|
||
|
if (r.extents.x2 > extents.x2)
|
||
|
r.extents.x2 = extents.x2;
|
||
|
if (r.extents.y1 < extents.y1)
|
||
|
r.extents.y1 = extents.y1;
|
||
|
if (r.extents.y2 > extents.y2)
|
||
|
r.extents.y2 = extents.y2;
|
||
|
|
||
|
if (r.extents.x1 < r.extents.x2 && r.extents.y1 < r.extents.y2)
|
||
|
{
|
||
|
if (r.extents.y1 >= (workArea.y + workArea.height))
|
||
|
XSubtractRegion (region, &r, region);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return region;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
moveHandleMotionEvent (CompScreen *s,
|
||
|
int xRoot,
|
||
|
int yRoot)
|
||
|
{
|
||
|
MOVE_SCREEN (s);
|
||
|
|
||
|
if (ms->grabIndex)
|
||
|
{
|
||
|
CompWindow *w;
|
||
|
int dx, dy;
|
||
|
int wX, wY;
|
||
|
int wWidth, wHeight;
|
||
|
|
||
|
MOVE_DISPLAY (s->display);
|
||
|
|
||
|
w = md->w;
|
||
|
|
||
|
wX = w->serverX;
|
||
|
wY = w->serverY;
|
||
|
wWidth = w->serverWidth + w->serverBorderWidth * 2;
|
||
|
wHeight = w->serverHeight + w->serverBorderWidth * 2;
|
||
|
|
||
|
md->x += xRoot - lastPointerX;
|
||
|
md->y += yRoot - lastPointerY;
|
||
|
|
||
|
if (w->type & CompWindowTypeFullscreenMask)
|
||
|
{
|
||
|
dx = dy = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
XRectangle workArea;
|
||
|
int min, max;
|
||
|
|
||
|
dx = md->x;
|
||
|
dy = md->y;
|
||
|
|
||
|
getWorkareaForOutput (s,
|
||
|
outputDeviceForWindow (w),
|
||
|
&workArea);
|
||
|
|
||
|
if (md->constrainY)
|
||
|
{
|
||
|
if (!md->region)
|
||
|
md->region = moveGetYConstrainRegion (s);
|
||
|
|
||
|
/* make sure that the top frame extents or the top row of
|
||
|
pixels are within what is currently our valid screen
|
||
|
region */
|
||
|
if (md->region)
|
||
|
{
|
||
|
int x, y, width, height;
|
||
|
int status;
|
||
|
|
||
|
x = wX + dx - w->input.left;
|
||
|
y = wY + dy - w->input.top;
|
||
|
width = wWidth + w->input.left + w->input.right;
|
||
|
height = w->input.top ? w->input.top : 1;
|
||
|
|
||
|
status = XRectInRegion (md->region, x, y, width, height);
|
||
|
|
||
|
/* only constrain movement if previous position was valid */
|
||
|
if (md->status == RectangleIn)
|
||
|
{
|
||
|
int xStatus = status;
|
||
|
|
||
|
while (dx && xStatus != RectangleIn)
|
||
|
{
|
||
|
xStatus = XRectInRegion (md->region,
|
||
|
x, y - dy,
|
||
|
width, height);
|
||
|
|
||
|
if (xStatus != RectangleIn)
|
||
|
dx += (dx < 0) ? 1 : -1;
|
||
|
|
||
|
x = wX + dx - w->input.left;
|
||
|
}
|
||
|
|
||
|
while (dy && status != RectangleIn)
|
||
|
{
|
||
|
status = XRectInRegion (md->region,
|
||
|
x, y,
|
||
|
width, height);
|
||
|
|
||
|
if (status != RectangleIn)
|
||
|
dy += (dy < 0) ? 1 : -1;
|
||
|
|
||
|
y = wY + dy - w->input.top;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
md->status = status;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (md->opt[MOVE_DISPLAY_OPTION_SNAPOFF_MAXIMIZED].value.b)
|
||
|
{
|
||
|
if (w->state & CompWindowStateMaximizedVertMask)
|
||
|
{
|
||
|
if (abs ((yRoot - workArea.y) - ms->snapOffY) >= SNAP_OFF)
|
||
|
{
|
||
|
if (!otherScreenGrabExist (s, "move", NULL))
|
||
|
{
|
||
|
int width = w->serverWidth;
|
||
|
|
||
|
w->saveMask |= CWX | CWY;
|
||
|
|
||
|
if (w->saveMask & CWWidth)
|
||
|
width = w->saveWc.width;
|
||
|
|
||
|
w->saveWc.x = xRoot - (width >> 1);
|
||
|
w->saveWc.y = yRoot + (w->input.top >> 1);
|
||
|
|
||
|
md->x = md->y = 0;
|
||
|
|
||
|
maximizeWindow (w, 0);
|
||
|
|
||
|
ms->snapOffY = ms->snapBackY;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (ms->origState & CompWindowStateMaximizedVertMask)
|
||
|
{
|
||
|
if (abs ((yRoot - workArea.y) - ms->snapBackY) < SNAP_BACK)
|
||
|
{
|
||
|
if (!otherScreenGrabExist (s, "move", NULL))
|
||
|
{
|
||
|
int wy;
|
||
|
|
||
|
/* update server position before maximizing
|
||
|
window again so that it is maximized on
|
||
|
correct output */
|
||
|
syncWindowPosition (w);
|
||
|
|
||
|
maximizeWindow (w, ms->origState);
|
||
|
|
||
|
wy = workArea.y + (w->input.top >> 1);
|
||
|
wy += w->sizeHints.height_inc >> 1;
|
||
|
|
||
|
warpPointer (s, 0, wy - pointerY);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (w->state & CompWindowStateMaximizedVertMask)
|
||
|
{
|
||
|
min = workArea.y + w->input.top;
|
||
|
max = workArea.y + workArea.height - w->input.bottom - wHeight;
|
||
|
|
||
|
if (wY + dy < min)
|
||
|
dy = min - wY;
|
||
|
else if (wY + dy > max)
|
||
|
dy = max - wY;
|
||
|
}
|
||
|
|
||
|
if (w->state & CompWindowStateMaximizedHorzMask)
|
||
|
{
|
||
|
if (wX > s->width || wX + w->width < 0)
|
||
|
return;
|
||
|
|
||
|
if (wX + wWidth < 0)
|
||
|
return;
|
||
|
|
||
|
min = workArea.x + w->input.left;
|
||
|
max = workArea.x + workArea.width - w->input.right - wWidth;
|
||
|
|
||
|
if (wX + dx < min)
|
||
|
dx = min - wX;
|
||
|
else if (wX + dx > max)
|
||
|
dx = max - wX;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (dx || dy)
|
||
|
{
|
||
|
moveWindow (w,
|
||
|
wX + dx - w->attrib.x,
|
||
|
wY + dy - w->attrib.y,
|
||
|
TRUE, FALSE);
|
||
|
|
||
|
if (md->opt[MOVE_DISPLAY_OPTION_LAZY_POSITIONING].value.b)
|
||
|
{
|
||
|
/* FIXME: This form of lazy positioning is broken and should
|
||
|
be replaced asap. Current code exists just to avoid a
|
||
|
major performance regression in the 0.5.2 release. */
|
||
|
w->serverX = w->attrib.x;
|
||
|
w->serverY = w->attrib.y;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
syncWindowPosition (w);
|
||
|
}
|
||
|
|
||
|
md->x -= dx;
|
||
|
md->y -= dy;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
moveHandleEvent (CompDisplay *d,
|
||
|
XEvent *event)
|
||
|
{
|
||
|
CompScreen *s;
|
||
|
|
||
|
MOVE_DISPLAY (d);
|
||
|
|
||
|
switch (event->type) {
|
||
|
case ButtonPress:
|
||
|
case ButtonRelease:
|
||
|
s = findScreenAtDisplay (d, event->xbutton.root);
|
||
|
if (s)
|
||
|
{
|
||
|
MOVE_SCREEN (s);
|
||
|
|
||
|
if (ms->grabIndex)
|
||
|
{
|
||
|
if (md->releaseButton == -1 ||
|
||
|
md->releaseButton == event->xbutton.button)
|
||
|
{
|
||
|
CompAction *action;
|
||
|
int opt = MOVE_DISPLAY_OPTION_INITIATE_BUTTON;
|
||
|
|
||
|
action = &md->opt[opt].value.action;
|
||
|
moveTerminate (d, action, CompActionStateTermButton,
|
||
|
NULL, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case KeyPress:
|
||
|
s = findScreenAtDisplay (d, event->xkey.root);
|
||
|
if (s)
|
||
|
{
|
||
|
MOVE_SCREEN (s);
|
||
|
|
||
|
if (ms->grabIndex)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < NUM_KEYS; i++)
|
||
|
{
|
||
|
if (event->xkey.keycode == md->key[i])
|
||
|
{
|
||
|
XWarpPointer (d->display, None, None, 0, 0, 0, 0,
|
||
|
mKeys[i].dx * KEY_MOVE_INC,
|
||
|
mKeys[i].dy * KEY_MOVE_INC);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case MotionNotify:
|
||
|
s = findScreenAtDisplay (d, event->xmotion.root);
|
||
|
if (s)
|
||
|
moveHandleMotionEvent (s, pointerX, pointerY);
|
||
|
break;
|
||
|
case EnterNotify:
|
||
|
case LeaveNotify:
|
||
|
s = findScreenAtDisplay (d, event->xcrossing.root);
|
||
|
if (s)
|
||
|
moveHandleMotionEvent (s, pointerX, pointerY);
|
||
|
break;
|
||
|
case ClientMessage:
|
||
|
if (event->xclient.message_type == d->wmMoveResizeAtom)
|
||
|
{
|
||
|
CompWindow *w;
|
||
|
|
||
|
if (event->xclient.data.l[2] == WmMoveResizeMove ||
|
||
|
event->xclient.data.l[2] == WmMoveResizeMoveKeyboard)
|
||
|
{
|
||
|
w = findWindowAtDisplay (d, event->xclient.window);
|
||
|
if (w)
|
||
|
{
|
||
|
CompOption o[6];
|
||
|
int xRoot, yRoot;
|
||
|
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] == WmMoveResizeMoveKeyboard)
|
||
|
{
|
||
|
option = MOVE_DISPLAY_OPTION_INITIATE_KEY;
|
||
|
|
||
|
moveInitiate (d, &md->opt[option].value.action,
|
||
|
CompActionStateInitKey,
|
||
|
o, 2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
unsigned int mods;
|
||
|
Window root, child;
|
||
|
int i;
|
||
|
|
||
|
option = MOVE_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 = "button";
|
||
|
o[5].value.i = event->xclient.data.l[3] ?
|
||
|
event->xclient.data.l[3] : -1;
|
||
|
|
||
|
moveInitiate (d,
|
||
|
&md->opt[option].value.action,
|
||
|
CompActionStateInitButton,
|
||
|
o, 6);
|
||
|
|
||
|
moveHandleMotionEvent (w->screen, xRoot, yRoot);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (md->w && event->xclient.data.l[2] == WmMoveResizeCancel)
|
||
|
{
|
||
|
if (md->w->id == event->xclient.window)
|
||
|
{
|
||
|
int option;
|
||
|
|
||
|
option = MOVE_DISPLAY_OPTION_INITIATE_BUTTON;
|
||
|
moveTerminate (d,
|
||
|
&md->opt[option].value.action,
|
||
|
CompActionStateCancel, NULL, 0);
|
||
|
option = MOVE_DISPLAY_OPTION_INITIATE_KEY;
|
||
|
moveTerminate (d,
|
||
|
&md->opt[option].value.action,
|
||
|
CompActionStateCancel, NULL, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case DestroyNotify:
|
||
|
if (md->w && md->w->id == event->xdestroywindow.window)
|
||
|
{
|
||
|
int option;
|
||
|
|
||
|
option = MOVE_DISPLAY_OPTION_INITIATE_BUTTON;
|
||
|
moveTerminate (d,
|
||
|
&md->opt[option].value.action,
|
||
|
0, NULL, 0);
|
||
|
option = MOVE_DISPLAY_OPTION_INITIATE_KEY;
|
||
|
moveTerminate (d,
|
||
|
&md->opt[option].value.action,
|
||
|
0, NULL, 0);
|
||
|
}
|
||
|
break;
|
||
|
case UnmapNotify:
|
||
|
if (md->w && md->w->id == event->xunmap.window)
|
||
|
{
|
||
|
int option;
|
||
|
|
||
|
option = MOVE_DISPLAY_OPTION_INITIATE_BUTTON;
|
||
|
moveTerminate (d,
|
||
|
&md->opt[option].value.action,
|
||
|
0, NULL, 0);
|
||
|
option = MOVE_DISPLAY_OPTION_INITIATE_KEY;
|
||
|
moveTerminate (d,
|
||
|
&md->opt[option].value.action,
|
||
|
0, NULL, 0);
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
UNWRAP (md, d, handleEvent);
|
||
|
(*d->handleEvent) (d, event);
|
||
|
WRAP (md, d, handleEvent, moveHandleEvent);
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
movePaintWindow (CompWindow *w,
|
||
|
const WindowPaintAttrib *attrib,
|
||
|
const CompTransform *transform,
|
||
|
Region region,
|
||
|
unsigned int mask)
|
||
|
{
|
||
|
WindowPaintAttrib sAttrib;
|
||
|
CompScreen *s = w->screen;
|
||
|
Bool status;
|
||
|
|
||
|
MOVE_SCREEN (s);
|
||
|
|
||
|
if (ms->grabIndex)
|
||
|
{
|
||
|
MOVE_DISPLAY (s->display);
|
||
|
|
||
|
if (md->w == w && md->moveOpacity != OPAQUE)
|
||
|
{
|
||
|
/* modify opacity of windows that are not active */
|
||
|
sAttrib = *attrib;
|
||
|
attrib = &sAttrib;
|
||
|
|
||
|
sAttrib.opacity = (sAttrib.opacity * md->moveOpacity) >> 16;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
UNWRAP (ms, s, paintWindow);
|
||
|
status = (*s->paintWindow) (w, attrib, transform, region, mask);
|
||
|
WRAP (ms, s, paintWindow, movePaintWindow);
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
static CompOption *
|
||
|
moveGetDisplayOptions (CompPlugin *plugin,
|
||
|
CompDisplay *display,
|
||
|
int *count)
|
||
|
{
|
||
|
MOVE_DISPLAY (display);
|
||
|
|
||
|
*count = NUM_OPTIONS (md);
|
||
|
return md->opt;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
moveSetDisplayOption (CompPlugin *plugin,
|
||
|
CompDisplay *display,
|
||
|
const char *name,
|
||
|
CompOptionValue *value)
|
||
|
{
|
||
|
CompOption *o;
|
||
|
int index;
|
||
|
|
||
|
MOVE_DISPLAY (display);
|
||
|
|
||
|
o = compFindOption (md->opt, NUM_OPTIONS (md), name, &index);
|
||
|
if (!o)
|
||
|
return FALSE;
|
||
|
|
||
|
switch (index) {
|
||
|
case MOVE_DISPLAY_OPTION_OPACITY:
|
||
|
if (compSetIntOption (o, value))
|
||
|
{
|
||
|
md->moveOpacity = (o->value.i * OPAQUE) / 100;
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
return compSetDisplayOption (display, o, value);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static const CompMetadataOptionInfo moveDisplayOptionInfo[] = {
|
||
|
{ "initiate_button", "button", 0, moveInitiate, moveTerminate },
|
||
|
{ "initiate_key", "key", 0, moveInitiate, moveTerminate },
|
||
|
{ "opacity", "int", "<min>0</min><max>100</max>", 0, 0 },
|
||
|
{ "constrain_y", "bool", 0, 0, 0 },
|
||
|
{ "snapoff_maximized", "bool", 0, 0, 0 },
|
||
|
{ "lazy_positioning", "bool", 0, 0, 0 }
|
||
|
};
|
||
|
|
||
|
static Bool
|
||
|
moveInitDisplay (CompPlugin *p,
|
||
|
CompDisplay *d)
|
||
|
{
|
||
|
MoveDisplay *md;
|
||
|
int i;
|
||
|
|
||
|
if (!checkPluginABI ("core", CORE_ABIVERSION))
|
||
|
return FALSE;
|
||
|
|
||
|
md = malloc (sizeof (MoveDisplay));
|
||
|
if (!md)
|
||
|
return FALSE;
|
||
|
|
||
|
if (!compInitDisplayOptionsFromMetadata (d,
|
||
|
&moveMetadata,
|
||
|
moveDisplayOptionInfo,
|
||
|
md->opt,
|
||
|
MOVE_DISPLAY_OPTION_NUM))
|
||
|
{
|
||
|
free (md);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
md->screenPrivateIndex = allocateScreenPrivateIndex (d);
|
||
|
if (md->screenPrivateIndex < 0)
|
||
|
{
|
||
|
compFiniDisplayOptions (d, md->opt, MOVE_DISPLAY_OPTION_NUM);
|
||
|
free (md);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
md->moveOpacity =
|
||
|
(md->opt[MOVE_DISPLAY_OPTION_OPACITY].value.i * OPAQUE) / 100;
|
||
|
|
||
|
md->w = 0;
|
||
|
md->region = NULL;
|
||
|
md->status = RectangleOut;
|
||
|
md->releaseButton = 0;
|
||
|
md->constrainY = FALSE;
|
||
|
|
||
|
for (i = 0; i < NUM_KEYS; i++)
|
||
|
md->key[i] = XKeysymToKeycode (d->display,
|
||
|
XStringToKeysym (mKeys[i].name));
|
||
|
|
||
|
WRAP (md, d, handleEvent, moveHandleEvent);
|
||
|
|
||
|
d->base.privates[displayPrivateIndex].ptr = md;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
moveFiniDisplay (CompPlugin *p,
|
||
|
CompDisplay *d)
|
||
|
{
|
||
|
MOVE_DISPLAY (d);
|
||
|
|
||
|
freeScreenPrivateIndex (d, md->screenPrivateIndex);
|
||
|
|
||
|
UNWRAP (md, d, handleEvent);
|
||
|
|
||
|
compFiniDisplayOptions (d, md->opt, MOVE_DISPLAY_OPTION_NUM);
|
||
|
|
||
|
if (md->region)
|
||
|
XDestroyRegion (md->region);
|
||
|
|
||
|
free (md);
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
moveInitScreen (CompPlugin *p,
|
||
|
CompScreen *s)
|
||
|
{
|
||
|
MoveScreen *ms;
|
||
|
|
||
|
MOVE_DISPLAY (s->display);
|
||
|
|
||
|
ms = malloc (sizeof (MoveScreen));
|
||
|
if (!ms)
|
||
|
return FALSE;
|
||
|
|
||
|
ms->grabIndex = 0;
|
||
|
|
||
|
ms->moveCursor = XCreateFontCursor (s->display->display, XC_fleur);
|
||
|
|
||
|
WRAP (ms, s, paintWindow, movePaintWindow);
|
||
|
|
||
|
s->base.privates[md->screenPrivateIndex].ptr = ms;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
moveFiniScreen (CompPlugin *p,
|
||
|
CompScreen *s)
|
||
|
{
|
||
|
MOVE_SCREEN (s);
|
||
|
|
||
|
UNWRAP (ms, s, paintWindow);
|
||
|
|
||
|
if (ms->moveCursor)
|
||
|
XFreeCursor (s->display->display, ms->moveCursor);
|
||
|
|
||
|
free (ms);
|
||
|
}
|
||
|
|
||
|
static CompBool
|
||
|
moveInitObject (CompPlugin *p,
|
||
|
CompObject *o)
|
||
|
{
|
||
|
static InitPluginObjectProc dispTab[] = {
|
||
|
(InitPluginObjectProc) 0, /* InitCore */
|
||
|
(InitPluginObjectProc) moveInitDisplay,
|
||
|
(InitPluginObjectProc) moveInitScreen
|
||
|
};
|
||
|
|
||
|
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
moveFiniObject (CompPlugin *p,
|
||
|
CompObject *o)
|
||
|
{
|
||
|
static FiniPluginObjectProc dispTab[] = {
|
||
|
(FiniPluginObjectProc) 0, /* FiniCore */
|
||
|
(FiniPluginObjectProc) moveFiniDisplay,
|
||
|
(FiniPluginObjectProc) moveFiniScreen
|
||
|
};
|
||
|
|
||
|
DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
|
||
|
}
|
||
|
|
||
|
static CompOption *
|
||
|
moveGetObjectOptions (CompPlugin *plugin,
|
||
|
CompObject *object,
|
||
|
int *count)
|
||
|
{
|
||
|
static GetPluginObjectOptionsProc dispTab[] = {
|
||
|
(GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
|
||
|
(GetPluginObjectOptionsProc) moveGetDisplayOptions
|
||
|
};
|
||
|
|
||
|
*count = 0;
|
||
|
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
|
||
|
(void *) count, (plugin, object, count));
|
||
|
}
|
||
|
|
||
|
static CompBool
|
||
|
moveSetObjectOption (CompPlugin *plugin,
|
||
|
CompObject *object,
|
||
|
const char *name,
|
||
|
CompOptionValue *value)
|
||
|
{
|
||
|
static SetPluginObjectOptionProc dispTab[] = {
|
||
|
(SetPluginObjectOptionProc) 0, /* SetCoreOption */
|
||
|
(SetPluginObjectOptionProc) moveSetDisplayOption
|
||
|
};
|
||
|
|
||
|
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
|
||
|
(plugin, object, name, value));
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
moveInit (CompPlugin *p)
|
||
|
{
|
||
|
if (!compInitPluginMetadataFromInfo (&moveMetadata,
|
||
|
p->vTable->name,
|
||
|
moveDisplayOptionInfo,
|
||
|
MOVE_DISPLAY_OPTION_NUM,
|
||
|
0, 0))
|
||
|
return FALSE;
|
||
|
|
||
|
displayPrivateIndex = allocateDisplayPrivateIndex ();
|
||
|
if (displayPrivateIndex < 0)
|
||
|
{
|
||
|
compFiniMetadata (&moveMetadata);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
compAddMetadataFromFile (&moveMetadata, p->vTable->name);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
moveFini (CompPlugin *p)
|
||
|
{
|
||
|
freeDisplayPrivateIndex (displayPrivateIndex);
|
||
|
compFiniMetadata (&moveMetadata);
|
||
|
}
|
||
|
|
||
|
static CompMetadata *
|
||
|
moveGetMetadata (CompPlugin *plugin)
|
||
|
{
|
||
|
return &moveMetadata;
|
||
|
}
|
||
|
|
||
|
CompPluginVTable moveVTable = {
|
||
|
"move",
|
||
|
moveGetMetadata,
|
||
|
moveInit,
|
||
|
moveFini,
|
||
|
moveInitObject,
|
||
|
moveFiniObject,
|
||
|
moveGetObjectOptions,
|
||
|
moveSetObjectOption
|
||
|
};
|
||
|
|
||
|
CompPluginVTable *
|
||
|
getCompPluginInfo20070830 (void)
|
||
|
{
|
||
|
return &moveVTable;
|
||
|
}
|