compiz-plugins-extra: add mouse-window-snapping

Closes: #5884 [via git-merge-pr]
This commit is contained in:
CoolOhm 2017-03-03 12:02:37 -08:00 committed by Jürgen Buchmüller
parent cc58e8cd8a
commit d311e01376
3 changed files with 1503 additions and 1 deletions

View file

@ -0,0 +1,992 @@
--- src/grid/grid.c 2016-04-10 12:23:24.000000000 -0700
+++ src/grid/grid.c 2017-03-01 23:23:09.809718104 -0800
@@ -1,7 +1,8 @@
/*
- * Compiz Fusion Grid plugin
+ * Compiz Grid plugin
*
* Copyright (c) 2008 Stephen Kennedy <suasol@gmail.com>
+ * Copyright (c) 2010 Scott Moreau <oreaus@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -37,6 +38,8 @@
# define DEBUG_PRINT(ARGS)
#endif
+static int displayPrivateIndex;
+
typedef enum
{
GridUnknown = 0,
@@ -49,8 +52,23 @@
GridTopLeft = 7,
GridTop = 8,
GridTopRight = 9,
+ GridMaximize = 10,
} GridType;
+
+typedef enum
+{
+ NoEdge = 0,
+ BottomLeft,
+ Bottom,
+ BottomRight,
+ Left,
+ Right,
+ TopLeft,
+ Top,
+ TopRight,
+} EdgeType;
+
typedef struct _GridProps
{
int gravityRight;
@@ -76,6 +94,56 @@
{1,0, 2,2},
};
+typedef struct _Animation
+{
+ GLfloat progress;
+ XRectangle fromRect;
+ XRectangle targetRect;
+ XRectangle currentRect;
+ GLfloat opacity;
+ GLfloat timer;
+ int duration;
+ Bool complete;
+ Bool fadingOut;
+} Animation;
+
+typedef struct _GridDisplay {
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+} GridDisplay;
+
+typedef struct _GridScreen
+{
+ WindowGrabNotifyProc windowGrabNotify;
+ WindowUngrabNotifyProc windowUngrabNotify;
+ PaintOutputProc paintOutput;
+ PreparePaintScreenProc preparePaintScreen;
+
+ Bool grabIsMove;
+ EdgeType edge, lastEdge;
+ XRectangle workarea;
+ XRectangle desiredSlot;
+ XRectangle desiredRect;
+ XRectangle currentRect;
+ GridProps props;
+ CompWindow *w;
+ Bool drawing;
+ Animation anim;
+ Bool animating;
+} GridScreen;
+
+#define GET_GRID_DISPLAY(d) \
+ ((GridDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
+
+#define GRID_DISPLAY(d) \
+ GridDisplay *gd = GET_GRID_DISPLAY (d)
+
+#define GET_GRID_SCREEN(s, gd) \
+ ((GridScreen *) (s)->base.privates[(gd)->screenPrivateIndex].ptr)
+
+#define GRID_SCREEN(s) \
+ GridScreen *gs = GET_GRID_SCREEN (s, GET_GRID_DISPLAY (s->display))
+
static void
slotToRect (CompWindow *w,
XRectangle *slot,
@@ -117,144 +185,599 @@
*rect = r;
}
+
+static void
+getTargetRect (CompWindow *cw,
+ GridType where)
+{
+ GRID_SCREEN (cw->screen);
+
+ gs->props = gridProps[where];
+
+ DEBUG_PRINT ((gridOut, "\nPressed KP_%i\n", where));
+
+ /* get current available area */
+ getWorkareaForOutput (cw->screen, outputDeviceForWindow(cw), &gs->workarea);
+ DEBUG_RECT (workarea);
+
+ /* Convention:
+ * xxxSlot include decorations (it's the screen area occupied)
+ * xxxRect are undecorated (it's the constrained position
+ of the contents)
+ */
+
+ /* slice and dice to get desired slot - including decorations */
+ gs->desiredSlot.y = gs->workarea.y + gs->props.gravityDown *
+ (gs->workarea.height / gs->props.numCellsY);
+ gs->desiredSlot.height = gs->workarea.height / gs->props.numCellsY;
+ gs->desiredSlot.x = gs->workarea.x + gs->props.gravityRight *
+ (gs->workarea.width / gs->props.numCellsX);
+ gs->desiredSlot.width = gs->workarea.width / gs->props.numCellsX;
+ DEBUG_RECT (desiredSlot);
+
+ /* Adjust for constraints and decorations */
+ constrainSize (cw, &gs->desiredSlot, &gs->desiredRect);
+ DEBUG_RECT (gs->desiredRect);
+}
+
+/* just keeping this for reference, but can use maximizeWindow instead */
+static void sendMaximizationRequest (CompWindow *w)
+{
+ XEvent xev;
+ CompScreen *s = w->screen;
+ CompDisplay *d = s->display;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = d->display;
+ xev.xclient.format = 32;
+
+ xev.xclient.message_type = d->winStateAtom;
+ xev.xclient.window = w->id;
+
+ xev.xclient.data.l[0] = 1;
+ xev.xclient.data.l[1] = d->winStateMaximizedHorzAtom;
+ xev.xclient.data.l[2] = d->winStateMaximizedVertAtom;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+
+ XSendEvent (d->display, s->root, FALSE,
+ SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+}
+
+
+static void
+gridCommonWindow (CompWindow *cw,
+ GridType where)
+{
+ GRID_SCREEN (cw->screen);
+
+ if ((cw) && (where != GridUnknown))
+ {
+ /* add maximize option */
+ if (where == GridMaximize)
+ {
+ sendMaximizationRequest (cw);
+ /* maximizeWindow (cw, MAXIMIZE_STATE); */
+ }
+ else
+ {
+ unsigned int valueMask = 0;
+ int desiredState = 0;
+
+ getTargetRect (cw, where);
+
+ XWindowChanges xwc;
+
+ /* if keys are pressed again then cycle through 1/3 or 2/3 widths... */
+
+ /* Get current rect not including decorations */
+ gs->currentRect.x = cw->serverX;
+ gs->currentRect.y = cw->serverY;
+ gs->currentRect.width = cw->serverWidth;
+ gs->currentRect.height = cw->serverHeight;
+ DEBUG_RECT (currentRect);
+
+ if ((gs->desiredRect.y == gs->currentRect.y &&
+ gs->desiredRect.height == gs->currentRect.height) &&
+ gridGetCycleSizes(cw->screen->display))
+ {
+ int slotWidth33 = gs->workarea.width / 3;
+ int slotWidth66 = gs->workarea.width - slotWidth33;
+
+ DEBUG_PRINT ((gridOut, "Multi!\n"));
+
+ if (gs->props.numCellsX == 2) /* keys (1, 4, 7, 3, 6, 9) */
+ {
+ if (gs->currentRect.width == gs->desiredRect.width &&
+ gs->currentRect.x == gs->desiredRect.x)
+ {
+ gs->desiredSlot.width = slotWidth66;
+ gs->desiredSlot.x = gs->workarea.x +
+ gs->props.gravityRight * slotWidth33;
+ }
+ else
+ {
+ /* tricky, have to allow for window constraints when
+ * computing what the 33% and 66% offsets would be
+ */
+ XRectangle rect33, rect66, slot33, slot66;
+
+ slot33 = gs->desiredSlot;
+ slot33.x = gs->workarea.x +
+ gs->props.gravityRight * slotWidth66;
+ slot33.width = slotWidth33;
+ constrainSize (cw, &slot33, &rect33);
+ DEBUG_RECT (slot33);
+ DEBUG_RECT (rect33);
+
+ slot66 = gs->desiredSlot;
+ slot66.x = gs->workarea.x +
+ gs->props.gravityRight * slotWidth33;
+ slot66.width = slotWidth66;
+ constrainSize (cw, &slot66, &rect66);
+ DEBUG_RECT (slot66);
+ DEBUG_RECT (rect66);
+
+ if (gs->currentRect.width == rect66.width &&
+ gs->currentRect.x == rect66.x)
+ {
+ gs->desiredSlot.width = slotWidth33;
+ gs->desiredSlot.x = gs->workarea.x +
+ gs->props.gravityRight * slotWidth66;
+ }
+ }
+ }
+ else /* keys (2, 5, 8) */
+ {
+ if (gs->currentRect.width == gs->desiredRect.width &&
+ gs->currentRect.x == gs->desiredRect.x)
+ {
+ gs->desiredSlot.width = slotWidth33;
+ gs->desiredSlot.x = gs->workarea.x + slotWidth33;
+ }
+ }
+ constrainSize (cw, &gs->desiredSlot, &gs->desiredRect);
+ DEBUG_RECT (gs->desiredRect);
+ }
+
+ xwc.x = gs->desiredRect.x;
+ xwc.y = gs->desiredRect.y;
+ xwc.width = gs->desiredRect.width;
+ xwc.height = gs->desiredRect.height;
+
+ if (cw->mapNum)
+ sendSyncRequest (cw);
+
+ if (where == GridRight || where == GridLeft)
+ {
+ desiredState = CompWindowStateMaximizedVertMask;
+ valueMask = CWX | CWWidth;
+ }
+ else if (where == GridTop || where == GridBottom)
+ {
+ desiredState = CompWindowStateMaximizedHorzMask;
+ valueMask = CWY | CWHeight;
+ }
+ else
+ {
+ desiredState = 0;
+ valueMask = CWX | CWY | CWWidth | CWHeight;
+ }
+
+ if (cw->state != desiredState)
+ maximizeWindow (cw, desiredState);
+
+ /* TODO: animate move+resize */
+ configureXWindow (cw, valueMask, &xwc);
+
+ }
+ }
+}
+
static Bool
-gridCommon (CompDisplay *d,
- CompAction *action,
+gridCommon (CompDisplay *d,
+ CompAction *action,
CompActionState state,
- CompOption *option,
- int nOption,
- GridType where)
+ CompOption *option,
+ int nOption,
+ GridType where)
{
Window xid;
CompWindow *cw;
xid = getIntOptionNamed (option, nOption, "window", 0);
cw = findWindowAtDisplay (d, xid);
- if (cw)
+
+ gridCommonWindow(cw, where);
+
+ return TRUE;
+}
+
+static GridType
+edgeToGridType (CompDisplay *d,
+ EdgeType edge)
+{
+ GridType ret = GridUnknown;
+
+ switch (edge)
{
- XRectangle workarea;
- XRectangle desiredSlot;
- XRectangle desiredRect;
- XRectangle currentRect;
- GridProps props = gridProps[where];
- XWindowChanges xwc;
-
- DEBUG_PRINT ((gridOut, "\nPressed KP_%i\n", where));
-
- /* get current available area */
- getWorkareaForOutput (cw->screen, outputDeviceForWindow(cw), &workarea);
- DEBUG_RECT (workarea);
-
- /* Convention:
- * xxxSlot include decorations (it's the screen area occupied)
- * xxxRect are undecorated (it's the constrained position
- of the contents)
- */
-
- /* slice and dice to get desired slot - including decorations */
- desiredSlot.y = workarea.y + props.gravityDown *
- (workarea.height / props.numCellsY);
- desiredSlot.height = workarea.height / props.numCellsY;
- desiredSlot.x = workarea.x + props.gravityRight *
- (workarea.width / props.numCellsX);
- desiredSlot.width = workarea.width / props.numCellsX;
- DEBUG_RECT (desiredSlot);
-
- /* Adjust for constraints and decorations */
- constrainSize (cw, &desiredSlot, &desiredRect);
- DEBUG_RECT (desiredRect);
-
- /* Get current rect not including decorations */
- currentRect.x = cw->serverX;
- currentRect.y = cw->serverY;
- currentRect.width = cw->serverWidth;
- currentRect.height = cw->serverHeight;
- DEBUG_RECT (currentRect);
+ case Left:
+ ret = (GridType) gridGetLeftEdgeAction (d);
+ break;
+ case Right:
+ ret = (GridType) gridGetRightEdgeAction (d);
+ break;
+ case Top:
+ ret = (GridType) gridGetTopEdgeAction (d);
+ break;
+ case Bottom:
+ ret = (GridType) gridGetBottomEdgeAction (d);
+ break;
+ case TopLeft:
+ ret = (GridType) gridGetTopLeftCornerAction (d);
+ break;
+ case TopRight:
+ ret = (GridType) gridGetTopRightCornerAction (d);
+ break;
+ case BottomLeft:
+ ret = (GridType) gridGetBottomLeftCornerAction (d);
+ break;
+ case BottomRight:
+ ret = (GridType) gridGetBottomRightCornerAction (d);
+ break;
+ case NoEdge:
+ default:
+ ret = -1;
+ break;
+ }
- if (desiredRect.y == currentRect.y &&
- desiredRect.height == currentRect.height)
- {
- int slotWidth33 = workarea.width / 3;
- int slotWidth66 = workarea.width - slotWidth33;
+ return ret;
+}
- DEBUG_PRINT ((gridOut, "Multi!\n"));
+static void
+gridHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ GridType where;
+ GRID_DISPLAY (d);
- if (props.numCellsX == 2) /* keys (1, 4, 7, 3, 6, 9) */
+ if (event->type == MotionNotify)
+ {
+ CompScreen *s;
+ s = findScreenAtDisplay (d, event->xmotion.root);
+ if (s)
+ {
+ GRID_SCREEN (s);
+ if (gs->grabIsMove)
{
- if (currentRect.width == desiredRect.width &&
- currentRect.x == desiredRect.x)
- {
- desiredSlot.width = slotWidth66;
- desiredSlot.x = workarea.x +
- props.gravityRight * slotWidth33;
- }
+ /* detect corners first */
+ /* Bottom Left */
+ if (pointerY > (s->height - gridGetBottomEdgeThreshold(d)) &&
+ pointerX < gridGetLeftEdgeThreshold(d))
+ gs->edge = BottomLeft;
+ /* Bottom Right */
+ else if (pointerY > (s->height - gridGetBottomEdgeThreshold(d)) &&
+ pointerX > (s->width - gridGetRightEdgeThreshold(d)))
+ gs->edge = BottomRight;
+ /* Top Left */
+ else if (pointerY < gridGetTopEdgeThreshold(d) && pointerX < gridGetLeftEdgeThreshold(d))
+ gs->edge = TopLeft;
+ /* Top Right */
+ else if (pointerY < gridGetTopEdgeThreshold(d) &&
+ pointerX > (s->width - gridGetRightEdgeThreshold(d)))
+ gs->edge = TopRight;
+ /* Left */
+ else if (pointerX < gridGetLeftEdgeThreshold(d))
+ gs->edge = Left;
+ /* Right */
+ else if (pointerX > (s->width - gridGetRightEdgeThreshold(d)))
+ gs->edge = Right;
+ /* Top */
+ else if (pointerY < gridGetTopEdgeThreshold(d))
+ gs->edge = Top;
+ /* Bottom */
+ else if (pointerY > (s->height - gridGetBottomEdgeThreshold(d)))
+ gs->edge = Bottom;
+ /* No Edge */
else
- {
- /* tricky, have to allow for window constraints when
- * computing what the 33% and 66% offsets would be
- */
- XRectangle rect33, rect66, slot33, slot66;
-
- slot33 = desiredSlot;
- slot33.x = workarea.x + props.gravityRight * slotWidth66;
- slot33.width = slotWidth33;
- constrainSize (cw, &slot33, &rect33);
- DEBUG_RECT (slot33);
- DEBUG_RECT (rect33);
-
- slot66 = desiredSlot;
- slot66.x = workarea.x + props.gravityRight * slotWidth33;
- slot66.width = slotWidth66;
- constrainSize (cw, &slot66, &rect66);
- DEBUG_RECT (slot66);
- DEBUG_RECT (rect66);
+ gs->edge = NoEdge;
- if (currentRect.width == rect66.width &&
- currentRect.x == rect66.x)
+ /* detect edge region change */
+ if (gs->lastEdge != gs->edge)
+ {
+ if (gs->edge != NoEdge)
{
- desiredSlot.width = slotWidth33;
- desiredSlot.x = workarea.x +
- props.gravityRight * slotWidth66;
+ where = edgeToGridType(d, gs->edge);
+
+ /* treat Maximize visual indicator same as GridCenter */
+ if (where == GridMaximize)
+ where=GridCenter;
+
+ getTargetRect (gs->w, where);
+
+ gs->anim.duration = gridGetAnimationDuration (d);
+ gs->anim.timer = gs->anim.duration;
+ gs->anim.opacity = 0.0f;
+ gs->anim.progress = 0.0f;
+ gs->anim.currentRect.x = gs->w->serverX;
+ gs->anim.currentRect.y = gs->w->serverY;
+ gs->anim.currentRect.width = gs->w->serverWidth;
+ gs->anim.currentRect.height = gs->w->serverHeight;
+ gs->anim.targetRect = gs->desiredSlot;
+ gs->anim.fromRect.x = gs->w->serverX - gs->w->input.left;
+ gs->anim.fromRect.y = gs->w->serverY - gs->w->input.top;
+ gs->anim.fromRect.width = gs->w->serverWidth +
+ gs->w->input.left +
+ gs->w->input.right +
+ gs->w->serverBorderWidth * 2;
+ gs->anim.fromRect.height = gs->w->serverHeight +
+ gs->w->input.top +
+ gs->w->input.bottom +
+ gs->w->serverBorderWidth * 2;
+ gs->animating = TRUE;
+ gs->anim.fadingOut = FALSE;
}
+ else
+ gs->anim.fadingOut = TRUE;
+
+ gs->lastEdge = gs->edge;
}
+
}
- else /* keys (2, 5, 8) */
- {
- if (currentRect.width == desiredRect.width &&
- currentRect.x == desiredRect.x)
- {
- desiredSlot.width = slotWidth33;
- desiredSlot.x = workarea.x + slotWidth33;
- }
- }
- constrainSize (cw, &desiredSlot, &desiredRect);
- DEBUG_RECT (desiredRect);
}
+ }
+
+ UNWRAP (gd, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (gd, d, handleEvent, gridHandleEvent);
+}
+
+static void
+gridWindowGrabNotify (CompWindow *w,
+ int x,
+ int y,
+ unsigned int state,
+ unsigned int mask)
+{
+ CompScreen *s = w->screen;
+
+ GRID_SCREEN (s);
+
+ if (mask & CompWindowGrabMoveMask)
+ {
+ gs->grabIsMove = TRUE;
+ gs->w = w;
+ }
+
+ UNWRAP (gs, s, windowGrabNotify);
+ (*s->windowGrabNotify) (w, x, y, state, mask);
+ WRAP (gs, s, windowGrabNotify, gridWindowGrabNotify);
+}
+
+static void
+gridWindowUngrabNotify (CompWindow *w)
+{
+ CompScreen *s = w->screen;
+ CompDisplay *d = s->display;
+
+ GRID_SCREEN (s);
+
+ if (gs->grabIsMove)
+ {
+ gs->grabIsMove = FALSE;
+
+ if (gs->edge != NoEdge)
+ {
+ gridCommonWindow (w, edgeToGridType(d, gs->edge));
+ gs->anim.fadingOut = TRUE;
+ }
+ }
+
+ gs->edge = NoEdge;
+ gs->lastEdge = NoEdge;
+
+ UNWRAP (gs, s, windowUngrabNotify);
+ (*s->windowUngrabNotify) (w);
+ WRAP (gs, s, windowUngrabNotify, gridWindowUngrabNotify);
+}
+
+static int
+applyProgress (int a, int b, float progress)
+{
+ return a < b ?
+ b - (abs (a - b) * progress) :
+ b + (abs (a - b) * progress);
+}
+
+static void
+setCurrentRect (CompScreen *s)
+{
+ GRID_SCREEN (s);
+
+ gs->anim.currentRect.x = applyProgress (gs->anim.targetRect.x,
+ gs->anim.fromRect.x,
+ gs->anim.progress);
+ gs->anim.currentRect.width = applyProgress (gs->anim.targetRect.width,
+ gs->anim.fromRect.width,
+ gs->anim.progress);
+ gs->anim.currentRect.y = applyProgress (gs->anim.targetRect.y,
+ gs->anim.fromRect.y,
+ gs->anim.progress);
+ gs->anim.currentRect.height = applyProgress (gs->anim.targetRect.height,
+ gs->anim.fromRect.height,
+ gs->anim.progress);
+}
+
+static void
+glPaintRectangle (CompScreen *s,
+ const ScreenPaintAttrib *sAttrib,
+ const CompTransform *transform,
+ CompOutput *output)
+{
+ float alpha = 0;
+
+ GRID_SCREEN (s);
+
+ BoxRec rect;
+
+ setCurrentRect (s);
+
+ rect.x1=gs->anim.currentRect.x;
+ rect.y1=gs->anim.currentRect.y;
+ rect.x2=gs->anim.currentRect.x + gs->anim.currentRect.width;
+ rect.y2=gs->anim.currentRect.y + gs->anim.currentRect.height;
+ CompTransform sTransform = *transform;
+
+ /* rect = desiredSlot;*/
+
+ glPushMatrix ();
+
+ transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
+
+ glLoadMatrixf (sTransform.m);
+
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+ glEnable (GL_BLEND);
+
+ /* fill rectangle */
+ /* TODO: have multiple animations
+ for (iter = animations.begin (); iter != animations.end () && animating; iter++)
+ { */
+
+ alpha = ((float) gridGetFillColorAlpha (s->display) / 65535.0f) *
+ gs->anim.opacity;
- xwc.x = desiredRect.x;
- xwc.y = desiredRect.y;
- xwc.width = desiredRect.width;
- xwc.height = desiredRect.height;
+ glColor4f (((float) gridGetFillColorRed (s->display) / 65535.0f) * alpha,
+ ((float) gridGetFillColorGreen (s->display) / 65535.0f) * alpha,
+ ((float) gridGetFillColorBlue (s->display) / 65535.0f) * alpha,
+ alpha);
- if (cw->mapNum)
- sendSyncRequest (cw);
+ glRecti (rect.x1, rect.y2, rect.x2, rect.y1);
- if (cw->state & MAXIMIZE_STATE)
+ /* draw outline */
+
+ alpha = ((float) gridGetOutlineColorAlpha (s->display) / 65535.0f) *
+ gs->anim.opacity;
+
+ glColor4f (((float) gridGetOutlineColorRed (s->display) / 65535.0f) * alpha,
+ ((float) gridGetOutlineColorGreen (s->display) / 65535.0f) * alpha,
+ ((float) gridGetOutlineColorBlue (s->display) / 65535.0f) * alpha,
+ alpha);
+
+ int thickness = gridGetOutlineThickness (s->display);
+ glLineWidth (thickness);
+ glBegin (GL_LINE_LOOP);
+
+ /* set outline rect smaller to avoid damage issues */
+ /* TODO: maybe get a better way of doing this */
+ float half_thickness = thickness * 0.5;
+ glVertex2f (rect.x1 + half_thickness, rect.y1 + half_thickness);
+ glVertex2f (rect.x2 - half_thickness, rect.y1 + half_thickness);
+ glVertex2f (rect.x2 - half_thickness, rect.y2 - half_thickness);
+ glVertex2f (rect.x1 + half_thickness, rect.y2 - half_thickness);
+ glEnd ();
+
+ /* clean up */
+ glColor4usv (defaultColor);
+ glDisable (GL_BLEND);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+ glPopMatrix ();
+}
+
+static void
+damagePaintRegion (CompScreen *s)
+{
+ REGION reg;
+ int x, y;
+
+ GRID_SCREEN (s);
+
+ /* if (!is->fadeTime && !is->drawing)
+ return; */
+
+ x = gs->anim.currentRect.x;
+ y = gs->anim.currentRect.y;
+
+ reg.rects = &reg.extents;
+ reg.numRects = 1;
+
+ reg.extents.x1 = x - 5;
+ reg.extents.y1 = y - 5;
+ reg.extents.x2 = x + gs->anim.currentRect.width + 5;
+ reg.extents.y2 = y + gs->anim.currentRect.height + 5;
+
+ damageScreenRegion (s, &reg);
+}
+
+static Bool
+gridPaintOutput (CompScreen *s,
+ const ScreenPaintAttrib *sAttrib,
+ const CompTransform *transform,
+ Region region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ Bool status;
+
+ GRID_SCREEN (s);
+
+ UNWRAP (gs, s, paintOutput);
+ status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
+ WRAP (gs, s, paintOutput, gridPaintOutput);
+
+ if (gs->animating && gridGetDrawIndicator (s->display))
+ {
+ glPaintRectangle (s, sAttrib, transform, output);
+ damagePaintRegion (s);
+ }
+
+ return status;
+}
+
+
+/* handle the fade in /fade out */
+static void
+gridPreparePaintScreen (CompScreen *s,
+ int ms)
+{
+ GRID_SCREEN (s);
+
+ if (gs->animating)
+ {
+ gs->anim.timer -= ms;
+
+ if (gs->anim.timer < 0)
+ gs->anim.timer = 0;
+
+ if (gs->anim.fadingOut)
+ gs->anim.opacity -= ms * 0.002;
+ else
+ {
+ if (gs->anim.opacity < 1.0f)
+ gs->anim.opacity = gs->anim.progress * gs->anim.progress;
+ else
+ gs->anim.opacity = 1.0f;
+ }
+
+ if (gs->anim.opacity < 0)
{
- /* maximized state interferes with us, clear it */
- maximizeWindow (cw, 0);
+ gs->anim.opacity = 0.0f;
+ gs->anim.fadingOut = FALSE;
+ gs->anim.complete = TRUE;
+ gs->animating = FALSE;
}
- /* TODO: animate move+resize */
- configureXWindow (cw, CWX | CWY | CWWidth | CWHeight, &xwc);
+ gs->anim.progress = (gs->anim.duration - gs->anim.timer) / gs->anim.duration;
}
- return TRUE;
+ UNWRAP (gs, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, ms);
+ WRAP (gs, s, preparePaintScreen, gridPreparePaintScreen);
}
#define HANDLER(WHERE) \
static Bool \
- grid##WHERE(CompDisplay *d, \
+ grid##WHERE(CompDisplay *d, \
CompAction *action, \
CompActionState state, \
CompOption *option, \
@@ -273,6 +796,7 @@
HANDLER (TopLeft)
HANDLER (Top)
HANDLER (TopRight)
+HANDLER (Maximize)
#undef HANDLER
@@ -282,6 +806,8 @@
gridInitDisplay (CompPlugin *p,
CompDisplay *d)
{
+ GridDisplay *gd;
+
if (!checkPluginABI ("core", CORE_ABIVERSION))
return FALSE;
@@ -294,22 +820,129 @@
gridSetPutToprightKeyInitiate (d, gridTopRight);
gridSetPutBottomleftKeyInitiate (d, gridBottomLeft);
gridSetPutBottomrightKeyInitiate (d, gridBottomRight);
+ gridSetPutMaximizeKeyInitiate (d, gridMaximize);
+
+ gd = malloc (sizeof (GridDisplay));
+ if (!gd)
+ return FALSE;
+
+ gd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (gd->screenPrivateIndex < 0)
+ {
+ free (gd);
+ return FALSE;
+ }
+
+ WRAP (gd, d, handleEvent, gridHandleEvent);
+
+ d->base.privates[displayPrivateIndex].ptr = gd;
+
+ return TRUE;
+}
+
+static void
+gridFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ GRID_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, gd->screenPrivateIndex);
+
+ UNWRAP (gd, d, handleEvent);
+
+ free (gd);
+}
+
+static Bool
+gridInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ GridScreen * gs;
+
+ GRID_DISPLAY (s->display);
+
+ gs = malloc (sizeof (GridScreen));
+ if (!gs)
+ return FALSE;
+
+ gs->grabIsMove = FALSE;
+ gs->edge = NoEdge;
+ gs->lastEdge = NoEdge;
+ gs->drawing = FALSE;
+
+ gs->w = 0;
+
+ gs->anim.progress = 0.0f;
+ gs->anim.fromRect.x = 0;
+ gs->anim.fromRect.y = 0;
+ gs->anim.fromRect.width = 0;
+ gs->anim.fromRect.height =0;
+ gs->anim.targetRect.x = 0;
+ gs->anim.targetRect.y = 0;
+ gs->anim.targetRect.width = 0;
+ gs->anim.targetRect.height = 0;
+ gs->anim.currentRect.x = 0;
+ gs->anim.currentRect.y = 0;
+ gs->anim.currentRect.width = 0;
+ gs->anim.currentRect.height = 0;
+ gs->anim.opacity = 0.5f;
+ gs->anim.timer = 0.0f;
+ gs->anim.duration = 0;
+ gs->anim.complete = FALSE;
+ gs->anim.fadingOut = FALSE;
+
+ gs->animating=FALSE;
+
+ WRAP (gs, s, windowGrabNotify, gridWindowGrabNotify);
+ WRAP (gs, s, windowUngrabNotify, gridWindowUngrabNotify);
+ WRAP (gs, s, paintOutput, gridPaintOutput);
+ WRAP (gs, s, preparePaintScreen, gridPreparePaintScreen);
+
+ s->base.privates[gd->screenPrivateIndex].ptr = gs;
return TRUE;
}
+static void
+gridFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ GRID_SCREEN (s);
+
+ UNWRAP (gs, s, windowGrabNotify);
+ UNWRAP (gs, s, windowUngrabNotify);
+ UNWRAP (gs, s, paintOutput);
+ UNWRAP (gs, s, preparePaintScreen);
+
+ free (gs);
+}
+
static CompBool
gridInitObject (CompPlugin *p,
CompObject *o)
{
static InitPluginObjectProc dispTab[] = {
(InitPluginObjectProc) 0, /* InitCore */
- (InitPluginObjectProc) gridInitDisplay
+ (InitPluginObjectProc) gridInitDisplay,
+ (InitPluginObjectProc) gridInitScreen
};
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
}
+static void
+gridFiniObject (CompPlugin *p,
+ CompObject *o)
+{
+ static FiniPluginObjectProc dispTab[] = {
+ (FiniPluginObjectProc) 0, /* FiniCore */
+ (FiniPluginObjectProc) gridFiniDisplay,
+ (FiniPluginObjectProc) gridFiniScreen
+ };
+
+ DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
+}
+
static Bool
gridInitPlugin (CompPlugin *p)
{
@@ -318,6 +951,10 @@
setlinebuf(gridOut);
#endif
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ return FALSE;
+
return TRUE;
}
@@ -328,6 +965,8 @@
fclose(gridOut);
gridOut = NULL;
#endif
+
+ freeDisplayPrivateIndex(displayPrivateIndex);
}
CompPluginVTable gridVTable =
@@ -337,7 +976,7 @@
gridInitPlugin,
gridFiniPlugin,
gridInitObject,
- 0,
+ gridFiniObject,
0,
0
};
@@ -346,4 +985,4 @@
getCompPluginInfo ()
{
return &gridVTable;
-}
+}
\ No newline at end of file

