summaryrefslogtreecommitdiff
path: root/plugins/rotate.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/rotate.c')
-rw-r--r--plugins/rotate.c807
1 files changed, 807 insertions, 0 deletions
diff --git a/plugins/rotate.c b/plugins/rotate.c
new file mode 100644
index 0000000..1202227
--- /dev/null
+++ b/plugins/rotate.c
@@ -0,0 +1,807 @@
+/*
+ * 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 <math.h>
+#include <sys/time.h>
+
+#include <comp.h>
+
+#define ROTATE_POINTER_INVERT_Y_DEFAULT FALSE
+
+#define ROTATE_POINTER_SENSITIVITY_DEFAULT 1.0f
+#define ROTATE_POINTER_SENSITIVITY_MIN 0.01f
+#define ROTATE_POINTER_SENSITIVITY_MAX 100.0f
+#define ROTATE_POINTER_SENSITIVITY_PRECISION 0.01f
+
+#define ROTATE_POINTER_SENSITIVITY_FACTOR 0.05f
+
+#define ROTATE_ACCELERATION_DEFAULT 4.0f
+#define ROTATE_ACCELERATION_MIN 1.0f
+#define ROTATE_ACCELERATION_MAX 20.0f
+#define ROTATE_ACCELERATION_PRECISION 0.1f
+
+#define ROTATE_INITIATE_BUTTON_DEFAULT Button1
+#define ROTATE_INITIATE_MODIFIERS_DEFAULT (CompPressMask | CompSuperMask)
+
+#define ROTATE_TERMINATE_BUTTON_DEFAULT Button1
+#define ROTATE_TERMINATE_MODIFIERS_DEFAULT CompReleaseMask
+
+#define ROTATE_LEFT_KEY_DEFAULT "Left"
+#define ROTATE_LEFT_MODIFIERS_DEFAULT \
+ (CompPressMask | ControlMask | CompSuperMask)
+
+#define ROTATE_RIGHT_KEY_DEFAULT "Right"
+#define ROTATE_RIGHT_MODIFIERS_DEFAULT \
+ (CompPressMask | ControlMask | CompSuperMask)
+
+#define ROTATE_SNAP_TOP_DEFAULT FALSE
+
+static int displayPrivateIndex;
+
+typedef struct _RotateDisplay {
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+} RotateDisplay;
+
+#define ROTATE_SCREEN_OPTION_POINTER_INVERT_Y 0
+#define ROTATE_SCREEN_OPTION_POINTER_SENSITIVITY 1
+#define ROTATE_SCREEN_OPTION_ACCELERATION 2
+#define ROTATE_SCREEN_OPTION_INITIATE 3
+#define ROTATE_SCREEN_OPTION_TERMINATE 4
+#define ROTATE_SCREEN_OPTION_LEFT 5
+#define ROTATE_SCREEN_OPTION_RIGHT 6
+#define ROTATE_SCREEN_OPTION_SNAP_TOP 7
+#define ROTATE_SCREEN_OPTION_NUM 8
+
+typedef struct _RotateScreen {
+ PreparePaintScreenProc preparePaintScreen;
+ DonePaintScreenProc donePaintScreen;
+ PaintScreenProc paintScreen;
+
+ CompOption opt[ROTATE_SCREEN_OPTION_NUM];
+
+ Bool pointerInvertY;
+ float pointerSensitivity;
+ Bool snapTop;
+ float acceleration;
+
+ int grabIndex;
+
+ GLfloat xrot, xVelocity;
+ GLfloat yrot, yVelocity;
+
+ GLfloat baseXrot;
+
+ Bool moving;
+ GLfloat moveTo;
+
+ int prevPointerX;
+ int prevPointerY;
+ XPoint savedPointer;
+ Bool grabbed;
+} RotateScreen;
+
+#define GET_ROTATE_DISPLAY(d) \
+ ((RotateDisplay *) (d)->privates[displayPrivateIndex].ptr)
+
+#define ROTATE_DISPLAY(d) \
+ RotateDisplay *rd = GET_ROTATE_DISPLAY (d)
+
+#define GET_ROTATE_SCREEN(s, rd) \
+ ((RotateScreen *) (s)->privates[(rd)->screenPrivateIndex].ptr)
+
+#define ROTATE_SCREEN(s) \
+ RotateScreen *rs = GET_ROTATE_SCREEN (s, GET_ROTATE_DISPLAY (s->display))
+
+#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
+
+static CompOption *
+rotateGetScreenOptions (CompScreen *screen,
+ int *count)
+{
+ ROTATE_SCREEN (screen);
+
+ *count = NUM_OPTIONS (rs);
+ return rs->opt;
+}
+
+static Bool
+rotateSetScreenOption (CompScreen *screen,
+ char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ ROTATE_SCREEN (screen);
+
+ o = compFindOption (rs->opt, NUM_OPTIONS (rs), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index) {
+ case ROTATE_SCREEN_OPTION_POINTER_INVERT_Y:
+ if (compSetBoolOption (o, value))
+ {
+ rs->pointerInvertY = o->value.b;
+ return TRUE;
+ }
+ break;
+ case ROTATE_SCREEN_OPTION_POINTER_SENSITIVITY:
+ if (compSetFloatOption (o, value))
+ {
+ rs->pointerSensitivity = o->value.f *
+ ROTATE_POINTER_SENSITIVITY_FACTOR;
+ return TRUE;
+ }
+ break;
+ case ROTATE_SCREEN_OPTION_ACCELERATION:
+ if (compSetFloatOption (o, value))
+ {
+ rs->acceleration = o->value.f;
+ return TRUE;
+ }
+ break;
+ case ROTATE_SCREEN_OPTION_INITIATE:
+ case ROTATE_SCREEN_OPTION_LEFT:
+ case ROTATE_SCREEN_OPTION_RIGHT:
+ if (addScreenBinding (screen, &value->bind))
+ {
+ removeScreenBinding (screen, &o->value.bind);
+
+ if (compSetBindingOption (o, value))
+ return TRUE;
+ }
+ break;
+ case ROTATE_SCREEN_OPTION_TERMINATE:
+ if (compSetBindingOption (o, value))
+ return TRUE;
+ break;
+ case ROTATE_SCREEN_OPTION_SNAP_TOP:
+ if (compSetBoolOption (o, value))
+ {
+ rs->snapTop = o->value.b;
+ return TRUE;
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static void
+rotateScreenInitOptions (RotateScreen *rs,
+ Display *display)
+{
+ CompOption *o;
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_POINTER_INVERT_Y];
+ o->name = "invert_y";
+ o->shortDesc = "Pointer Invert Y";
+ o->longDesc = "Invert Y axis for pointer movement";
+ o->type = CompOptionTypeBool;
+ o->value.b = ROTATE_POINTER_INVERT_Y_DEFAULT;
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_POINTER_SENSITIVITY];
+ o->name = "sensitivity";
+ o->shortDesc = "Pointer Sensitivity";
+ o->longDesc = "Sensitivity of pointer movement";
+ o->type = CompOptionTypeFloat;
+ o->value.f = ROTATE_POINTER_SENSITIVITY_DEFAULT;
+ o->rest.f.min = ROTATE_POINTER_SENSITIVITY_MIN;
+ o->rest.f.max = ROTATE_POINTER_SENSITIVITY_MAX;
+ o->rest.f.precision = ROTATE_POINTER_SENSITIVITY_PRECISION;
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_ACCELERATION];
+ o->name = "acceleration";
+ o->shortDesc = "Acceleration";
+ o->longDesc = "Rotation Acceleration";
+ o->type = CompOptionTypeFloat;
+ o->value.f = ROTATE_ACCELERATION_DEFAULT;
+ o->rest.f.min = ROTATE_ACCELERATION_MIN;
+ o->rest.f.max = ROTATE_ACCELERATION_MAX;
+ o->rest.f.precision = ROTATE_ACCELERATION_PRECISION;
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_INITIATE];
+ o->name = "initiate";
+ o->shortDesc = "Initiate";
+ o->longDesc = "Start Rotation";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeButton;
+ o->value.bind.u.button.modifiers = ROTATE_INITIATE_MODIFIERS_DEFAULT;
+ o->value.bind.u.button.button = ROTATE_INITIATE_BUTTON_DEFAULT;
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_TERMINATE];
+ o->name = "terminate";
+ o->shortDesc = "Terminate";
+ o->longDesc = "Stop Rotation";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeButton;
+ o->value.bind.u.button.modifiers = ROTATE_TERMINATE_MODIFIERS_DEFAULT;
+ o->value.bind.u.button.button = ROTATE_TERMINATE_BUTTON_DEFAULT;
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_LEFT];
+ o->name = "rotate_left";
+ o->shortDesc = "Rotate Left";
+ o->longDesc = "Rotate Left";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = ROTATE_LEFT_MODIFIERS_DEFAULT;
+ o->value.bind.u.key.keycode =
+ XKeysymToKeycode (display,
+ XStringToKeysym (ROTATE_LEFT_KEY_DEFAULT));
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_RIGHT];
+ o->name = "rotate_right";
+ o->shortDesc = "Rotate Right";
+ o->longDesc = "Rotate Right";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = ROTATE_RIGHT_MODIFIERS_DEFAULT;
+ o->value.bind.u.key.keycode =
+ XKeysymToKeycode (display,
+ XStringToKeysym (ROTATE_RIGHT_KEY_DEFAULT));
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_SNAP_TOP];
+ o->name = "snap_top";
+ o->shortDesc = "Snap To Top Face";
+ o->longDesc = "Snap Cube Rotation to Top Face";
+ o->type = CompOptionTypeBool;
+ o->value.b = ROTATE_SNAP_TOP_DEFAULT;
+}
+
+static int
+adjustVelocity (RotateScreen *rs)
+{
+ float xrot, yrot, adjust, amount;
+
+ if (rs->moving)
+ {
+ xrot = rs->moveTo + (rs->xrot + rs->baseXrot);
+ }
+ else
+ {
+ xrot = rs->xrot;
+ if (rs->xrot < -45.0f)
+ xrot = 90.0f + rs->xrot;
+ else if (rs->xrot > 45.0f)
+ xrot = rs->xrot - 90.0f;
+ }
+
+ adjust = -xrot * 0.05f * rs->acceleration;
+ amount = fabs (xrot);
+ if (amount < 10.0f)
+ amount = 10.0f;
+ else if (amount > 30.0f)
+ amount = 30.0f;
+
+ rs->xVelocity = (amount * rs->xVelocity + adjust) / (amount + 2.0f);
+
+ if (rs->snapTop && rs->yrot > 50.0f)
+ yrot = -(90.f - rs->yrot);
+ else
+ yrot = rs->yrot;
+
+ adjust = -yrot * 0.05f * rs->acceleration;
+ amount = fabs (rs->yrot);
+ if (amount < 10.0f)
+ amount = 10.0f;
+ else if (amount > 30.0f)
+ amount = 30.0f;
+
+ rs->yVelocity = (amount * rs->yVelocity + adjust) / (amount + 2.0f);
+
+ return (fabs (xrot) < 0.1f && fabs (rs->xVelocity) < 0.2f &&
+ fabs (yrot) < 0.1f && fabs (rs->yVelocity) < 0.2f);
+}
+
+static void
+rotatePreparePaintScreen (CompScreen *s,
+ int msSinceLastPaint)
+{
+ ROTATE_SCREEN (s);
+
+ if (rs->grabIndex)
+ {
+ rs->xrot += (rs->xVelocity * msSinceLastPaint) / s->redrawTime;
+ rs->yrot += (rs->yVelocity * msSinceLastPaint) / s->redrawTime;
+
+ if (rs->xrot > 90.0f)
+ {
+ rs->baseXrot += 90.0f;
+ rs->xrot -= 90.0f;
+ }
+ else if (rs->xrot < 0.0f)
+ {
+ rs->baseXrot -= 90.0f;
+ rs->xrot += 90.0f;
+ }
+
+ if (rs->yrot > 100.0f)
+ {
+ rs->yVelocity = -0.5f;
+ rs->yrot = 100.0f;
+ }
+ else if (rs->yrot < -100.0f)
+ {
+ rs->yVelocity = 0.5f;
+ rs->yrot = -100.0f;
+ }
+
+ if (rs->grabbed)
+ {
+ rs->xVelocity /= 1.25f;
+ rs->yVelocity /= 1.25f;
+
+ if (fabs (rs->xVelocity) < 0.01f)
+ rs->xVelocity = 0.0f;
+ if (fabs (rs->yVelocity) < 0.01f)
+ rs->yVelocity = 0.0f;
+ }
+ else if (adjustVelocity (rs))
+ {
+ rs->xVelocity = 0.0f;
+ rs->yVelocity = 0.0f;
+
+ if (fabs (rs->yrot) < 0.1f)
+ {
+ int move;
+
+ rs->xrot += rs->baseXrot;
+ if (rs->xrot < 0.0f)
+ move = (rs->xrot / 90.0f) - 0.5f;
+ else
+ move = (rs->xrot / 90.0f) + 0.5f;
+
+ if (move)
+ {
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (w->attrib.map_state != IsViewable)
+ continue;
+
+ if (w->type == s->display->winDesktopAtom ||
+ w->type == s->display->winDockAtom)
+ continue;
+
+ (*s->invisibleWindowMove) (w, s->width * move, 0);
+
+ w->invisible = WINDOW_INVISIBLE (w);
+
+ XMoveWindow (s->display->display,
+ (w->client) ? w->client : w->id,
+ w->attrib.x, w->attrib.y);
+ }
+ }
+
+ rs->xrot = 0.0f;
+ rs->yrot = 0.0f;
+ rs->baseXrot = rs->moveTo = 0.0f;
+ rs->moving = FALSE;
+
+ removeScreenGrab (s, rs->grabIndex, &rs->savedPointer);
+ rs->grabIndex = 0;
+ }
+ }
+ }
+
+ UNWRAP (rs, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, msSinceLastPaint);
+ WRAP (rs, s, preparePaintScreen, rotatePreparePaintScreen);
+}
+
+static void
+rotateDonePaintScreen (CompScreen *s)
+{
+ ROTATE_SCREEN (s);
+
+ if (rs->grabIndex)
+ {
+ if ((!rs->grabbed && !rs->snapTop) || rs->xVelocity || rs->yVelocity)
+ damageScreen (s);
+ }
+
+ UNWRAP (rs, s, donePaintScreen);
+ (*s->donePaintScreen) (s);
+ WRAP (rs, s, donePaintScreen, rotateDonePaintScreen);
+}
+
+static Bool
+rotatePaintScreen (CompScreen *s,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ Region region,
+ unsigned int mask)
+{
+ Bool status;
+
+ ROTATE_SCREEN (s);
+
+ if (rs->grabIndex)
+ {
+ ScreenPaintAttrib sa = *sAttrib;
+
+ sa.xRotate += rs->baseXrot + rs->xrot;
+ sa.vRotate += rs->yrot;
+
+ mask &= ~PAINT_SCREEN_REGION_MASK;
+ mask |= PAINT_SCREEN_TRANSFORMED_MASK;
+
+ UNWRAP (rs, s, paintScreen);
+ status = (*s->paintScreen) (s, &sa, wAttrib, region, mask);
+ WRAP (rs, s, paintScreen, rotatePaintScreen);
+ }
+ else
+ {
+ UNWRAP (rs, s, paintScreen);
+ status = (*s->paintScreen) (s, sAttrib, wAttrib, region, mask);
+ WRAP (rs, s, paintScreen, rotatePaintScreen);
+ }
+
+ return status;
+}
+
+static void
+rotateInitiate (CompScreen *s,
+ int x,
+ int y)
+{
+ ROTATE_SCREEN (s);
+
+ rs->prevPointerX = x;
+ rs->prevPointerY = y;
+
+ rs->moving = FALSE;
+
+ if (!rs->grabIndex)
+ {
+ rs->grabIndex = pushScreenGrab (s, s->invisibleCursor);
+ if (rs->grabIndex)
+ {
+ rs->savedPointer.x = rs->prevPointerX;
+ rs->savedPointer.y = rs->prevPointerY;
+
+ gettimeofday (&s->lastRedraw, 0);
+ }
+ }
+
+ if (rs->grabIndex)
+ {
+ rs->grabbed = TRUE;
+ rs->snapTop = rs->opt[ROTATE_SCREEN_OPTION_SNAP_TOP].value.b;
+ }
+}
+
+static void
+rotateLeft (CompScreen *s,
+ int x,
+ int y)
+{
+ ROTATE_SCREEN (s);
+
+ if (!rs->grabIndex)
+ rotateInitiate (s, x, y);
+
+ if (rs->grabIndex)
+ {
+ rs->moving = TRUE;
+ rs->moveTo -= 90.0f;
+ rs->grabbed = FALSE;
+ damageScreen (s);
+ }
+}
+
+static void
+rotateRight (CompScreen *s,
+ int x,
+ int y)
+{
+ ROTATE_SCREEN (s);
+
+ if (!rs->grabIndex)
+ rotateInitiate (s, x, y);
+
+ if (rs->grabIndex)
+ {
+ rs->moving = TRUE;
+ rs->moveTo += 90.0f;
+ rs->grabbed = FALSE;
+
+ damageScreen (s);
+ }
+}
+
+static void
+rotateTerminate (CompScreen *s)
+{
+ ROTATE_SCREEN (s);
+
+ if (rs->grabIndex)
+ {
+ rs->grabbed = FALSE;
+ damageScreen (s);
+ }
+}
+
+static void
+rotateHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ CompScreen *s;
+
+ ROTATE_DISPLAY (d);
+
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ s = findScreenAtDisplay (d, event->xkey.root);
+ if (s)
+ {
+ ROTATE_SCREEN (s);
+
+ if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_INITIATE], event))
+ rotateInitiate (s, event->xkey.x_root, event->xkey.y_root);
+
+ if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_LEFT], event))
+ rotateLeft (s, event->xkey.x_root, event->xkey.y_root);
+
+ if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_RIGHT], event))
+ rotateRight (s, event->xkey.x_root, event->xkey.y_root);
+
+ if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_TERMINATE], event))
+ rotateTerminate (s);
+
+ if (event->type == KeyPress &&
+ event->xkey.keycode == s->escapeKeyCode)
+ {
+ rs->snapTop = FALSE;
+ rotateTerminate (s);
+ }
+ }
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ s = findScreenAtDisplay (d, event->xbutton.root);
+ if (s)
+ {
+ ROTATE_SCREEN (s);
+
+ if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_INITIATE], event))
+ rotateInitiate (s,
+ event->xbutton.x_root,
+ event->xbutton.y_root);
+
+ if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_LEFT], event))
+ rotateLeft (s, event->xbutton.x_root, event->xbutton.y_root);
+
+ if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_RIGHT], event))
+ rotateRight (s, event->xbutton.x_root, event->xbutton.y_root);
+
+ if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_TERMINATE], event))
+ rotateTerminate (s);
+ }
+ break;
+ case MotionNotify:
+ s = findScreenAtDisplay (d, event->xmotion.root);
+ if (s)
+ {
+ ROTATE_SCREEN (s);
+
+ if (rs->grabIndex && rs->grabbed)
+ {
+ GLfloat pointerDx;
+ GLfloat pointerDy;
+
+ pointerDx = event->xmotion.x_root - rs->prevPointerX;
+ pointerDy = event->xmotion.y_root - rs->prevPointerY;
+ rs->prevPointerX = event->xmotion.x_root;
+ rs->prevPointerY = event->xmotion.y_root;
+
+ if (event->xmotion.x_root < 50 ||
+ event->xmotion.y_root < 50 ||
+ event->xmotion.x_root > s->width - 50 ||
+ event->xmotion.y_root > s->height - 50)
+ {
+ rs->prevPointerX = s->width / 2;
+ rs->prevPointerY = s->height / 2;
+
+ XWarpPointer (d->display, None, s->root, 0, 0, 0, 0,
+ rs->prevPointerX, rs->prevPointerY);
+ }
+
+ if (rs->pointerInvertY)
+ pointerDy = -pointerDy;
+
+ rs->xVelocity += pointerDx * rs->pointerSensitivity;
+ rs->yVelocity += pointerDy * rs->pointerSensitivity;
+
+ damageScreen (s);
+ return;
+ }
+ }
+ default:
+ break;
+ }
+
+ UNWRAP (rd, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (rd, d, handleEvent, rotateHandleEvent);
+}
+
+static Bool
+rotateInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ RotateDisplay *rd;
+
+ rd = malloc (sizeof (RotateDisplay));
+ if (!rd)
+ return FALSE;
+
+ rd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (rd->screenPrivateIndex < 0)
+ {
+ free (rd);
+ return FALSE;
+ }
+
+ WRAP (rd, d, handleEvent, rotateHandleEvent);
+
+ d->privates[displayPrivateIndex].ptr = rd;
+
+ return TRUE;
+}
+
+static void
+rotateFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ ROTATE_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, rd->screenPrivateIndex);
+
+ UNWRAP (rd, d, handleEvent);
+
+ free (rd);
+}
+
+static Bool
+rotateInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ RotateScreen *rs;
+
+ ROTATE_DISPLAY (s->display);
+
+ rs = malloc (sizeof (RotateScreen));
+ if (!rs)
+ return FALSE;
+
+ rs->grabIndex = 0;
+
+ rs->xrot = 0.0f;
+ rs->xVelocity = 0.0f;
+ rs->yrot = 0.0f;
+ rs->yVelocity = 0.0f;
+
+ rs->baseXrot = 0.0f;
+
+ rs->moving = FALSE;
+ rs->moveTo = 0.0f;
+
+ rs->savedPointer.x = 0;
+ rs->savedPointer.y = 0;
+ rs->prevPointerX = 0;
+ rs->prevPointerY = 0;
+
+ rs->grabbed = FALSE;
+ rs->snapTop = FALSE;
+
+ rs->acceleration = ROTATE_ACCELERATION_DEFAULT;
+
+ rs->pointerInvertY = ROTATE_POINTER_INVERT_Y_DEFAULT;
+ rs->pointerSensitivity = ROTATE_POINTER_SENSITIVITY_DEFAULT *
+ ROTATE_POINTER_SENSITIVITY_FACTOR;
+
+ rotateScreenInitOptions (rs, s->display->display);
+
+ addScreenBinding (s, &rs->opt[ROTATE_SCREEN_OPTION_INITIATE].value.bind);
+ addScreenBinding (s, &rs->opt[ROTATE_SCREEN_OPTION_LEFT].value.bind);
+ addScreenBinding (s, &rs->opt[ROTATE_SCREEN_OPTION_RIGHT].value.bind);
+
+ WRAP (rs, s, preparePaintScreen, rotatePreparePaintScreen);
+ WRAP (rs, s, donePaintScreen, rotateDonePaintScreen);
+ WRAP (rs, s, paintScreen, rotatePaintScreen);
+
+ s->privates[rd->screenPrivateIndex].ptr = rs;
+
+ return TRUE;
+}
+
+static void
+rotateFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ ROTATE_SCREEN (s);
+
+ UNWRAP (rs, s, preparePaintScreen);
+ UNWRAP (rs, s, donePaintScreen);
+ UNWRAP (rs, s, paintScreen);
+
+ free (rs);
+}
+
+static Bool
+rotateInit (CompPlugin *p)
+{
+ if (!findActivePlugin ("cube"))
+ {
+ fprintf (stderr, "%s: 'cube' required but not loaded\n", programName);
+ return FALSE;
+ }
+
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+rotateFini (CompPlugin *p)
+{
+ if (displayPrivateIndex >= 0)
+ freeDisplayPrivateIndex (displayPrivateIndex);
+}
+
+CompPluginVTable rotateVTable = {
+ "rotate",
+ "Rotate Cube",
+ "Rotate desktop cube",
+ rotateInit,
+ rotateFini,
+ rotateInitDisplay,
+ rotateFiniDisplay,
+ rotateInitScreen,
+ rotateFiniScreen,
+ 0, /* InitWindow */
+ 0, /* FiniWindow */
+ 0, /* GetDisplayOptions */
+ 0, /* SetDisplayOption */
+ rotateGetScreenOptions,
+ rotateSetScreenOption
+};
+
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &rotateVTable;
+}