/* * 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 */ #include #include #include #include #include #define MOVE_INITIATE_BUTTON_DEFAULT Button1 #define MOVE_INITIATE_BUTTON_MODIFIERS_DEFAULT CompAltMask #define MOVE_INITIATE_KEY_DEFAULT "F7" #define MOVE_INITIATE_KEY_MODIFIERS_DEFAULT CompAltMask #define MOVE_OPACITY_DEFAULT 100 #define MOVE_OPACITY_MIN 1 #define MOVE_OPACITY_MAX 100 #define MOVE_CONSTRAIN_Y_TOP_DEFAULT TRUE #define MOVE_CONSTRAIN_Y_BOTTOM_DEFAULT FALSE #define MOVE_SNAPOFF_MAXIMIZED_DEFAULT FALSE #define MOVE_OPACIFY_MIN_OPACITY_DEFAULT 80 #define MOVE_OPACIFY_MIN_OPACITY_MIN 1 #define MOVE_OPACIFY_MIN_OPACITY_MAX 100 #define MOVE_SNAPOFF_DISTANCE_DEFAULT 100 #define MOVE_SNAPOFF_DISTANCE_MIN 1 #define MOVE_SNAPOFF_DISTANCE_MAX 300 #define MOVE_SNAPBACK_DISTANCE_DEFAULT 20 #define MOVE_SNAPBACK_DISTANCE_MIN 1 #define MOVE_SNAPBACK_DISTANCE_MAX 100 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 static int displayPrivateIndex; #define MOVE_DISPLAY_OPTION_INITIATE 0 #define MOVE_DISPLAY_OPTION_OPACITY 1 #define MOVE_DISPLAY_OPTION_CONSTRAIN_Y_TOP 2 #define MOVE_DISPLAY_OPTION_CONSTRAIN_Y_BOTTOM 3 #define MOVE_DISPLAY_OPTION_OPACIFY_MIN_OPACITY 4 #define MOVE_DISPLAY_OPTION_SNAPOFF_MAXIMIZED 5 #define MOVE_DISPLAY_OPTION_SNAPOFF_DISTANCE 6 #define MOVE_DISPLAY_OPTION_SNAPBACK_DISTANCE 7 #define MOVE_DISPLAY_OPTION_NUM 8 typedef struct _MoveDisplay { int screenPrivateIndex; HandleEventProc handleEvent; CompOption opt[MOVE_DISPLAY_OPTION_NUM]; CompWindow *w; int x; int y; Region region; int status; KeyCode key[NUM_KEYS]; Bool moveOpacitySet; GLushort moveOpacity; GLushort opacifyMinOpacity; } MoveDisplay; typedef struct _MoveScreen { int grabIndex; Cursor moveCursor; unsigned int origState; int snapOffY; int snapBackY; } MoveScreen; #define GET_MOVE_DISPLAY(d) \ ((MoveDisplay *) (d)->privates[displayPrivateIndex].ptr) #define MOVE_DISPLAY(d) \ MoveDisplay *md = GET_MOVE_DISPLAY (d) #define GET_MOVE_SCREEN(s, md) \ ((MoveScreen *) (s)->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) { XRectangle workArea; unsigned int mods; int x, y, head; MOVE_SCREEN(w->screen); head = screenGetOutputDevForWindow(w); screenGetOutputDevWorkArea(w->screen, head, &workArea); 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)); if (otherScreenGrabExist(w->screen, "move", 0)) 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->x = 0; md->y = 0; d->lastPointerX = x; d->lastPointerY = y; ms->origState = w->state; 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) { md->w = w; (w->screen->windowGrabNotify) (w, x, y, mods, CompWindowGrabMoveMask | CompWindowGrabButtonMask); if (md->moveOpacity != OPAQUE && w->paint.opacity >= md->opacifyMinOpacity) { /* modify opacity of windows that are not active */ setWindowOpacity(w, md->moveOpacity, PL_TEMP_HELLO); md->moveOpacitySet = True; } else md->moveOpacitySet = False; if (state & CompActionStateInitKey) { int xRoot, yRoot; xRoot = w->attrib.x + (w->width / 2); yRoot = w->attrib.y + (w->height / 2); warpPointer(d, xRoot - d->pointerX, yRoot - d->pointerY); } } } 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); (md->w->screen->windowUngrabNotify) (md->w); if (state & CompActionStateCancel) moveWindow(md->w, md->w->serverX - md->w->attrib.x, md->w->serverY - md->w->attrib.y, TRUE, FALSE); syncWindowPosition(md->w); if (md->moveOpacitySet) resetWindowOpacity(md->w, PL_TEMP_HELLO); damageScreen(md->w->screen); if (ms->grabIndex) { removeScreenGrab(md->w->screen, ms->grabIndex, NULL); ms->grabIndex = 0; } md->w = 0; } action->state &= ~(CompActionStateTermKey | CompActionStateTermButton); return FALSE; } static Region moveGetYConstrainRegion(CompScreen * s) { CompWindow *w; Region region; REGION r; 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); 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; 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; 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; MOVE_DISPLAY(s->display); w = md->w; md->x += xRoot - s->display->lastPointerX; md->y += yRoot - s->display->lastPointerY; if (md->w->syncWait) return; if (w->type & CompWindowTypeFullscreenMask) { dx = dy = 0; } else { XRectangle workArea; int min, max; Bool constrainTop = md->opt[MOVE_DISPLAY_OPTION_CONSTRAIN_Y_TOP].value.b; Bool constrainBottom = md->opt[MOVE_DISPLAY_OPTION_CONSTRAIN_Y_BOTTOM].value.b; dx = md->x; dy = md->y; screenGetOutputDevWorkArea(s, screenGetOutputDevForWindow(w), &workArea); if (constrainTop || constrainBottom) { 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; if (constrainTop) { y = w->attrib.y + dy - w->input.top; height = w->input.top ? w->input.top : 1; if (constrainBottom) height += w->height + w->input.bottom; } else /* if (constrainBottom) redundant */ { y = w->attrib.y + dy + w->height; height = w->input.bottom ? w->input.bottom : 1; } x = w->attrib.x + dx - w->input.left; width = w->width + w->input.left + w->input.right; 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 = w->attrib.x + 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 = w->attrib.y + dy + (constrainTop ? (-w->input.top) : w-> height); } } else { md->status = status; } } } if (md->opt[MOVE_DISPLAY_OPTION_SNAPOFF_MAXIMIZED].value.b) { if (w->state & CompWindowStateMaximizedVertMask) { if ((yRoot - workArea.y) - ms->snapOffY >= md->opt[MOVE_DISPLAY_OPTION_SNAPOFF_DISTANCE].value.i) { XWindowChanges xwc; syncWindowPosition(w); xwc.x = w->serverX; xwc.y = w->serverY; xwc.width = w->serverWidth; xwc.height = w->serverHeight; restoreHorzRestoreData(w, &xwc); restoreVertRestoreData(w, &xwc); xwc.x = xRoot - (xwc.width >> 1); xwc.y = yRoot + (w->input.top >> 1); saveHorzRestoreData(w, &xwc); saveVertRestoreData(w, &xwc); md->x = md->y = 0; maximizeWindow(w, 0); ms->snapOffY = ms->snapBackY; return; } } else if (ms->origState & CompWindowStateMaximizedVertMask) { if ((yRoot - workArea.y) - ms->snapBackY < md-> opt[MOVE_DISPLAY_OPTION_SNAPBACK_DISTANCE].value.i) { if (!otherScreenGrabExist(s, "move", 0)) { int wy; /* update server position before maximizing window again so it is maximized on the correct output */ syncWindowPosition(w); maximizeWindow(w, ms->origState); wy = workArea.y + (w->input.top >> 1); wy += w->sizeHints.height_inc >> 1; warpPointer(s-> display, 0, wy - s->display->pointerY); return; } } } } if (w->state & CompWindowStateMaximizedVertMask) { min = workArea.y + w->input.top; max = workArea.y + workArea.height - w->input.bottom - w->serverHeight - w->serverBorderWidth * 2; if (w->attrib.y + dy < min) dy = min - w->attrib.y; else if (w->attrib.y + dy > max) dy = max - w->attrib.y; } if (w->state & CompWindowStateMaximizedHorzMask) { if (w->attrib.x + w->serverWidth + w->serverBorderWidth < 0) return; min = workArea.x + w->input.left; max = workArea.x + workArea.width - w->input.right - w->serverWidth - w->serverBorderWidth * 2; if (w->attrib.x + dx < min) dx = min - w->attrib.x; else if (w->attrib.x + dx > max) dx = max - w->attrib.x; } } moveWindow(md->w, dx, dy, TRUE, FALSE); damageScreen(s); 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) { moveTerminate(d, &md-> opt [MOVE_DISPLAY_OPTION_INITIATE]. value.action, 0, NULL, 0); } } break; case KeyPress: case KeyRelease: s = findScreenAtDisplay(d, event->xkey.root); if (s) { MOVE_SCREEN(s); if (ms->grabIndex && event->type == KeyPress) { 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, d->pointerX, d->pointerY); break; case EnterNotify: case LeaveNotify: s = findScreenAtDisplay(d, event->xcrossing.root); if (s) moveHandleMotionEvent(s, d->pointerX, d->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[4]; int xRoot, yRoot; CompAction *action = &md->opt[MOVE_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] == WmMoveResizeMoveKeyboard) { moveInitiate(d, action, CompActionStateInitKey, o, 1); } else { unsigned int mods; Window root, child; int 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]; moveInitiate(d, action, CompActionStateInitButton, o, 4); moveHandleMotionEvent(w->screen, xRoot, yRoot); } } } } } break; case DestroyNotify: if (md->w && md->w->id == event->xdestroywindow.window) moveTerminate(d, &md-> opt[MOVE_DISPLAY_OPTION_INITIATE]. value.action, 0, NULL, 0); break; case UnmapNotify: if (md->w && md->w->id == event->xunmap.window) moveTerminate(d, &md-> opt[MOVE_DISPLAY_OPTION_INITIATE]. value.action, 0, NULL, 0); default: break; } UNWRAP(md, d, handleEvent); (*d->handleEvent) (d, event); WRAP(md, d, handleEvent, moveHandleEvent); } static void moveDisplayInitOptions(MoveDisplay * md) { CompOption *o; o = &md->opt[MOVE_DISPLAY_OPTION_INITIATE]; o->advanced = False; o->name = "initiate"; o->group = N_("Bindings"); o->subGroup = N_("Move window"); o->displayHints = ""; o->shortDesc = N_("Initiate Window Move"); o->longDesc = N_("Start moving Window."); o->type = CompOptionTypeAction; o->value.action.initiate = moveInitiate; o->value.action.terminate = moveTerminate; 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 = MOVE_INITIATE_BUTTON_MODIFIERS_DEFAULT; o->value.action.button.button = MOVE_INITIATE_BUTTON_DEFAULT; o->value.action.type |= CompBindingTypeKey; o->value.action.state |= CompActionStateInitKey; o->value.action.key.modifiers = MOVE_INITIATE_KEY_MODIFIERS_DEFAULT; o->value.action.key.keysym = XStringToKeysym(MOVE_INITIATE_KEY_DEFAULT); o = &md->opt[MOVE_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 = MOVE_OPACIFY_MIN_OPACITY_DEFAULT; o->rest.i.min = MOVE_OPACIFY_MIN_OPACITY_MIN; o->rest.i.max = MOVE_OPACIFY_MIN_OPACITY_MAX; o = &md->opt[MOVE_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 Moving windows."); o->type = CompOptionTypeInt; o->value.i = MOVE_OPACITY_DEFAULT; o->rest.i.min = MOVE_OPACITY_MIN; o->rest.i.max = MOVE_OPACITY_MAX; o = &md->opt[MOVE_DISPLAY_OPTION_CONSTRAIN_Y_TOP]; o->advanced = False; o->name = "constrain_y_top"; o->group = N_("Misc. options"); o->subGroup = N_("Movement constraints"); o->displayHints = ""; o->shortDesc = N_("Constrain Y to Top of Screen"); o->longDesc = N_("Prevent windows from Moving over the Top of the Screen."); o->type = CompOptionTypeBool; o->value.b = MOVE_CONSTRAIN_Y_TOP_DEFAULT; o = &md->opt[MOVE_DISPLAY_OPTION_CONSTRAIN_Y_BOTTOM]; o->advanced = False; o->name = "constrain_y_bottom"; o->group = N_("Misc. options"); o->subGroup = N_("Movement constraints"); o->displayHints = ""; o->shortDesc = N_("Constrain Y to Bottom of Screen"); o->longDesc = N_("Prevent windows from Moving past the Bottom of the Screen."); o->type = CompOptionTypeBool; o->value.b = MOVE_CONSTRAIN_Y_BOTTOM_DEFAULT; o = &md->opt[MOVE_DISPLAY_OPTION_SNAPOFF_MAXIMIZED]; o->advanced = False; o->name = "snapoff_maximized"; o->group = N_("Misc. options"); o->subGroup = N_("Snapoff/snapback"); o->displayHints = ""; o->shortDesc = N_("Snapoff Maximized Windows"); o->longDesc = N_("Snap off and unMaximize Maximized Windows " "when dragging."); o->type = CompOptionTypeBool; o->value.b = MOVE_SNAPOFF_MAXIMIZED_DEFAULT; o = &md->opt[MOVE_DISPLAY_OPTION_SNAPOFF_DISTANCE]; o->advanced = False; o->name = "snapoff_distance"; o->group = N_("Misc. options"); o->subGroup = N_("Snapoff/snapback"); o->displayHints = ""; o->shortDesc = N_("Snapoff Distance"); o->longDesc = N_("Pointer movement Distance after which window is Snapped off."); o->type = CompOptionTypeInt; o->value.i = MOVE_SNAPOFF_DISTANCE_DEFAULT; o->rest.i.min = MOVE_SNAPOFF_DISTANCE_MIN; o->rest.i.max = MOVE_SNAPOFF_DISTANCE_MAX; o = &md->opt[MOVE_DISPLAY_OPTION_SNAPBACK_DISTANCE]; o->advanced = False; o->name = "snapback_distance"; o->group = N_("Misc. options"); o->subGroup = N_("Snapoff/snapback"); o->displayHints = ""; o->shortDesc = N_("Snapback Distance"); o->longDesc = N_("Pointer movement Distance to Snap window back."); o->type = CompOptionTypeInt; o->value.i = MOVE_SNAPBACK_DISTANCE_DEFAULT; o->rest.i.min = MOVE_SNAPBACK_DISTANCE_MIN; o->rest.i.max = MOVE_SNAPBACK_DISTANCE_MAX; } static CompOption *moveGetDisplayOptions(CompDisplay * display, int *count) { if (display) { MOVE_DISPLAY(display); *count = NUM_OPTIONS(md); return md->opt; } else { MoveDisplay *md = malloc(sizeof(MoveDisplay)); moveDisplayInitOptions(md); *count = NUM_OPTIONS(md); return md->opt; } } static Bool moveSetDisplayOption(CompDisplay * display, 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_INITIATE: if (setDisplayAction(display, o, value)) return TRUE; break; case MOVE_DISPLAY_OPTION_OPACITY: if (compSetIntOption(o, value)) { md->moveOpacity = (o->value.i * OPAQUE) / 100; return TRUE; } break; case MOVE_DISPLAY_OPTION_OPACIFY_MIN_OPACITY: if (compSetIntOption(o, value)) { md->opacifyMinOpacity = (o->value.i * OPAQUE) / 100; return TRUE; } break; case MOVE_DISPLAY_OPTION_SNAPOFF_DISTANCE: case MOVE_DISPLAY_OPTION_SNAPBACK_DISTANCE: if (compSetIntOption(o, value)) return TRUE; break; case MOVE_DISPLAY_OPTION_CONSTRAIN_Y_TOP: case MOVE_DISPLAY_OPTION_CONSTRAIN_Y_BOTTOM: case MOVE_DISPLAY_OPTION_SNAPOFF_MAXIMIZED: if (compSetBoolOption(o, value)) return TRUE; break; default: break; } return FALSE; } static Bool moveInitDisplay(CompPlugin * p, CompDisplay * d) { MoveDisplay *md; int i; md = malloc(sizeof(MoveDisplay)); if (!md) return FALSE; md->screenPrivateIndex = allocateScreenPrivateIndex(d); if (md->screenPrivateIndex < 0) { free(md); return FALSE; } md->moveOpacity = (MOVE_OPACITY_DEFAULT * OPAQUE) / 100; md->opacifyMinOpacity = (MOVE_OPACIFY_MIN_OPACITY_DEFAULT * OPAQUE) / 100; moveDisplayInitOptions(md); md->w = 0; md->region = NULL; for (i = 0; i < NUM_KEYS; i++) md->key[i] = XKeysymToKeycode(d->display, XStringToKeysym(mKeys[i].name)); WRAP(md, d, handleEvent, moveHandleEvent); d->privates[displayPrivateIndex].ptr = md; return TRUE; } static void moveFiniDisplay(CompPlugin * p, CompDisplay * d) { MOVE_DISPLAY(d); freeScreenPrivateIndex(d, md->screenPrivateIndex); UNWRAP(md, d, handleEvent); 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); addScreenAction(s, &md->opt[MOVE_DISPLAY_OPTION_INITIATE].value.action); s->privates[md->screenPrivateIndex].ptr = ms; return TRUE; } static void moveFiniScreen(CompPlugin * p, CompScreen * s) { MOVE_SCREEN(s); MOVE_DISPLAY(s->display); removeScreenAction(s, &md->opt[MOVE_DISPLAY_OPTION_INITIATE].value.action); XFreeCursor(s->display->display, ms->moveCursor); free(ms); } static Bool moveInit(CompPlugin * p) { displayPrivateIndex = allocateDisplayPrivateIndex(); if (displayPrivateIndex < 0) return FALSE; return TRUE; } static void moveFini(CompPlugin * p) { if (displayPrivateIndex >= 0) freeDisplayPrivateIndex(displayPrivateIndex); } CompPluginVTable moveVTable = { "move", N_("Move Window"), N_("Move window"), moveInit, moveFini, moveInitDisplay, moveFiniDisplay, moveInitScreen, moveFiniScreen, 0, /* InitWindow */ 0, /* FiniWindow */ moveGetDisplayOptions, moveSetDisplayOption, 0, /* GetScreenOptions */ 0, /* SetScreenOption */ NULL, 0, 0, 0, BERYL_ABI_INFO, "beryl-plugins", "wm", 0, 0, True, }; CompPluginVTable *getCompPluginInfo(void) { return &moveVTable; }