View file

@ -0,0 +1,510 @@
--- metadata/grid.xml.in 2016-04-10 12:23:24.000000000 -0700
+++ metadata/grid.xml.in 2017-03-01 23:26:45.521723881 -0800
@@ -52,7 +52,505 @@
<_long>Move window to the bottom right corner</_long>
<default>&lt;Primary&gt;&lt;Alt&gt;KP_3</default>
</option>
+ <option name="put_maximize_key" type="key">
+ <_short>Maximize</_short>
+ <_long>Maximize window</_long>
+ <default>&lt;Primary&gt;&lt;Alt&gt;KP_0</default>
+ </option>
+ <option name="cycle_sizes" type="key">
+ <_short>Cycle Through Multiple Sizes</_short>
+ <_long>Cycle through multiple different sizes by using the same keyboard shortcut multiple times in a row.</_long>
+ <default>false</default>
+ </option>
+ </group>
+ <group>
+ <_short>Corners / Edges</_short>
+ <subgroup>
+ <_short>Resize Actions</_short>
+ <_long>Window resize action</_long>
+ <option name="top_left_corner_action" type="int">
+ <_short>Top Left Corner</_short>
+ <_long>Action to be performed when window is dropped on the top left corner</_long>
+ <default>7</default>
+ <min>0</min>
+ <max>10</max>
+ <desc>
+ <value>0</value>
+ <_name>None</_name>
+ </desc>
+ <desc>
+ <value>1</value>
+ <_name>Bottom Left Corner</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Bottom Half</_name>
+ </desc>
+ <desc>
+ <value>3</value>
+ <_name>Bottom Right Corner</_name>
+ </desc>
+ <desc>
+ <value>4</value>
+ <_name>Left Half</_name>
+ </desc>
+ <desc>
+ <value>5</value>
+ <_name>Fill Screen</_name>
+ </desc>
+ <desc>
+ <value>6</value>
+ <_name>Right Half</_name>
+ </desc>
+ <desc>
+ <value>7</value>
+ <_name>Top Left Corner</_name>
+ </desc>
+ <desc>
+ <value>8</value>
+ <_name>Top Half</_name>
+ </desc>
+ <desc>
+ <value>9</value>
+ <_name>Top Right Corner</_name>
+ </desc>
+ <desc>
+ <value>10</value>
+ <_name>Maximize</_name>
+ </desc>
+ </option>
+ <option name="top_edge_action" type="int">
+ <_short>Top Edge</_short>
+ <_long>Action to be performed when window is dropped on the top edge</_long>
+ <default>10</default>
+ <min>0</min>
+ <max>10</max>
+ <desc>
+ <value>0</value>
+ <_name>None</_name>
+ </desc>
+ <desc>
+ <value>1</value>
+ <_name>Bottom Left Corner</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Bottom Half</_name>
+ </desc>
+ <desc>
+ <value>3</value>
+ <_name>Bottom Right Corner</_name>
+ </desc>
+ <desc>
+ <value>4</value>
+ <_name>Left Half</_name>
+ </desc>
+ <desc>
+ <value>5</value>
+ <_name>Fill Screen</_name>
+ </desc>
+ <desc>
+ <value>6</value>
+ <_name>Right Half</_name>
+ </desc>
+ <desc>
+ <value>7</value>
+ <_name>Top Left Corner</_name>
+ </desc>
+ <desc>
+ <value>8</value>
+ <_name>Top Half</_name>
+ </desc>
+ <desc>
+ <value>9</value>
+ <_name>Top Right Corner</_name>
+ </desc>
+ <desc>
+ <value>10</value>
+ <_name>Maximize</_name>
+ </desc>
+ </option>
+ <option name="top_right_corner_action" type="int">
+ <_short>Top Right Corner</_short>
+ <_long>Action to be performed when window is dropped on the top right corner</_long>
+ <default>9</default>
+ <min>0</min>
+ <max>10</max>
+ <desc>
+ <value>0</value>
+ <_name>None</_name>
+ </desc>
+ <desc>
+ <value>1</value>
+ <_name>Bottom Left Corner</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Bottom Half</_name>
+ </desc>
+ <desc>
+ <value>3</value>
+ <_name>Bottom Right Corner</_name>
+ </desc>
+ <desc>
+ <value>4</value>
+ <_name>Left Half</_name>
+ </desc>
+ <desc>
+ <value>5</value>
+ <_name>Fill Screen</_name>
+ </desc>
+ <desc>
+ <value>6</value>
+ <_name>Right Half</_name>
+ </desc>
+ <desc>
+ <value>7</value>
+ <_name>Top Left Corner</_name>
+ </desc>
+ <desc>
+ <value>8</value>
+ <_name>Top Half</_name>
+ </desc>
+ <desc>
+ <value>9</value>
+ <_name>Top Right Corner</_name>
+ </desc>
+ <desc>
+ <value>10</value>
+ <_name>Maximize</_name>
+ </desc>
+ </option>
+ <option name="left_edge_action" type="int">
+ <_short>Left Edge</_short>
+ <_long>Action to be performed when window is dropped on the left edge</_long>
+ <default>4</default>
+ <min>0</min>
+ <max>10</max>
+ <desc>
+ <value>0</value>
+ <_name>None</_name>
+ </desc>
+ <desc>
+ <value>1</value>
+ <_name>Bottom Left Corner</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Bottom Half</_name>
+ </desc>
+ <desc>
+ <value>3</value>
+ <_name>Bottom Right Corner</_name>
+ </desc>
+ <desc>
+ <value>4</value>
+ <_name>Left Half</_name>
+ </desc>
+ <desc>
+ <value>5</value>
+ <_name>Fill Screen</_name>
+ </desc>
+ <desc>
+ <value>6</value>
+ <_name>Right Half</_name>
+ </desc>
+ <desc>
+ <value>7</value>
+ <_name>Top Left Corner</_name>
+ </desc>
+ <desc>
+ <value>8</value>
+ <_name>Top Half</_name>
+ </desc>
+ <desc>
+ <value>9</value>
+ <_name>Top Right Corner</_name>
+ </desc>
+ <desc>
+ <value>10</value>
+ <_name>Maximize</_name>
+ </desc>
+ </option>
+ <option name="right_edge_action" type="int">
+ <_short>Right Edge</_short>
+ <_long>Action to be performed when window is dropped on the right edge</_long>
+ <default>6</default>
+ <min>0</min>
+ <max>10</max>
+ <desc>
+ <value>0</value>
+ <_name>None</_name>
+ </desc>
+ <desc>
+ <value>1</value>
+ <_name>Bottom Left Corner</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Bottom Half</_name>
+ </desc>
+ <desc>
+ <value>3</value>
+ <_name>Bottom Right Corner</_name>
+ </desc>
+ <desc>
+ <value>4</value>
+ <_name>Left Half</_name>
+ </desc>
+ <desc>
+ <value>5</value>
+ <_name>Fill Screen</_name>
+ </desc>
+ <desc>
+ <value>6</value>
+ <_name>Right Half</_name>
+ </desc>
+ <desc>
+ <value>7</value>
+ <_name>Top Left Corner</_name>
+ </desc>
+ <desc>
+ <value>8</value>
+ <_name>Top Half</_name>
+ </desc>
+ <desc>
+ <value>9</value>
+ <_name>Top Right Corner</_name>
+ </desc>
+ <desc>
+ <value>10</value>
+ <_name>Maximize</_name>
+ </desc>
+ </option>
+ <option name="bottom_left_corner_action" type="int">
+ <_short>Bottom Left Corner</_short>
+ <_long>Action to be performed when window is dropped on the bottom left corner</_long>
+ <default>1</default>
+ <min>0</min>
+ <max>10</max>
+ <desc>
+ <value>0</value>
+ <_name>None</_name>
+ </desc>
+ <desc>
+ <value>1</value>
+ <_name>Bottom Left Corner</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Bottom Half</_name>
+ </desc>
+ <desc>
+ <value>3</value>
+ <_name>Bottom Right Corner</_name>
+ </desc>
+ <desc>
+ <value>4</value>
+ <_name>Left Half</_name>
+ </desc>
+ <desc>
+ <value>5</value>
+ <_name>Fill Screen</_name>
+ </desc>
+ <desc>
+ <value>6</value>
+ <_name>Right Half</_name>
+ </desc>
+ <desc>
+ <value>7</value>
+ <_name>Top Left Corner</_name>
+ </desc>
+ <desc>
+ <value>8</value>
+ <_name>Top Half</_name>
+ </desc>
+ <desc>
+ <value>9</value>
+ <_name>Top Right Corner</_name>
+ </desc>
+ <desc>
+ <value>10</value>
+ <_name>Maximize</_name>
+ </desc>
+ </option>
+ <option name="bottom_edge_action" type="int">
+ <_short>Bottom Edge</_short>
+ <_long>Action to be performed when window is dropped on the bottom edge</_long>
+ <default>2</default>
+ <min>0</min>
+ <max>10</max>
+ <desc>
+ <value>0</value>
+ <_name>None</_name>
+ </desc>
+ <desc>
+ <value>1</value>
+ <_name>Bottom Left Corner</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Bottom Half</_name>
+ </desc>
+ <desc>
+ <value>3</value>
+ <_name>Bottom Right Corner</_name>
+ </desc>
+ <desc>
+ <value>4</value>
+ <_name>Left Half</_name>
+ </desc>
+ <desc>
+ <value>5</value>
+ <_name>Fill Screen</_name>
+ </desc>
+ <desc>
+ <value>6</value>
+ <_name>Right Half</_name>
+ </desc>
+ <desc>
+ <value>7</value>
+ <_name>Top Left Corner</_name>
+ </desc>
+ <desc>
+ <value>8</value>
+ <_name>Top Half</_name>
+ </desc>
+ <desc>
+ <value>9</value>
+ <_name>Top Right Corner</_name>
+ </desc>
+ <desc>
+ <value>10</value>
+ <_name>Maximize</_name>
+ </desc>
+ </option>
+ <option name="bottom_right_corner_action" type="int">
+ <_short>Bottom Right Corner</_short>
+ <_long>Action to be performed when window is dropped on the bottom right corner</_long>
+ <default>3</default>
+ <min>0</min>
+ <max>10</max>
+ <desc>
+ <value>0</value>
+ <_name>None</_name>
+ </desc>
+ <desc>
+ <value>1</value>
+ <_name>Bottom Left Corner</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Bottom Half</_name>
+ </desc>
+ <desc>
+ <value>3</value>
+ <_name>Bottom Right Corner</_name>
+ </desc>
+ <desc>
+ <value>4</value>
+ <_name>Left Half</_name>
+ </desc>
+ <desc>
+ <value>5</value>
+ <_name>Fill Screen</_name>
+ </desc>
+ <desc>
+ <value>6</value>
+ <_name>Right Half</_name>
+ </desc>
+ <desc>
+ <value>7</value>
+ <_name>Top Left Corner</_name>
+ </desc>
+ <desc>
+ <value>8</value>
+ <_name>Top Half</_name>
+ </desc>
+ <desc>
+ <value>9</value>
+ <_name>Top Right Corner</_name>
+ </desc>
+ <desc>
+ <value>10</value>
+ <_name>Maximize</_name>
+ </desc>
+ </option>
+ </subgroup>
+ <subgroup>
+ <_short>Thresholds</_short>
+ <option name="left_edge_threshold" type="int">
+ <_short>Left Edge</_short>
+ <_long>Maximum number of pixels from the left edge a window can be dropped</_long>
+ <default>5</default>
+ <min>0</min>
+ <max>500</max>
+ </option>
+ <option name="right_edge_threshold" type="int">
+ <_short>Right Edge</_short>
+ <_long>Maximum number of pixels from the right edge a window can be dropped</_long>
+ <default>5</default>
+ <min>0</min>
+ <max>500</max>
+ </option>
+ <option name="top_edge_threshold" type="int">
+ <_short>Top Edge</_short>
+ <_long>Maximum number of pixels from the top edge a window can be dropped</_long>
+ <default>5</default>
+ <min>0</min>
+ <max>500</max>
+ </option>
+ <option name="bottom_edge_threshold" type="int">
+ <_short>Bottom Edge</_short>
+ <_long>Maximum number of pixels from the Bottom edge a window can be dropped</_long>
+ <default>5</default>
+ <min>0</min>
+ <max>500</max>
+ </option>
+ </subgroup>
+ </group>
+ <group>
+ <_short>Appearance</_short>
+ <option name="draw_indicator" type="bool">
+ <_short>Draw Indicator</_short>
+ <_long>Draw Window Resize Indicator</_long>
+ <default>true</default>
+ </option>
+ <option name="animation_duration" type="int">
+ <_short>Preview Animation Duration</_short>
+ <_long>Preview animation duration (in ms).</_long>
+ <default>350</default>
+ <min>0</min>
+ </option>
+ <option name="outline_thickness" type="float">
+ <_short>Outline Thickness</_short>
+ <_long>Outline Thickness</_long>
+ <default>2.0</default>
+ <min>1.0</min>
+ <max>8.0</max>
+ <precision>1.0</precision>
+ </option>
+ <option name="outline_color" type="color">
+ <_short>Outline Color</_short>
+ <_long>Color of the resize indicator outline</_long>
+ <default>
+ <red>0x2f2f</red>
+ <green>0x2f2f</green>
+ <blue>0x4f4f</blue>
+ <alpha>0x9f9f</alpha>
+ </default>
+ </option>
+ <option name="fill_color" type="color">
+ <_short>Fill Color</_short>
+ <_long>Fill color of the resize indicator</_long>
+ <default>
+ <red>0x2f2f</red>
+ <green>0x2f2f</green>
+ <blue>0x4f4f</blue>
+ <alpha>0x4f4f</alpha>
+ </default>
+ </option>
</group>
</display>
</plugin>
-</compiz>
+</compiz>
\ No newline at end of file

View file

@ -2,7 +2,7 @@
pkgname=compiz-plugins-extra pkgname=compiz-plugins-extra
version=0.8.12.1 version=0.8.12.1
revision=1 revision=2
build_style=gnu-configure build_style=gnu-configure
configure_args="--disable-static" configure_args="--disable-static"