Logo Search packages:      
Sourcecode: beryl-plugins version File versions

rotate.c

/*
 * 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 <davidr@novell.com>
 */

#define _GNU_SOURCE                       /* for asprintf */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/time.h>

#include <X11/Xatom.h>
#include <X11/Xproto.h>

#include <beryl.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   6.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 (ControlMask | CompAltMask)

#define ROTATE_INITIATE_STICKY_BUTTON_DEFAULT    Button2
#define ROTATE_INITIATE_STICKY_MODIFIERS_DEFAULT (ControlMask | CompAltMask)

#define ROTATE_INITIATEDESKTOP_BUTTON_DEFAULT    Button2
#define ROTATE_INITIATEDESKTOP_MODIFIERS_DEFAULT 0

#define ROTATE_WHEELINGS_DEFAULT 1
#define ROTATE_WHEELINGS_MIN 1
#define ROTATE_WHEELINGS_MAX 20

#define ROTATE_WHEEL_ON_EDGES_DEFAULT FALSE

#define ROTATE_WHEELMAXDIST_DEFAULT 5
#define ROTATE_WHEELMAXDIST_MIN 1
#define ROTATE_WHEELMAXDIST_MAX 300

#define ROTATE_LEFT_WHEEL_DEFAULT    Button4
#define ROTATE_LEFT_WHEEL_MODIFIERS_DEFAULT   0

#define ROTATE_RIGHT_WHEEL_DEFAULT    Button5
#define ROTATE_RIGHT_WHEEL_MODIFIERS_DEFAULT  0

#define ROTATE_LEFT_KEY_DEFAULT       "Left"
#define ROTATE_LEFT_MODIFIERS_DEFAULT (ControlMask | CompAltMask)

#define ROTATE_RIGHT_KEY_DEFAULT       "Right"
#define ROTATE_RIGHT_MODIFIERS_DEFAULT (ControlMask | CompAltMask)

#define ROTATE_UP_KEY_DEFAULT       "Up"
#define ROTATE_UP_MODIFIERS_DEFAULT (ControlMask | CompAltMask)

#define ROTATE_DOWN_KEY_DEFAULT       "Down"
#define ROTATE_DOWN_MODIFIERS_DEFAULT (ControlMask | CompAltMask)

#define ROTATE_LEFT_WINDOW_KEY_DEFAULT       "Left"
#define ROTATE_LEFT_WINDOW_MODIFIERS_DEFAULT \
    (ShiftMask | ControlMask | CompAltMask)

#define ROTATE_RIGHT_WINDOW_KEY_DEFAULT       "Right"
#define ROTATE_RIGHT_WINDOW_MODIFIERS_DEFAULT \
    (ShiftMask | ControlMask | CompAltMask)

#define ROTATE_SNAP_TOP_DEFAULT TRUE
#define ROTATE_SNAP_BOTTOM_DEFAULT TRUE

#define ROTATE_SPEED_DEFAULT   2.5f
#define ROTATE_SPEED_MIN       0.1f
#define ROTATE_SPEED_MAX       50.0f
#define ROTATE_SPEED_PRECISION 0.1f

#define ROTATE_TIMESTEP_DEFAULT   0.9f
#define ROTATE_TIMESTEP_MIN       0.1f
#define ROTATE_TIMESTEP_MAX       50.0f
#define ROTATE_TIMESTEP_PRECISION 0.1f

#define ROTATE_MANTIMESTEP_DEFAULT   2.5f
#define ROTATE_MANTIMESTEP_MIN       0.1f
#define ROTATE_MANTIMESTEP_MAX       50.0f
#define ROTATE_MANTIMESTEP_PRECISION 0.1f

#define ROTATE_EDGEFLIP_POINTER_DEFAULT FALSE
#define ROTATE_EDGEFLIP_WINDOW_DEFAULT  TRUE
#define ROTATE_EDGEFLIP_DND_DEFAULT     TRUE

#define ROTATE_FLIPTIME_DEFAULT 250
#define ROTATE_FLIPTIME_MIN     0
#define ROTATE_FLIPTIME_MAX     1000

#define ROTATE_ZOOM_DEFAULT   0.0f
#define ROTATE_ZOOM_MIN       0.0f
#define ROTATE_ZOOM_MAX       15.0f
#define ROTATE_ZOOM_PRECISION 0.1f

#define ROTATE_ZOOM_BEFORE_ROTATE_DEFAULT FALSE

static int displayPrivateIndex;

#define ROTATE_DISPLAY_OPTION_INITIATE          0
#define ROTATE_DISPLAY_OPTION_LEFT              1
#define ROTATE_DISPLAY_OPTION_RIGHT             2
#define ROTATE_DISPLAY_OPTION_LEFT_WINDOW       3
#define ROTATE_DISPLAY_OPTION_RIGHT_WINDOW      4
#define ROTATE_DISPLAY_OPTION_EDGEFLIP_POINTER  5
#define ROTATE_DISPLAY_OPTION_EDGEFLIP_WINDOW   6
#define ROTATE_DISPLAY_OPTION_EDGEFLIP_DND      7
#define ROTATE_DISPLAY_OPTION_FLIPTIME          8
#define ROTATE_DISPLAY_OPTION_TO_1              9
#define ROTATE_DISPLAY_OPTION_TO_2             10
#define ROTATE_DISPLAY_OPTION_TO_3             11
#define ROTATE_DISPLAY_OPTION_TO_4             12
#define ROTATE_DISPLAY_OPTION_TO_5             13
#define ROTATE_DISPLAY_OPTION_TO_6             14
#define ROTATE_DISPLAY_OPTION_TO_7             15
#define ROTATE_DISPLAY_OPTION_TO_8             16
#define ROTATE_DISPLAY_OPTION_TO_9             17
#define ROTATE_DISPLAY_OPTION_TO_10            18
#define ROTATE_DISPLAY_OPTION_TO_11            19
#define ROTATE_DISPLAY_OPTION_TO_12            20
#define ROTATE_DISPLAY_OPTION_TO_1_WINDOW      21
#define ROTATE_DISPLAY_OPTION_TO_2_WINDOW      22
#define ROTATE_DISPLAY_OPTION_TO_3_WINDOW      23
#define ROTATE_DISPLAY_OPTION_TO_4_WINDOW      24
#define ROTATE_DISPLAY_OPTION_TO_5_WINDOW      25
#define ROTATE_DISPLAY_OPTION_TO_6_WINDOW      26
#define ROTATE_DISPLAY_OPTION_TO_7_WINDOW      27
#define ROTATE_DISPLAY_OPTION_TO_8_WINDOW      28
#define ROTATE_DISPLAY_OPTION_TO_9_WINDOW      29
#define ROTATE_DISPLAY_OPTION_TO_10_WINDOW     30
#define ROTATE_DISPLAY_OPTION_TO_11_WINDOW     31
#define ROTATE_DISPLAY_OPTION_TO_12_WINDOW     32
#define ROTATE_DISPLAY_OPTION_TO               33
#define ROTATE_DISPLAY_OPTION_WINDOW           34
#define ROTATE_DISPLAY_OPTION_WHEELINGS        35
#define ROTATE_DISPLAY_OPTION_LEFT_WHEEL       36
#define ROTATE_DISPLAY_OPTION_RIGHT_WHEEL      37
#define ROTATE_DISPLAY_OPTION_UP               38
#define ROTATE_DISPLAY_OPTION_DOWN             39
#define ROTATE_DISPLAY_OPTION_INITIATEDESKTOP  40
#define ROTATE_DISPLAY_OPTION_STICKY_INITIATE  41
#define ROTATE_DISPLAY_OPTION_FLIP_LEFT        42
#define ROTATE_DISPLAY_OPTION_FLIP_RIGHT       43

#define ROTATE_DISPLAY_OPTION_NUM              44

typedef struct _RotateDisplay
{
      int screenPrivateIndex;
      HandleEventProc handleEvent;

      CompOption opt[ROTATE_DISPLAY_OPTION_NUM];

      unsigned int leftWheelings, rightWheelings;
} 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_SNAP_TOP               3
#define ROTATE_SCREEN_OPTION_SPEED                  4
#define ROTATE_SCREEN_OPTION_TIMESTEP               5
#define ROTATE_SCREEN_OPTION_MANTIMESTEP            6
#define ROTATE_SCREEN_OPTION_ZOOM                   7
#define ROTATE_SCREEN_OPTION_SNAP_BOTTOM            8
#define ROTATE_SCREEN_OPTION_ZOOM_BEFORE_ROTATE     9
#define ROTATE_SCREEN_OPTION_ZOOM_ONLY_ON_INITIATE 10
#define ROTATE_SCREEN_OPTION_WHEEL_ON_EDGES        11
#define ROTATE_SCREEN_OPTION_WHEELMAXDIST          12
#define ROTATE_SCREEN_OPTION_NUM                   13


typedef struct _RotateScreen
{
      PreparePaintScreenProc preparePaintScreen;
      DonePaintScreenProc donePaintScreen;
      PaintScreenProc paintScreen;
      SetScreenOptionForPluginProc setScreenOptionForPlugin;
      WindowGrabNotifyProc windowGrabNotify;
      WindowUngrabNotifyProc windowUngrabNotify;

      CompOption opt[ROTATE_SCREEN_OPTION_NUM];

      float pointerSensitivity;
      Bool snapTop;
      Bool snapBottom;

      float zoom;

      int grabIndex;

      GLfloat xrot, xVelocity;
      GLfloat yrot, yVelocity;

      float zoomTranslate;
      GLfloat zoomVelocity;

      GLfloat baseXrot;
      GLfloat baseYrot;

      Bool moving;
      GLfloat moveTo;
      Bool zooming;
      Bool rotating;

      Bool movingVert;
      GLfloat moveToY;

      int invert;

      Window moveWindow;
      int moveWindowX;

      XPoint savedPointer;
      Bool grabbed;
      int manualAtom;
      CompTimeoutHandle rotateHandle;
      Bool slow;
      unsigned int grabMask;
      CompWindow *grabWindow;

      int previousRotationAtom;
      int snapTopBottomAtom;
} 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 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:
      case ROTATE_SCREEN_OPTION_ZOOM_BEFORE_ROTATE:
      case ROTATE_SCREEN_OPTION_ZOOM_ONLY_ON_INITIATE:
      case ROTATE_SCREEN_OPTION_WHEEL_ON_EDGES:
            if (compSetBoolOption(o, value))
                  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_SNAP_TOP:
            if (compSetBoolOption(o, value))
            {
                  rs->snapTop = o->value.b;
                  return TRUE;
            }
            break;
      case ROTATE_SCREEN_OPTION_SNAP_BOTTOM:
            if (compSetBoolOption(o, value))
            {
                  rs->snapBottom = o->value.b;
                  return TRUE;
            }
            break;
      case ROTATE_SCREEN_OPTION_ACCELERATION:
      case ROTATE_SCREEN_OPTION_SPEED:
      case ROTATE_SCREEN_OPTION_TIMESTEP:
      case ROTATE_SCREEN_OPTION_MANTIMESTEP:
            if (compSetFloatOption(o, value))
                  return TRUE;
            break;
      case ROTATE_SCREEN_OPTION_ZOOM:
            if (compSetFloatOption(o, value))
            {
                  if (o->value.f < 0.05f)
                  {
                        rs->zooming = FALSE;
                        rs->zoom = 0.0f;
                  }
                  else
                  {
                        rs->zooming = TRUE;
                        rs->zoom = o->value.f / 30.0f;
                  }

                  return TRUE;
            }
            break;
      case ROTATE_SCREEN_OPTION_WHEELMAXDIST:
            if (compSetIntOption(o, value))
                  return TRUE;
      default:
            break;
      }

      return FALSE;
}

static void rotateScreenInitOptions(RotateScreen * rs)
{
      CompOption *o;

      o = &rs->opt[ROTATE_SCREEN_OPTION_POINTER_INVERT_Y];
      o->advanced = False;
      o->name = "invert_y";
      o->group = N_("Behaviour");
      o->subGroup = N_("General");
      o->displayHints = "";
      o->shortDesc = N_("Pointer Invert Y");
      o->longDesc =
                  N_("Invert Y axis for Pointer movement while Rotating the Cube.");
      o->type = CompOptionTypeBool;
      o->value.b = ROTATE_POINTER_INVERT_Y_DEFAULT;

      o = &rs->opt[ROTATE_SCREEN_OPTION_POINTER_SENSITIVITY];
      o->advanced = False;
      o->name = "sensitivity";
      o->group = N_("Misc. Options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Pointer Sensitivity");
      o->longDesc = N_("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->advanced = False;
      o->name = "acceleration";
      o->group = N_("Misc. Options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Acceleration");
      o->longDesc = N_("Acceleration of Cube Rotation.");
      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_SNAP_TOP];
      o->advanced = False;
      o->name = "snap_top";
      o->group = N_("Behaviour");
      o->subGroup = N_("General");
      o->displayHints = "";
      o->shortDesc = N_("Snap To Top Face");
      o->longDesc = N_("Snap Cube Rotation to Top Face.");
      o->type = CompOptionTypeBool;
      o->value.b = ROTATE_SNAP_TOP_DEFAULT;

      o = &rs->opt[ROTATE_SCREEN_OPTION_SNAP_BOTTOM];
      o->advanced = False;
      o->name = "snap_bottom";
      o->group = N_("Behaviour");
      o->subGroup = N_("General");
      o->displayHints = "";
      o->shortDesc = N_("Snap To Bottom Face");
      o->longDesc = N_("Snap Cube Rotation to Bottom Face.");
      o->type = CompOptionTypeBool;
      o->value.b = ROTATE_SNAP_BOTTOM_DEFAULT;

      o = &rs->opt[ROTATE_SCREEN_OPTION_SPEED];
      o->advanced = False;
      o->name = "speed";
      o->group = N_("Misc. Options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Rotation Speed");
      o->longDesc = N_("Rotation Speed.");
      o->type = CompOptionTypeFloat;
      o->value.f = ROTATE_SPEED_DEFAULT;
      o->rest.f.min = ROTATE_SPEED_MIN;
      o->rest.f.max = ROTATE_SPEED_MAX;
      o->rest.f.precision = ROTATE_SPEED_PRECISION;

      o = &rs->opt[ROTATE_SCREEN_OPTION_TIMESTEP];
      o->advanced = False;
      o->name = "timestep";
      o->group = N_("Misc. Options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Auto Timestep");
      o->longDesc = N_("Rotation Timestep on Automatic Rotation.");
      o->type = CompOptionTypeFloat;
      o->value.f = ROTATE_TIMESTEP_DEFAULT;
      o->rest.f.min = ROTATE_TIMESTEP_MIN;
      o->rest.f.max = ROTATE_TIMESTEP_MAX;
      o->rest.f.precision = ROTATE_TIMESTEP_PRECISION;

      o = &rs->opt[ROTATE_SCREEN_OPTION_MANTIMESTEP];
      o->advanced = False;
      o->name = "mantimestep";
      o->group = N_("Misc. Options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Manual Timestep");
      o->longDesc = N_("Rotation Timestep on Manual Rotation.");
      o->type = CompOptionTypeFloat;
      o->value.f = ROTATE_MANTIMESTEP_DEFAULT;
      o->rest.f.min = ROTATE_MANTIMESTEP_MIN;
      o->rest.f.max = ROTATE_MANTIMESTEP_MAX;
      o->rest.f.precision = ROTATE_MANTIMESTEP_PRECISION;

      o = &rs->opt[ROTATE_SCREEN_OPTION_ZOOM];
      o->advanced = False;
      o->name = "zoom";
      o->group = N_("Behaviour");
      o->subGroup = N_("General");
      o->displayHints = "";
      o->shortDesc = N_("Zoom");
      o->longDesc =
                  N_("Distance desktop should be Zoomed out while Rotating.");
      o->type = CompOptionTypeFloat;
      o->value.f = ROTATE_ZOOM_DEFAULT;
      o->rest.f.min = ROTATE_ZOOM_MIN;
      o->rest.f.max = ROTATE_ZOOM_MAX;
      o->rest.f.precision = ROTATE_ZOOM_PRECISION;

      o = &rs->opt[ROTATE_SCREEN_OPTION_ZOOM_BEFORE_ROTATE];
      o->advanced = False;
      o->name = "zoom_before_rotate";
      o->group = N_("Behaviour");
      o->subGroup = N_("General");
      o->displayHints = "";
      o->shortDesc = N_("Zoom Before Rotate");
      o->longDesc = N_("Zoom out before doing Rotation.");
      o->type = CompOptionTypeBool;
      o->value.b = ROTATE_ZOOM_BEFORE_ROTATE_DEFAULT;

      o = &rs->opt[ROTATE_SCREEN_OPTION_ZOOM_ONLY_ON_INITIATE];
      o->advanced = False;
      o->name = "zoom_initiate_only";
      o->group = N_("Behaviour");
      o->subGroup = N_("General");
      o->displayHints = "";
      o->shortDesc = N_("Zoom Only on Initiate");
      o->longDesc =
                  N_
                  ("Zoom out only when the 'Initiate' key/mouse combo is pressed.");
      o->type = CompOptionTypeBool;
      o->value.b = FALSE;

      o = &rs->opt[ROTATE_SCREEN_OPTION_WHEEL_ON_EDGES];
      o->advanced = False;
      o->name = "wheel_on_edges";
      o->group = N_("Behaviour");
      o->subGroup = N_("General");
      o->displayHints = "";
      o->shortDesc = N_("Rotate With Wheel Near Edges");
      o->longDesc = N_("Enable Rotate through Mouse Wheel near screen Edges.");
      o->type = CompOptionTypeBool;
      o->value.b = ROTATE_WHEEL_ON_EDGES_DEFAULT;

      o = &rs->opt[ROTATE_SCREEN_OPTION_WHEELMAXDIST];
      o->advanced = False;
      o->name = "wheel_max_dist";
      o->group = N_("Misc. Options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Max Distance From Edge to Rotate");
      o->longDesc =
                  N_
                  ("Maximum cursor Distance from Edges to initiate Rotate with wheel.");
      o->type = CompOptionTypeInt;
      o->value.i = ROTATE_WHEELMAXDIST_DEFAULT;
      o->rest.i.min = ROTATE_WHEELMAXDIST_MIN;
      o->rest.i.max = ROTATE_WHEELMAXDIST_MAX;

}

static CompOption *rotateGetScreenOptions(CompScreen * screen, int *count)
{
      if (screen)
      {
            ROTATE_SCREEN(screen);

            *count = NUM_OPTIONS(rs);
            return rs->opt;
      }
      else
      {
            RotateScreen *rs = malloc(sizeof(RotateScreen));

            rotateScreenInitOptions(rs);
            *count = NUM_OPTIONS(rs);
            return rs->opt;
      }
}


static int adjustVelocity(CompScreen * s, RotateScreen * rs, int size)
{
      float xrot, yrot, adjust, amount;

      if (rs->moving)
      {
            xrot = rs->moveTo + (rs->xrot + rs->baseXrot);
      }
      else
      {
            xrot = rs->xrot;
            if (rs->xrot < -180.0f / size)
                  xrot = 360.0f / size + rs->xrot;
            else if (rs->xrot > 180.0f / size)
                  xrot = rs->xrot - 360.0f / size;
            IPCS_SetBool(IPCS_OBJECT(s), rs->snapTopBottomAtom, TRUE);
      }

      adjust = -xrot * 0.05f *
                  rs->opt[ROTATE_SCREEN_OPTION_ACCELERATION].value.f;
      amount = fabs(xrot);
      if (amount < 10.0f)
            amount = 10.0f;
      else if (amount > 30.0f)
            amount = 30.0f;

      if (rs->slow)
            adjust *= 0.05f;

      rs->xVelocity = (amount * rs->xVelocity + adjust) / (amount + 2.0f);

      if (rs->movingVert)
      {
            yrot = rs->moveToY + (rs->yrot + rs->baseYrot);
      }
      else
      {
            if (rs->snapTop && s->hsize > 2 && rs->yrot > 50.0f)
            {
                  yrot = -(90.f - rs->yrot);
            }
            else if (rs->snapBottom && s->hsize > 2 && rs->yrot < -50.0f)
            {
                  yrot = (90.0f + rs->yrot);
            }
            else
            {
                  yrot = rs->yrot;
            }
      }

      adjust = -yrot * 0.05f *
                  rs->opt[ROTATE_SCREEN_OPTION_ACCELERATION].value.f;
      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 rotateReleaseMoveWindow(CompScreen * s)
{
      CompWindow *w;

      ROTATE_SCREEN(s);

      w = findWindowAtScreen(s, rs->moveWindow);
      if (w)
            syncWindowPosition(w);

      rs->moveWindow = None;
}

static void rotatePreparePaintScreen(CompScreen * s, int msSinceLastPaint)
{
      ROTATE_SCREEN(s);

      Bool performZooming = FALSE;

      if (rs->zooming && (!otherScreenGrabExist(s, "rotate", 0) ||
                                    (rs->zoomTranslate != 0.0f
                                     && rs->zoomTranslate != rs->zoom)))
            performZooming = TRUE;

      if (rs->grabIndex || rs->moving || rs->movingVert)
      {
            int steps, stepsCount;
            float amount, chunk;

            amount = msSinceLastPaint * 0.05f *
                        rs->opt[ROTATE_SCREEN_OPTION_SPEED].value.f;
            steps = stepsCount =
                        amount / (0.5f *
                                      (rs->grabbed ? rs->
                                       opt[ROTATE_SCREEN_OPTION_MANTIMESTEP].value.
                                       f : rs->opt[ROTATE_SCREEN_OPTION_TIMESTEP].value.
                                       f));

            if (!steps)
                  steps = stepsCount = 1;
            chunk = amount / (float)steps;

            if (performZooming &&
                  rs->opt[ROTATE_SCREEN_OPTION_ZOOM_BEFORE_ROTATE].value.
                  b && rs->rotating)
            {
                  steps = stepsCount;

                  while (steps--)
                  {
                        float dt, adjust, tamount;

                        dt = rs->zoom - rs->zoomTranslate;

                        adjust = dt * 0.15f;
                        tamount = fabs(dt) * 1.5f;
                        if (tamount < 0.2f)
                              tamount = 0.2f;
                        else if (tamount > 2.0f)
                              tamount = 2.0f;

                        rs->zoomVelocity =
                                    (tamount * rs->zoomVelocity + adjust) / (tamount +
                                                                                                 1.0f);

                        if (fabs(dt) < 0.1f && fabs(rs->zoomVelocity) < 0.0005f)
                        {
                              rs->zoomTranslate = rs->zoom;
                              break;
                        }
                        rs->zoomTranslate += rs->zoomVelocity * chunk;
                  }

                  if (rs->zoomTranslate != rs->zoom)
                  {
                        UNWRAP(rs, s, preparePaintScreen);
                        (*s->preparePaintScreen) (s, msSinceLastPaint);
                        WRAP(rs, s, preparePaintScreen, rotatePreparePaintScreen);
                        return;
                  }
            }

            steps = stepsCount;
            while (steps--)
            {
                  rs->xrot += rs->xVelocity * chunk;
                  rs->yrot += rs->yVelocity * chunk;

                  if (rs->xrot > 360.0f / s->hsize)
                  {
                        rs->baseXrot += 360.0f / s->hsize;
                        rs->xrot -= 360.0f / s->hsize;
                  }
                  else if (rs->xrot < 0.0f)
                  {
                        rs->baseXrot -= 360.0f / s->hsize;
                        rs->xrot += 360.0f / s->hsize;
                  }

                  if (rs->yrot > 100.0f)
                  {
                        rs->yVelocity = 0.0f;
                        rs->yrot = 100.0f;
                  }
                  else if (rs->yrot < -100.0f)
                  {
                        rs->yVelocity = 0.0f;
                        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(s, rs, s->hsize))
                  {
                        rs->xVelocity = 0.0f;
                        rs->yVelocity = 0.0f;

                        damageScreen(s);

                        if ((fabs(rs->yrot) < 0.1f))
                              //&& !screenGrabExist(s, "scale", 0))
                        {
                              float xrot;
                              int tx;

                              xrot = rs->baseXrot + rs->xrot;
                              if (xrot < 0.0f)
                                    tx = (s->hsize * xrot / 360.0f) - 0.5f;
                              else
                                    tx = (s->hsize * xrot / 360.0f) + 0.5f;

                              if (s->hsize == 4)
                              {
                                    float previousRotation = IPCS_GetFloat(IPCS_OBJECT(s),
                                                                                             rs->
                                                                                             previousRotationAtom);
                                    IPCS_SetFloat(IPCS_OBJECT(s),
                                                        rs->previousRotationAtom,
                                                        previousRotation + tx);
                              }

                              compDisplayClearRequestFlagForPlugin
                                          (s->display, "rotate", "ENABLE_3D");

                              moveScreenViewport(s, tx, 0, TRUE);

                              rs->xrot = 0.0f;
                              rs->yrot = 0.0f;
                              rs->baseXrot = rs->moveTo = 0.0f;
                              rs->baseYrot = rs->moveToY = 0.0f;

                              rs->moving = FALSE;
                              rs->movingVert = FALSE;

                              if (rs->grabIndex)
                              {
                                    removeScreenGrab(s, rs->grabIndex, &rs->savedPointer);
                                    rs->grabIndex = 0;
                              }

                              if (rs->moveWindow)
                              {
                                    CompWindow *w;

                                    w = findWindowAtScreen(s, rs->moveWindow);
                                    if (w)
                                    {
                                          moveWindow(w,
                                                         rs->
                                                         moveWindowX
                                                         - w->attrib.x, 0, TRUE, TRUE);
                                          syncWindowPosition(w);
                                    }
                              }
                              else
                                    focusDefaultWindow(s->display);

                              rs->moveWindow = 0;
                        }
                        break;
                  }
            }

            if (rs->moveWindow)
            {
                  CompWindow *w;

                  w = findWindowAtScreen(s, rs->moveWindow);
                  if (w)
                  {
                        float xrot = (s->hsize * (rs->baseXrot + rs->xrot)) / 360.0f;

                        moveWindowToViewportPosition(w,
                                                                   rs->
                                                                   moveWindowX -
                                                                   xrot * s->width, FALSE);
                  }
            }
      }

      if (fabs(rs->xrot) < 0.01f && fabs(rs->yrot) < 0.01f && !rs->grabbed)
            rs->rotating = FALSE;
      else
            rs->rotating = TRUE;

      if (performZooming
            && !rs->opt[ROTATE_SCREEN_OPTION_ZOOM_BEFORE_ROTATE].value.b
            && (rs->rotating || rs->zoomTranslate != 0.0f)
            && !(rs->opt[ROTATE_SCREEN_OPTION_ZOOM_ONLY_ON_INITIATE].value.
                   b && !(rs->grabbed || rs->zoomTranslate != 0.0f)))
      {

            int steps, stepsCount;
            float amount, chunk;

            amount = msSinceLastPaint * 0.05f *
                        rs->opt[ROTATE_SCREEN_OPTION_SPEED].value.f;
            steps = stepsCount =
                        amount / (0.5f *
                                      rs->opt[ROTATE_SCREEN_OPTION_TIMESTEP].value.f);
            if (!steps)
                  steps = stepsCount = 1;
            chunk = amount / (float)steps;
            Bool zoomOut = FALSE;

            if (rs->moving
                  && fabs(rs->xrot + rs->baseXrot + rs->moveTo) >
                  (360.0 / (s->hsize * 2.0)))
            {
                  zoomOut = TRUE;
            }

            if (rs->movingVert
                  && fabs(rs->yrot + rs->baseYrot + rs->moveToY) > 45.0)
            {
                  zoomOut = TRUE;
            }

            if (rs->grabbed)
                  zoomOut = TRUE;

            while (steps--)
            {
                  float dt, adjust, tamount;

                  if (rs->rotating && zoomOut)
                        dt = rs->zoom - rs->zoomTranslate;
                  else
                        dt = 0.0f - rs->zoomTranslate;

                  adjust = dt * 0.15f;
                  tamount = fabs(dt) * 1.5f;
                  if (tamount < 0.2f)
                        tamount = 0.2f;
                  else if (tamount > 2.0f)
                        tamount = 2.0f;

                  rs->zoomVelocity =
                              (tamount * rs->zoomVelocity + adjust) / (tamount + 1.0f);

                  if (fabs(dt) < 0.1f && fabs(rs->zoomVelocity) < 0.0005f)
                  {
                        if (rs->rotating && zoomOut)
                              rs->zoomTranslate = rs->zoom;
                        else
                              rs->zoomTranslate = 0.0f;
                        break;
                  }
                  rs->zoomTranslate += rs->zoomVelocity * chunk;
            }
      }

      if (performZooming
            && rs->opt[ROTATE_SCREEN_OPTION_ZOOM_BEFORE_ROTATE].value.b
            && !rs->rotating && rs->zoomTranslate != 0.0f && rs->yrot == 0.0f)
      {
            int steps, stepsCount;
            float amount, chunk;

            amount = msSinceLastPaint * 0.05f *
                        rs->opt[ROTATE_SCREEN_OPTION_SPEED].value.f;
            steps = stepsCount =
                        amount / (0.5f *
                                      rs->opt[ROTATE_SCREEN_OPTION_TIMESTEP].value.f);
            if (!steps)
                  steps = stepsCount = 1;
            chunk = amount / (float)steps;

            while (steps--)
            {
                  float dt, adjust, tamount;

                  dt = 0.0f - rs->zoomTranslate;

                  adjust = dt * 0.15f;
                  tamount = fabs(dt) * 1.5f;
                  if (tamount < 0.2f)
                        tamount = 0.2f;
                  else if (tamount > 2.0f)
                        tamount = 2.0f;

                  rs->zoomVelocity =
                              (tamount * rs->zoomVelocity + adjust) / (tamount + 1.0f);

                  if (fabs(dt) < 0.1f && fabs(rs->zoomVelocity) < 0.0005f)
                  {
                        rs->zoomTranslate = 0.0f;
                        break;
                  }
                  rs->zoomTranslate += rs->zoomVelocity * chunk;
            }
            if (rs->zoomTranslate != 0.0f)
            {
                  UNWRAP(rs, s, preparePaintScreen);
                  (*s->preparePaintScreen) (s, msSinceLastPaint);
                  WRAP(rs, s, preparePaintScreen, rotatePreparePaintScreen);
                  return;
            }
      }

      UNWRAP(rs, s, preparePaintScreen);
      (*s->preparePaintScreen) (s, msSinceLastPaint);
      WRAP(rs, s, preparePaintScreen, rotatePreparePaintScreen);
}

static void rotateDonePaintScreen(CompScreen * s)
{
      ROTATE_SCREEN(s);

      if (rs->grabIndex || rs->moving || rs->movingVert)
      {
            if ((!rs->grabbed && !rs->snapTop && !rs->snapBottom)
                  || rs->xVelocity || rs->yVelocity || rs->zooming)
                  damageScreen(s);
      }
      else if (rs->zooming && rs->zoomTranslate != 0.0f)
            damageScreen(s);

      UNWRAP(rs, s, donePaintScreen);
      (*s->donePaintScreen) (s);
      WRAP(rs, s, donePaintScreen, rotateDonePaintScreen);
}

static Bool
rotatePaintScreen(CompScreen * s,
                          const ScreenPaintAttrib * sAttrib,
                          Region region, int output, unsigned int mask)
{
      Bool status;

      ROTATE_SCREEN(s);

      if (rs->grabIndex || rs->moving || rs->movingVert)
      {
            ScreenPaintAttrib sa = *sAttrib;

            if (rs->zooming)
                  sa.zCamera -= rs->zoomTranslate;

            sa.xRotate += rs->baseXrot + rs->xrot;
            sa.vRotate += rs->baseYrot + rs->yrot;

            mask &= ~PAINT_SCREEN_REGION_MASK;
            mask |= PAINT_SCREEN_TRANSFORMED_MASK;

            UNWRAP(rs, s, paintScreen);
            status = (*s->paintScreen) (s, &sa, region, output, mask);
            WRAP(rs, s, paintScreen, rotatePaintScreen);
      }
      else if (rs->zooming && rs->zoomTranslate != 0.0f)
      {
            ScreenPaintAttrib sa = *sAttrib;

            sa.zCamera -= rs->zoomTranslate;
            mask &= ~PAINT_SCREEN_REGION_MASK;
            mask |= PAINT_SCREEN_TRANSFORMED_MASK;

            UNWRAP(rs, s, paintScreen);
            status = (*s->paintScreen) (s, &sa, region, output, mask);
            WRAP(rs, s, paintScreen, rotatePaintScreen);
      }
      else
      {
            UNWRAP(rs, s, paintScreen);
            status = (*s->paintScreen) (s, sAttrib, region, output, mask);
            WRAP(rs, s, paintScreen, rotatePaintScreen);
      }

      return status;
}

static Bool
rotateInitiate(CompDisplay * d,
                     CompAction * action,
                     CompActionState state, CompOption * option, int nOption)
{
      CompScreen *s;
      Window xid;

      xid = getIntOptionNamed(option, nOption, "root", 0);

      s = findScreenAtDisplay(d, xid);
      if (s)
      {
            ROTATE_SCREEN(s);
            IPCS_SetBool(IPCS_OBJECT(s), rs->snapTopBottomAtom, FALSE);

            if (s->hsize < 2)
                  return FALSE;

            if (rs->rotateHandle && rs->grabWindow)
            {
                  if (otherScreenGrabExist(s, "rotate", "move", 0))
                        return FALSE;
            }
            else
            {
                  if (otherScreenGrabExist(s, "rotate", "switcher", "cube", 0))
                        return FALSE;
            }

            rs->moving = FALSE;
            rs->slow = FALSE;
            rs->movingVert = FALSE;
            rs->moveTo = 0.0f;
            rs->moveToY = 0.0f;

            compDisplaySetRequestFlagForPlugin(s->display, "rotate", "ENABLE_3D");

            rs->rotating = FALSE;
            if ((state & CompActionStateInitButton))
            {
                  IPCS_SetBool(IPCS_OBJECT(s), rs->manualAtom, TRUE);
            }
            else
            {
                  IPCS_SetBool(IPCS_OBJECT(s), rs->manualAtom, FALSE);
            }
            if (!rs->grabIndex)
            {
                  rs->grabIndex = pushScreenGrab(s, s->invisibleCursor, "rotate");
                  if (rs->grabIndex)
                  {
                        int x, y;

                        x = getIntOptionNamed(option, nOption, "x", 0);
                        y = getIntOptionNamed(option, nOption, "y", 0);

                        rs->savedPointer.x = x;
                        rs->savedPointer.y = y;
                  }
            }

            if (rs->grabIndex)
            {
                  rs->moveTo = 0.0f;
                  rs->moveToY = 0.0f;

                  rs->grabbed = TRUE;
                  rs->snapTop = rs->opt[ROTATE_SCREEN_OPTION_SNAP_TOP].value.b;
                  rs->snapBottom =
                              rs->opt[ROTATE_SCREEN_OPTION_SNAP_BOTTOM].value.b;

                  if (state & CompActionStateInitButton)
                        action->state |= CompActionStateTermButton;

                  if (state & CompActionStateInitKey)
                        action->state |= CompActionStateTermKey;
            }
      }

      return TRUE;
}

static Bool
rotateInitiateDesktop(CompDisplay * d,
                                CompAction * action,
                                CompActionState state, CompOption * option, int nOption)
{
      CompScreen *s = findScreenAtDisplay(d,
                                                            getIntOptionNamed(option, nOption,
                                                                                      "root", 0));

      if (s)
      {
            int x, y;

            x = getIntOptionNamed(option, nOption, "x", 0);
            y = getIntOptionNamed(option, nOption, "y", 0);

            if (pointerOnlyOnDesktop(s, x, y) || screenGrabExist(s, "rotate", 0))
                  return rotateInitiate(d, action, state, option, nOption);
      }
      return FALSE;
}


static Bool
rotateTerminate(CompDisplay * d,
                        CompAction * action,
                        CompActionState state, CompOption * option, int nOption)
{
      CompScreen *s;
      Window xid;

      xid = getIntOptionNamed(option, nOption, "root", 0);
      for (s = d->screens; s; s = s->next)
      {
            ROTATE_SCREEN(s);

            if (xid && s->root != xid)
                  continue;

            rs->rotating = FALSE;

            if (rs->grabIndex)
            {
                  if (!xid)
                  {
                        rs->snapTop = FALSE;
                        rs->snapBottom = FALSE;
                  }

                  rs->grabbed = FALSE;
                  damageScreen(s);
            }
      }

      action->state &= ~(CompActionStateTermButton | CompActionStateTermKey);

      return FALSE;
}

static Bool
rotate(CompDisplay * d,
         CompAction * action,
         CompActionState state, CompOption * option, int nOption)
{
      CompScreen *s;
      Window xid;

      xid = getIntOptionNamed(option, nOption, "root", 0);

      s = findScreenAtDisplay(d, xid);
      if (s)
      {
            int direction;

            ROTATE_SCREEN(s);

            if (s->hsize < 2)
                  return FALSE;

            if (otherScreenGrabExist
                  (s, "rotate", "move", "switcher", "cube", "scale", "group-drag",
                   0))
                  return FALSE;

            /* FIXME: this is sort of a hack - we check if
               the state of scale is "waiting for user
               we definitely need a better communication 
               mechanism here... */

            int *scaleState = (int *)IPCS_GetVPtrND(IPCS_OBJECT(s),
                                                                        "SCALE_STATE_INT_PTR", NULL);

            if (scaleState && (*scaleState == 2))
                  return FALSE;

            direction = getIntOptionNamed(option, nOption, "direction", 0);
            if (!direction)
                  return FALSE;

            if (rs->moveWindow)
                  rotateReleaseMoveWindow(s);

            /* we allow the grab to fail here so that we can rotate on
               drag-and-drop */
            if (!rs->grabIndex)
            {
                  CompOption o[3];

                  o[0].type = CompOptionTypeInt;
                  o[0].name = "x";
                  o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

                  o[1].type = CompOptionTypeInt;
                  o[1].name = "y";
                  o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

                  o[2].type = CompOptionTypeInt;
                  o[2].name = "root";
                  o[2].value.i = s->root;

                  rotateInitiate(d, NULL, 0, o, 3);
            }

            rs->moving = TRUE;
            rs->moveTo += (360.0f / s->hsize) * direction;
            rs->grabbed = FALSE;

            damageScreen(s);
      }

      return FALSE;
}

static Bool
rotateVert(CompDisplay * d,
               CompAction * action,
               CompActionState state, CompOption * option, int nOption)
{
      CompScreen *s;
      Window xid;

      xid = getIntOptionNamed(option, nOption, "root", 0);

      s = findScreenAtDisplay(d, xid);
      if (s && s->hsize > 2)
      {
            int direction;

            ROTATE_SCREEN(s);

            if (otherScreenGrabExist(s, "rotate", "move", "switcher", "cube", 0))
                  return FALSE;

            direction = getIntOptionNamed(option, nOption, "direction", 0);
            if (!direction)
                  return FALSE;

            if (rs->moveWindow)
                  rotateReleaseMoveWindow(s);

            /* we allow the grab to fail here so that we can rotate on
               drag-and-drop */
            if (!rs->grabIndex)
            {
                  CompOption o[3];

                  o[0].type = CompOptionTypeInt;
                  o[0].name = "x";
                  o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

                  o[1].type = CompOptionTypeInt;
                  o[1].name = "y";
                  o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

                  o[2].type = CompOptionTypeInt;
                  o[2].name = "root";
                  o[2].value.i = s->root;

                  rotateInitiate(d, NULL, 0, o, 3);
            }

            if (fabs(rs->moveToY) == 90.0f
                  && (rs->moveToY + -90.0f * direction) != 0.0f)
            {
                  direction = -direction;
                  rs->moving = TRUE;
                  rs->moveTo += 180.0f * direction;
            }

            rs->movingVert = TRUE;
            rs->moveToY += -90.0f * direction;
            rs->grabbed = FALSE;

            damageScreen(s);
      }

      return FALSE;
}

static Bool
rotateWithWindow(CompDisplay * d,
                         CompAction * action,
                         CompActionState state, CompOption * option, int nOption)
{
      CompScreen *s;
      Window xid;

      xid = getIntOptionNamed(option, nOption, "root", 0);

      s = findScreenAtDisplay(d, xid);
      if (s)
      {
            int direction;

            ROTATE_SCREEN(s);

            if (s->hsize < 2)
                  return FALSE;

            direction = getIntOptionNamed(option, nOption, "direction", 0);
            if (!direction)
                  return FALSE;

            xid = getIntOptionNamed(option, nOption, "window", 0);

            if (rs->moveWindow != xid)
            {
                  CompWindow *w;

                  rotateReleaseMoveWindow(s);

                  w = findWindowAtScreen(s, xid);
                  if (w)
                  {
                        if (!
                              (w->
                               type & (CompWindowTypeDesktopMask |
                                           CompWindowTypeDockMask)))
                        {
                              if (!(w->state & CompWindowStateStickyMask))
                              {
                                    rs->moveWindow = w->id;
                                    rs->moveWindowX = w->attrib.x;
                                    raiseWindow(w);
                              }
                        }
                  }
            }

            if (!rs->grabIndex)
            {
                  CompOption o[3];

                  o[0].type = CompOptionTypeInt;
                  o[0].name = "x";
                  o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

                  o[1].type = CompOptionTypeInt;
                  o[1].name = "y";
                  o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

                  o[2].type = CompOptionTypeInt;
                  o[2].name = "root";
                  o[2].value.i = s->root;

                  rotateInitiate(d, NULL, 0, o, 3);
            }

            if (rs->grabIndex)
            {
                  rs->moving = TRUE;
                  rs->moveTo += (360.0f / s->hsize) * direction;
                  rs->grabbed = FALSE;

                  damageScreen(s);
            }
      }

      return TRUE;
}

static Bool
pointerNearScreenEdge(CompScreen * s, int x, int y, int maxDistance)
{
      if (((x - s->x) >= -maxDistance && (x - s->x) <= maxDistance)
            || ((s->x + s->width - x) >= -maxDistance
                  && (s->x + s->width - x) <= maxDistance)
            || ((y - s->y) >= -maxDistance && (y - s->y) <= maxDistance)
            || ((s->y + s->height - y) >= -maxDistance
                  && (s->y + s->height - y) <= maxDistance))
            return TRUE;
      return FALSE;
}

static Bool
rotateWheel(CompDisplay * d, int direction, CompOption * option, int nOption)
{
      ROTATE_DISPLAY(d);
      CompScreen *s = findScreenAtDisplay(d,
                                                            getIntOptionNamed(option,
                                                                                      nOption,
                                                                                      "root", 0));

      if (s)
      {
            ROTATE_SCREEN(s);
            int x, y;
            unsigned int *wheelings;

            if (direction == -1)
            {
                  wheelings = &rd->rightWheelings;
                  rd->leftWheelings = 0;
            }
            else
            {
                  wheelings = &rd->leftWheelings;
                  rd->rightWheelings = 0;
            }

            x = getIntOptionNamed(option, nOption, "x", 0);
            y = getIntOptionNamed(option, nOption, "y", 0);

            if (pointerOnlyOnDesktop(s, x, y)
                  || (rs->opt[ROTATE_SCREEN_OPTION_WHEEL_ON_EDGES].value.
                        b
                        && pointerNearScreenEdge(s, x, y,
                                                             rs->
                                                             opt
                                                             [ROTATE_SCREEN_OPTION_WHEELMAXDIST].
                                                             value.i)))
            {
                  if (++(*wheelings) ==
                        rd->opt[ROTATE_DISPLAY_OPTION_WHEELINGS].value.i)
                  {
                        *wheelings = 0;

                        CompOption o[4];

                        o[0].type = CompOptionTypeInt;
                        o[0].name = "x";
                        o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

                        o[1].type = CompOptionTypeInt;
                        o[1].name = "y";
                        o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

                        o[2].type = CompOptionTypeInt;
                        o[2].name = "root";
                        o[2].value.i = getIntOptionNamed(option, nOption, "root", 0);

                        o[3].type = CompOptionTypeInt;
                        o[3].name = "direction";
                        o[3].value.i = direction;

                        rotate(d, NULL, 0, o, 4);
                  }
            }
            else
                  *wheelings = 0;
      }

      return FALSE;
}

static Bool
rotateRightWheel(CompDisplay * d,
                         CompAction * action,
                         CompActionState state, CompOption * option, int nOption)
{
      return rotateWheel(d, 1, option, nOption);
}

static Bool
rotateLeftWheel(CompDisplay * d,
                        CompAction * action,
                        CompActionState state, CompOption * option, int nOption)
{
      return rotateWheel(d, -1, option, nOption);
}

static Bool
rotateReal(CompDisplay * d, Bool vert, int direction,
               CompOption * option, int nOption)
{
      CompOption o[4];

      o[0].type = CompOptionTypeInt;
      o[0].name = "x";
      o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

      o[1].type = CompOptionTypeInt;
      o[1].name = "y";
      o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

      o[2].type = CompOptionTypeInt;
      o[2].name = "root";
      o[2].value.i = getIntOptionNamed(option, nOption, "root", 0);

      o[3].type = CompOptionTypeInt;
      o[3].name = "direction";
      o[3].value.i = direction;

      if (vert)
            rotateVert(d, NULL, 0, o, 4);
      else
            rotate(d, NULL, 0, o, 4);

      return FALSE;
}

static Bool
rotateLeft(CompDisplay * d,
               CompAction * action,
               CompActionState state, CompOption * option, int nOption)
{
      return rotateReal(d, FALSE, -1, option, nOption);
}

static Bool
rotateRight(CompDisplay * d,
                  CompAction * action,
                  CompActionState state, CompOption * option, int nOption)
{
      return rotateReal(d, FALSE, 1, option, nOption);
}

static Bool
rotateTop(CompDisplay * d,
              CompAction * action,
              CompActionState state, CompOption * option, int nOption)
{
      return rotateReal(d, TRUE, 1, option, nOption);
}

static Bool
rotateDown(CompDisplay * d,
               CompAction * action,
               CompActionState state, CompOption * option, int nOption)
{
      return rotateReal(d, TRUE, -1, option, nOption);
}

static Bool
rotateWithWindowReal(CompDisplay * d, int direction, CompOption * option,
                               int nOption)
{
      CompOption o[5];

      o[0].type = CompOptionTypeInt;
      o[0].name = "x";
      o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

      o[1].type = CompOptionTypeInt;
      o[1].name = "y";
      o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

      o[2].type = CompOptionTypeInt;
      o[2].name = "root";
      o[2].value.i = getIntOptionNamed(option, nOption, "root", 0);

      o[3].type = CompOptionTypeInt;
      o[3].name = "direction";
      o[3].value.i = direction;

      o[4].type = CompOptionTypeInt;
      o[4].name = "window";
      o[4].value.i = getIntOptionNamed(option, nOption, "window", 0);

      rotateWithWindow(d, NULL, 0, o, 5);

      return FALSE;
}

static Bool
rotateLeftWithWindow(CompDisplay * d,
                               CompAction * action,
                               CompActionState state, CompOption * option, int nOption)
{
      return rotateWithWindowReal(d, -1, option, nOption);
}

static Bool
rotateRightWithWindow(CompDisplay * d,
                                CompAction * action,
                                CompActionState state, CompOption * option, int nOption)
{
      return rotateWithWindowReal(d, 1, option, nOption);
}

static Bool rotateFlip(CompScreen * s, int direction)
{
      int warpX;
      CompOption o[4];

      ROTATE_SCREEN(s);

      rs->moveTo = 0.0f;
      rs->slow = FALSE;

      if (otherScreenGrabExist(s, "rotate", "move", "group-drag", 0))
            return FALSE;

      if (direction == 1)
      {
            //rotation to right
            warpX = s->display->pointerX - s->width;
            warpPointer(s->display, 10 - s->width, 0);
            s->display->lastPointerX = warpX;
      }
      else
      {
            warpX = s->display->pointerX + s->width;
            warpPointer(s->display, s->width - 10, 0);
            s->display->lastPointerX = warpX;
      }

      o[0].type = CompOptionTypeInt;
      o[0].name = "x";
      o[0].value.i = 0;

      o[1].type = CompOptionTypeInt;
      o[1].name = "y";
      o[1].value.i = s->display->pointerY;

      o[2].type = CompOptionTypeInt;
      o[2].name = "root";
      o[2].value.i = s->root;

      o[3].type = CompOptionTypeInt;
      o[3].name = "direction";
      o[3].value.i = direction;

      rotate(s->display, NULL, 0, o, 4);

      XWarpPointer(s->display->display, None, None, 0, 0, 0, 0, direction, 0);

      if (direction == 1)
            rs->savedPointer.x = s->display->lastPointerX + 9;
      else
            rs->savedPointer.x = s->display->lastPointerX - 9;

      rs->rotateHandle = 0;

      return FALSE;
}

static Bool rotateFlipLeft(void *closure)
{
      CompScreen *s = closure;

      return rotateFlip(s, -1);
}

static Bool rotateFlipRight(void *closure)
{
      CompScreen *s = closure;

      return rotateFlip(s, 1);
}

static void
rotateEdgeFlip(CompScreen * s,
                     int edge,
                     CompAction * action,
                     CompActionState state, CompOption * option, int nOption)
{
      CompOption o[4];
      int direction;

      ROTATE_DISPLAY(s->display);
      ROTATE_SCREEN(s);

      if (s->hsize < 2)
            return;

      if (otherScreenGrabExist(s, "rotate", "move", "group-drag", 0))
            return;

      if (state & CompActionStateInitEdgeDnd)
      {
            if (!rd->opt[ROTATE_DISPLAY_OPTION_EDGEFLIP_DND].value.b)
                  return;

            if (otherScreenGrabExist(s, "rotate", 0))
                  return;
      }
      else if (screenGrabExist(s, "move", 0))
      {
            if (!rd->opt[ROTATE_DISPLAY_OPTION_EDGEFLIP_WINDOW].value.b)
                  return;

            if (!rs->grabWindow)
                  return;

            /* bail out if window is horizontally maximized or fullscreen */
            if (rs->grabWindow->
                  state & (CompWindowStateMaximizedHorzMask |
                               CompWindowStateFullscreenMask))
                  return;
      }
      else if (screenGrabExist(s, "group-drag", 0))
      {
            if (!rd->opt[ROTATE_DISPLAY_OPTION_EDGEFLIP_DND].value.b)
                  return;
      }
      else
      {
            if (!rd->opt[ROTATE_DISPLAY_OPTION_EDGEFLIP_POINTER].value.b)
                  return;
      }

      o[0].type = CompOptionTypeInt;
      o[0].name = "x";
      o[0].value.i = 0;

      o[1].type = CompOptionTypeInt;
      o[1].name = "y";
      o[1].value.i = s->display->pointerY;

      o[2].type = CompOptionTypeInt;
      o[2].name = "root";
      o[2].value.i = s->root;

      o[3].type = CompOptionTypeInt;
      o[3].name = "direction";

      if (edge == SCREEN_EDGE_LEFT)
            direction = -1;
      else
            direction = 1;

      if (rd->opt[ROTATE_DISPLAY_OPTION_FLIPTIME].value.i == 0
            || (rs->moving && !rs->slow))
      {
            int pointerDx, warpX;

            if (edge == SCREEN_EDGE_LEFT)
            {
                  pointerDx = s->display->pointerX - s->display->lastPointerX;
                  warpX = s->display->pointerX + s->width;
                  warpPointer(s->display, s->width - 10, 0);
                  s->display->lastPointerX = warpX - pointerDx;
            }
            else
            {
                  pointerDx = s->display->pointerX - s->display->lastPointerX;
                  warpX = s->display->pointerX - s->width;
                  warpPointer(s->display, 10 - s->width, 0);
                  s->display->lastPointerX = warpX - pointerDx;
            }

            o[3].value.i = direction;
            rotate(s->display, NULL, 0, o, 4);

            XWarpPointer(s->display->display, None, None, 0, 0, 0, 0,
                               direction, 0);
            rs->savedPointer.x = s->display->lastPointerX + (direction * 9);
      }
      else
      {
            if (!rs->rotateHandle)
                  rs->rotateHandle =
                              compAddTimeout(rd->
                                                   opt
                                                   [ROTATE_DISPLAY_OPTION_FLIPTIME].
                                                   value.i,
                                                   (edge ==
                                                      SCREEN_EDGE_LEFT) ?
                                                   rotateFlipLeft : rotateFlipRight, s);

            rs->moving = TRUE;
            rs->moveTo += (direction * 360.0f / s->hsize);
            rs->slow = TRUE;

            if (state & CompActionStateInitEdge)
                  action->state |= CompActionStateTermEdge;

            if (state & CompActionStateInitEdgeDnd)
                  action->state |= CompActionStateTermEdgeDnd;

            damageScreen(s);
      }
}

static Bool
rotateFlipTerminate(CompDisplay * d,
                              CompAction * action,
                              CompActionState state, CompOption * option, int nOption)
{
      CompScreen *s;
      Window xid;

      xid = getIntOptionNamed(option, nOption, "root", 0);

      for (s = d->screens; s; s = s->next)
      {
            ROTATE_SCREEN(s);

            if (xid && s->root != xid)
                  continue;

            if (rs->rotateHandle)
            {
                  compRemoveTimeout(rs->rotateHandle);
                  rs->rotateHandle = 0;

                  if (rs->slow)
                  {
                        rs->moveTo = 0.0f;
                        rs->slow = FALSE;
                  }

                  damageScreen(s);
            }

            action->state &= ~(CompActionStateTermEdge |
                                       CompActionStateTermEdgeDnd);
      }

      return FALSE;
}

static Bool
rotateEdgeFlipLeft(CompDisplay * d,
                           CompAction * action,
                           CompActionState state, CompOption * option, int nOption)
{
      CompScreen *s;
      Window xid;

      xid = getIntOptionNamed(option, nOption, "root", 0);

      s = findScreenAtDisplay(d, xid);
      if (s)
            rotateEdgeFlip(s, SCREEN_EDGE_LEFT, action, state, option, nOption);

      return FALSE;
}

static Bool
rotateEdgeFlipRight(CompDisplay * d,
                              CompAction * action,
                              CompActionState state, CompOption * option, int nOption)
{
      CompScreen *s;
      Window xid;

      xid = getIntOptionNamed(option, nOption, "root", 0);

      s = findScreenAtDisplay(d, xid);
      if (s)
            rotateEdgeFlip(s, SCREEN_EDGE_RIGHT, action, state, option, nOption);

      return FALSE;
}

static int rotateRotationTo(CompScreen * s, int face)
{
      int delta;

      ROTATE_SCREEN(s);

      delta = face - s->x - (rs->moveTo / (360.0f / s->hsize));
      if (delta > s->hsize / 2)
            delta -= s->hsize;
      else if (delta < -(s->hsize / 2))
            delta += s->hsize;

      return delta;
}

static Bool
rotateTo(CompDisplay * d,
             CompAction * action,
             CompActionState state, CompOption * option, int nOption)
{
      CompScreen *s;
      Window xid;

      xid = getIntOptionNamed(option, nOption, "root", 0);

      s = findScreenAtDisplay(d, xid);
      if (s)
      {
            CompOption o[4];
            int face = -1;
            int i = ROTATE_DISPLAY_OPTION_TO_1;

            ROTATE_DISPLAY(s->display);

            while (i <= ROTATE_DISPLAY_OPTION_TO_12)
            {
                  if (action == &rd->opt[i].value.action)
                  {
                        face = i - ROTATE_DISPLAY_OPTION_TO_1;
                        break;
                  }

                  i++;
            }

            if (face < 0)
                  face = getIntOptionNamed(option, nOption, "face", s->x);

            o[0].type = CompOptionTypeInt;
            o[0].name = "x";
            o[0].value.i =
                        getIntOptionNamed(option, nOption, "x", s->display->pointerX);

            o[1].type = CompOptionTypeInt;
            o[1].name = "y";
            o[1].value.i =
                        getIntOptionNamed(option, nOption, "y", s->display->pointerY);

            o[2].type = CompOptionTypeInt;
            o[2].name = "root";
            o[2].value.i = s->root;

            o[3].type = CompOptionTypeInt;
            o[3].name = "direction";
            o[3].value.i = rotateRotationTo(s, face);

            rotate(d, NULL, 0, o, 4);
      }

      return FALSE;
}

static Bool
rotateToWithWindow(CompDisplay * d,
                           CompAction * action,
                           CompActionState state, CompOption * option, int nOption)
{
      CompScreen *s;
      Window xid;

      xid = getIntOptionNamed(option, nOption, "root", 0);

      s = findScreenAtDisplay(d, xid);
      if (s)
      {
            CompOption o[5];
            int face = -1;
            int i = ROTATE_DISPLAY_OPTION_TO_1_WINDOW;

            ROTATE_DISPLAY(s->display);

            while (i <= ROTATE_DISPLAY_OPTION_TO_12_WINDOW)
            {
                  if (action == &rd->opt[i].value.action)
                  {
                        face = i - ROTATE_DISPLAY_OPTION_TO_1_WINDOW;
                        break;
                  }

                  i++;
            }

            if (face < 0)
                  face = getIntOptionNamed(option, nOption, "face", s->x);

            o[0].type = CompOptionTypeInt;
            o[0].name = "x";
            o[0].value.i =
                        getIntOptionNamed(option, nOption, "x", s->display->pointerX);

            o[1].type = CompOptionTypeInt;
            o[1].name = "y";
            o[1].value.i =
                        getIntOptionNamed(option, nOption, "y", s->display->pointerY);

            o[2].type = CompOptionTypeInt;
            o[2].name = "root";
            o[2].value.i = s->root;

            o[3].type = CompOptionTypeInt;
            o[3].name = "direction";
            o[3].value.i = rotateRotationTo(s, face);

            o[4].type = CompOptionTypeInt;
            o[4].name = "window";
            o[4].value.i = getIntOptionNamed(option, nOption, "window", 0);

            rotateWithWindow(d, NULL, 0, o, 5);
      }

      return FALSE;
}

static void rotateHandleEvent(CompDisplay * d, XEvent * event)
{
      CompScreen *s;

      ROTATE_DISPLAY(d);

      switch (event->type)
      {
      case MotionNotify:
            s = findScreenAtDisplay(d, event->xmotion.root);
            if (s)
            {
                  ROTATE_SCREEN(s);

                  if (rs->grabIndex)
                  {
                        if (rs->grabbed)
                        {
                              GLfloat pointerDx, pointerDy;

                              pointerDx = d->pointerX - d->lastPointerX;
                              pointerDy = d->pointerY - d->lastPointerY;

                              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)
                              {
                                    warpPointer(d,
                                                      (s->width /
                                                       2) -
                                                      d->pointerX,
                                                      (s->height / 2) - d->pointerY);
                              }

                              if (rs->
                                    opt[ROTATE_SCREEN_OPTION_POINTER_INVERT_Y].value.b)
                                    pointerDy = -pointerDy;

                              rs->xVelocity +=
                                          pointerDx * rs->pointerSensitivity * rs->invert;
                              rs->yVelocity += pointerDy * rs->pointerSensitivity;

                              damageScreen(s);
                        }
                        else
                        {
                              rs->savedPointer.x += d->pointerX - d->lastPointerX;
                              rs->savedPointer.y += d->pointerY - d->lastPointerY;
                        }
                  }
            }
            break;
      case ClientMessage:
            if (event->xclient.message_type == d->winActiveAtom)
            {
                  CompWindow *w;

                  w = findWindowAtDisplay(d, event->xclient.window);
                  if (w)
                  {
                        int dx;

                        ROTATE_SCREEN(w->screen);

                        s = w->screen;

                        /* window must be placed */
                        if (!w->placed)
                              break;

                        if (w->state & CompWindowStateOffscreenMask)
                              break;

                        if (otherScreenGrabExist
                              (s, "rotate", "switcher", "cube", "scale", 0))
                              break;

                        /* reset movement */
                        rs->moving = FALSE;
                        rs->moveTo = 0.0f;
                        rs->movingVert = FALSE;
                        rs->moveToY = 0.0f;

                        defaultViewportForWindow(w, &dx, NULL);
                        dx -= s->x;
                        if (dx)
                        {
                              Window win;
                              int i, x, y;
                              unsigned int ui;
                              CompOption o[4];

                              XQueryPointer(d->display, s->root,
                                                  &win, &win, &x, &y, &i, &i, &ui);

                              if (dx > (s->hsize + 1) / 2)
                                    dx -= s->hsize;
                              else if (dx < -(s->hsize + 1) / 2)
                                    dx += s->hsize;

                              o[0].type = CompOptionTypeInt;
                              o[0].name = "x";
                              o[0].value.i = x;

                              o[1].type = CompOptionTypeInt;
                              o[1].name = "y";
                              o[1].value.i = y;

                              o[2].type = CompOptionTypeInt;
                              o[2].name = "root";
                              o[2].value.i = s->root;

                              o[3].type = CompOptionTypeInt;
                              o[3].name = "direction";
                              o[3].value.i = dx;

                              rotate(d, NULL, 0, o, 4);
                        }
                  }
            }
            else if (event->xclient.message_type == d->desktopViewportAtom)
            {
                  s = findScreenAtDisplay(d, event->xclient.window);
                  if (s)
                  {
                        int dx;

                        if (otherScreenGrabExist
                              (s, "rotate", "switcher", "cube", "scale", 0))
                              break;

                        dx = event->xclient.data.l[0] / s->width - s->x;
                        if (dx)
                        {
                              Window win;
                              int i, x, y;
                              unsigned int ui;
                              CompOption o[4];

                              XQueryPointer(d->display, s->root,
                                                  &win, &win, &x, &y, &i, &i, &ui);

                              if (dx > (s->hsize + 1) / 2)
                                    dx -= s->hsize;
                              else if (dx < -(s->hsize + 1) / 2)
                                    dx += s->hsize;

                              o[0].type = CompOptionTypeInt;
                              o[0].name = "x";
                              o[0].value.i = x;

                              o[1].type = CompOptionTypeInt;
                              o[1].name = "y";
                              o[1].value.i = y;

                              o[2].type = CompOptionTypeInt;
                              o[2].name = "root";
                              o[2].value.i = s->root;

                              o[3].type = CompOptionTypeInt;
                              o[3].name = "direction";
                              o[3].value.i = dx;

                              rotate(d, NULL, 0, o, 4);
                        }
                  }
            }
      default:
            break;
      }

      UNWRAP(rd, d, handleEvent);
      (*d->handleEvent) (d, event);
      WRAP(rd, d, handleEvent, rotateHandleEvent);
}

static void
rotateWindowGrabNotify(CompWindow * w,
                                 int x, int y, unsigned int state, unsigned int mask)
{
      ROTATE_SCREEN(w->screen);

      if (!rs->grabWindow)
      {
            rs->grabMask = mask;
            rs->grabWindow = w;
      }

      UNWRAP(rs, w->screen, windowGrabNotify);
      (*w->screen->windowGrabNotify) (w, x, y, state, mask);
      WRAP(rs, w->screen, windowGrabNotify, rotateWindowGrabNotify);
}

static void rotateWindowUngrabNotify(CompWindow * w)
{
      ROTATE_SCREEN(w->screen);

      if (w == rs->grabWindow)
      {
            rs->grabMask = 0;
            rs->grabWindow = NULL;
      }

      UNWRAP(rs, w->screen, windowUngrabNotify);
      (*w->screen->windowUngrabNotify) (w);
      WRAP(rs, w->screen, windowUngrabNotify, rotateWindowUngrabNotify);
}

static void rotateUpdateCubeOptions(CompScreen * s)
{
      CompPlugin *p;

      ROTATE_SCREEN(s);

      p = findActivePlugin("cube");
      if (p && p->vTable->getScreenOptions)
      {
            CompOption *options, *option;
            int nOptions;

            options = (*p->vTable->getScreenOptions) (s, &nOptions);
            option = compFindOption(options, nOptions, "in", 0);
            if (option)
                  rs->invert = option->value.b ? -1 : 1;
      }
}

static Bool
rotateSetScreenOptionForPlugin(CompScreen * s,
                                             char *plugin,
                                             char *name, CompOptionValue * value)
{
      Bool status;

      ROTATE_SCREEN(s);

      UNWRAP(rs, s, setScreenOptionForPlugin);
      status = (*s->setScreenOptionForPlugin) (s, plugin, name, value);
      WRAP(rs, s, setScreenOptionForPlugin, rotateSetScreenOptionForPlugin);

      if (status && strcmp(plugin, "cube") == 0 && strcmp(name, "in") == 0)
            rotateUpdateCubeOptions(s);

      return status;
}

static Bool
rotateSetDisplayOption(CompDisplay * display,
                                 char *name, CompOptionValue * value)
{
      CompOption *o;
      int index;

      ROTATE_DISPLAY(display);

      o = compFindOption(rd->opt, NUM_OPTIONS(rd), name, &index);
      if (!o)
            return FALSE;

      switch (index)
      {
      case ROTATE_DISPLAY_OPTION_INITIATE:
      case ROTATE_DISPLAY_OPTION_LEFT:
      case ROTATE_DISPLAY_OPTION_RIGHT:
      case ROTATE_DISPLAY_OPTION_UP:
      case ROTATE_DISPLAY_OPTION_DOWN:
      case ROTATE_DISPLAY_OPTION_TO_1:
      case ROTATE_DISPLAY_OPTION_TO_2:
      case ROTATE_DISPLAY_OPTION_TO_3:
      case ROTATE_DISPLAY_OPTION_TO_4:
      case ROTATE_DISPLAY_OPTION_TO_5:
      case ROTATE_DISPLAY_OPTION_TO_6:
      case ROTATE_DISPLAY_OPTION_TO_7:
      case ROTATE_DISPLAY_OPTION_TO_8:
      case ROTATE_DISPLAY_OPTION_TO_9:
      case ROTATE_DISPLAY_OPTION_TO_10:
      case ROTATE_DISPLAY_OPTION_TO_11:
      case ROTATE_DISPLAY_OPTION_TO_12:
      case ROTATE_DISPLAY_OPTION_LEFT_WINDOW:
      case ROTATE_DISPLAY_OPTION_RIGHT_WINDOW:
      case ROTATE_DISPLAY_OPTION_LEFT_WHEEL:
      case ROTATE_DISPLAY_OPTION_RIGHT_WHEEL:
      case ROTATE_DISPLAY_OPTION_TO_1_WINDOW:
      case ROTATE_DISPLAY_OPTION_TO_2_WINDOW:
      case ROTATE_DISPLAY_OPTION_TO_3_WINDOW:
      case ROTATE_DISPLAY_OPTION_TO_4_WINDOW:
      case ROTATE_DISPLAY_OPTION_TO_5_WINDOW:
      case ROTATE_DISPLAY_OPTION_TO_6_WINDOW:
      case ROTATE_DISPLAY_OPTION_TO_7_WINDOW:
      case ROTATE_DISPLAY_OPTION_TO_8_WINDOW:
      case ROTATE_DISPLAY_OPTION_TO_9_WINDOW:
      case ROTATE_DISPLAY_OPTION_TO_10_WINDOW:
      case ROTATE_DISPLAY_OPTION_TO_11_WINDOW:
      case ROTATE_DISPLAY_OPTION_TO_12_WINDOW:
      case ROTATE_DISPLAY_OPTION_FLIP_LEFT:
      case ROTATE_DISPLAY_OPTION_FLIP_RIGHT:
      case ROTATE_DISPLAY_OPTION_INITIATEDESKTOP:
      case ROTATE_DISPLAY_OPTION_STICKY_INITIATE:
            if (setDisplayAction(display, o, value))
                  return TRUE;
            break;
      case ROTATE_DISPLAY_OPTION_WHEELINGS:
      case ROTATE_DISPLAY_OPTION_FLIPTIME:
            if (compSetIntOption(o, value))
                  return TRUE;
            break;
      case ROTATE_DISPLAY_OPTION_TO:
      case ROTATE_DISPLAY_OPTION_WINDOW:
            if (compSetActionOption(o, value))
                  return TRUE;
            break;
      case ROTATE_DISPLAY_OPTION_EDGEFLIP_POINTER:
      case ROTATE_DISPLAY_OPTION_EDGEFLIP_WINDOW:
      case ROTATE_DISPLAY_OPTION_EDGEFLIP_DND:
            if (compSetBoolOption(o, value))
                  return TRUE;
            break;
      default:
            break;
      }

      return FALSE;
}

static void rotateDisplayInitOptions(RotateDisplay * rd)
{
      CompOption *o;
      char *str;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_INITIATE];
      o->advanced = False;
      o->name = "initiate";
      o->group = N_("Bindings");
      o->subGroup = N_("Initiate");
      o->displayHints = "";
      o->shortDesc = N_("Initiate Rotation");
      o->longDesc = N_("Start Rotation.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateInitiate;
      o->value.action.terminate = rotateTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeButton;
      o->value.action.button.modifiers = ROTATE_INITIATE_MODIFIERS_DEFAULT;
      o->value.action.button.button = ROTATE_INITIATE_BUTTON_DEFAULT;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_STICKY_INITIATE];
      o->advanced = False;
      o->name = "initiate_sticky";
      o->group = N_("Bindings");
      o->subGroup = N_("Initiate");
      o->displayHints = "";
      o->shortDesc = N_("Initiate Sticky");
      o->longDesc =
                  N_
                  ("Start Rotation and don't finish it until specifily terminated by"
                   " the normal Initiate.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateInitiate;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeButton;
      o->value.action.button.modifiers =
                  ROTATE_INITIATE_STICKY_MODIFIERS_DEFAULT;
      o->value.action.button.button = ROTATE_INITIATE_STICKY_BUTTON_DEFAULT;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_WHEELINGS];
      o->advanced = False;
      o->name = "rotate_wheelings";
      o->group = N_("Behaviour");
      o->subGroup = N_("General");
      o->displayHints = "";
      o->shortDesc = N_("Mouse Wheel Scrolls for Rotation");
      o->longDesc = N_("Number of Mouse Wheel Scrolls required for Rotation.");
      o->type = CompOptionTypeInt;
      o->value.i = ROTATE_WHEELINGS_DEFAULT;
      o->rest.i.min = ROTATE_WHEELINGS_MIN;
      o->rest.i.max = ROTATE_WHEELINGS_MAX;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_LEFT_WHEEL];
      o->advanced = False;
      o->name = "rotate_left_wheel";
      o->group = N_("Bindings");
      o->subGroup = N_("Rotate Left");
      o->displayHints = "";
      o->shortDesc = N_("Rotate Left with Mouse Wheel");
      o->longDesc = N_("Rotate Left with Mouse Wheel.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateLeftWheel;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitButton;
      o->value.action.type = CompBindingTypeButton;
      o->value.action.button.modifiers = ROTATE_LEFT_WHEEL_MODIFIERS_DEFAULT;
      o->value.action.button.button = ROTATE_LEFT_WHEEL_DEFAULT;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_RIGHT_WHEEL];
      o->advanced = False;
      o->name = "rotate_right_wheel";
      o->group = N_("Bindings");
      o->subGroup = N_("Rotate Right");
      o->displayHints = "";
      o->shortDesc = N_("Rotate Right with Mouse Wheel");
      o->longDesc = N_("Rotate Right with Mouse Wheel.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateRightWheel;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitButton;
      o->value.action.type = CompBindingTypeButton;
      o->value.action.button.modifiers = ROTATE_RIGHT_WHEEL_MODIFIERS_DEFAULT;
      o->value.action.button.button = ROTATE_RIGHT_WHEEL_DEFAULT;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_LEFT];
      o->advanced = False;
      o->name = "rotate_left";
      o->group = N_("Bindings");
      o->subGroup = N_("Rotate Left");
      o->displayHints = "";
      o->shortDesc = N_("Rotate Left");
      o->longDesc = N_("Rotate Left.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateLeft;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitEdge;
      o->value.action.state |= CompActionStateInitEdgeDnd;
      o->value.action.state |= CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = ROTATE_LEFT_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(ROTATE_LEFT_KEY_DEFAULT);

      o = &rd->opt[ROTATE_DISPLAY_OPTION_RIGHT];
      o->advanced = False;
      o->name = "rotate_right";
      o->group = N_("Bindings");
      o->subGroup = N_("Rotate Right");
      o->displayHints = "";
      o->shortDesc = N_("Rotate Right");
      o->longDesc = N_("Rotate Right.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateRight;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitEdge;
      o->value.action.state |= CompActionStateInitEdgeDnd;
      o->value.action.state |= CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = ROTATE_RIGHT_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(ROTATE_RIGHT_KEY_DEFAULT);

      o = &rd->opt[ROTATE_DISPLAY_OPTION_UP];
      o->advanced = False;
      o->name = "rotate_up";
      o->group = N_("Bindings");
      o->subGroup = N_("Rotate Up");
      o->displayHints = "";
      o->shortDesc = N_("Rotate Up");
      o->longDesc = N_("Rotate Up.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateTop;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitEdge;
      o->value.action.state |= CompActionStateInitEdgeDnd;
      o->value.action.state |= CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = ROTATE_UP_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(ROTATE_UP_KEY_DEFAULT);

      o = &rd->opt[ROTATE_DISPLAY_OPTION_DOWN];
      o->advanced = False;
      o->name = "rotate_down";
      o->group = N_("Bindings");
      o->subGroup = N_("Rotate Down");
      o->displayHints = "";
      o->shortDesc = N_("Rotate Down");
      o->longDesc = N_("Rotate Down.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateDown;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitEdge;
      o->value.action.state |= CompActionStateInitEdgeDnd;
      o->value.action.state |= CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = ROTATE_DOWN_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(ROTATE_DOWN_KEY_DEFAULT);

      o = &rd->opt[ROTATE_DISPLAY_OPTION_LEFT_WINDOW];
      o->advanced = False;
      o->name = "rotate_left_window";
      o->group = N_("Bindings");
      o->subGroup = N_("Rotate Left");
      o->displayHints = "";
      o->shortDesc = N_("Rotate Left with Window");
      o->longDesc = N_("Rotate Left and bring the active Window along.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateLeftWithWindow;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitEdge;
      o->value.action.state |= CompActionStateInitEdgeDnd;
      o->value.action.state |= CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = ROTATE_LEFT_WINDOW_MODIFIERS_DEFAULT;
      o->value.action.key.keysym =
                  XStringToKeysym(ROTATE_LEFT_WINDOW_KEY_DEFAULT);

      o = &rd->opt[ROTATE_DISPLAY_OPTION_RIGHT_WINDOW];
      o->advanced = False;
      o->name = "rotate_right_window";
      o->group = N_("Bindings");
      o->subGroup = N_("Rotate Right");
      o->displayHints = "";
      o->shortDesc = N_("Rotate Right with Window");
      o->longDesc = N_("Rotate Right and bring the active Window along.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateRightWithWindow;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitEdge;
      o->value.action.state |= CompActionStateInitEdgeDnd;
      o->value.action.state |= CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = ROTATE_RIGHT_WINDOW_MODIFIERS_DEFAULT;
      o->value.action.key.keysym =
                  XStringToKeysym(ROTATE_RIGHT_WINDOW_KEY_DEFAULT);

#define ROTATE_TO_SHORT        N_("Rotate To Face %d")
#define ROTATE_TO_LONG         N_("Rotate to face %d")
#define ROTATE_TO_WINDOW_SHORT N_("Rotate To Face %d with Window")
#define ROTATE_TO_WINDOW_LONG  N_("Rotate to face %d and bring active " \
        "window along")

#define ROTATE_TO_OPTION(n)                         \
    o = &rd->opt[ROTATE_DISPLAY_OPTION_TO_ ## n];             \
    o->advanced=False;\
o->name              = "rotate_to_" #n;             \
    asprintf (&str, ROTATE_TO_SHORT, n);                 \
    o->group=N_("Bindings");\
o->subGroup=N_("Face shortcuts");\
o->displayHints="";\
o->shortDesc          = str;                 \
    asprintf (&str, ROTATE_TO_LONG, n);                     \
    o->longDesc              = str;                 \
    o->type              = CompOptionTypeAction;         \
    o->value.action.initiate      = rotateTo;                 \
    o->value.action.terminate      = 0;                     \
    o->value.action.bell      = FALSE;                 \
    o->value.action.edgeMask      = 0;                     \
    o->value.action.state      = CompActionStateInitKey;         \
    o->value.action.state     |= CompActionStateInitButton;         \
    o->value.action.type      = CompBindingTypeNone;         \
    \
    o = &rd->opt[ROTATE_DISPLAY_OPTION_TO_ ## n ## _WINDOW];         \
    o->advanced=False;\
o->name              = "rotate_to_" #n "_window";         \
    asprintf (&str, ROTATE_TO_WINDOW_SHORT, n);                 \
    o->group=N_("Bindings");\
o->subGroup=N_("Face shortcuts");\
o->displayHints="";\
o->shortDesc          = str;                 \
    asprintf (&str, ROTATE_TO_WINDOW_LONG, n);                 \
    o->longDesc              = str;                 \
    o->type              = CompOptionTypeAction;         \
    o->value.action.initiate      = rotateToWithWindow;             \
    o->value.action.terminate      = 0;                     \
    o->value.action.bell      = FALSE;                 \
    o->value.action.edgeMask      = 0;                     \
    o->value.action.state      = CompActionStateInitKey;         \
    o->value.action.state     |= CompActionStateInitButton;         \
    o->value.action.type      = CompBindingTypeNone

      ROTATE_TO_OPTION(1);
      ROTATE_TO_OPTION(2);
      ROTATE_TO_OPTION(3);
      ROTATE_TO_OPTION(4);
      ROTATE_TO_OPTION(5);
      ROTATE_TO_OPTION(6);
      ROTATE_TO_OPTION(7);
      ROTATE_TO_OPTION(8);
      ROTATE_TO_OPTION(9);
      ROTATE_TO_OPTION(10);
      ROTATE_TO_OPTION(11);
      ROTATE_TO_OPTION(12);

      o = &rd->opt[ROTATE_DISPLAY_OPTION_TO];
      o->advanced = False;
      o->name = "rotate_to";
      o->group = N_("");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Rotate To");
      o->longDesc = N_("Rotate to Viewport.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateTo;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = 0;
      o->value.action.type = CompBindingTypeNone;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_WINDOW];
      o->advanced = False;
      o->name = "rotate_window";
      o->group = N_("");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Rotate Window");
      o->longDesc = N_("Rotate with Window.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateToWithWindow;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = 0;
      o->value.action.type = CompBindingTypeNone;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_FLIP_LEFT];
      o->advanced = False;
      o->name = "rotate_flip_left";
      o->group = N_("Bindings");
      o->subGroup = N_("Edge Flip");
      o->displayHints = "";
      o->shortDesc = N_("Rotate Flip Left");
      o->longDesc = N_("Flip to Left Viewport and warp pointer.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateEdgeFlipLeft;
      o->value.action.terminate = rotateFlipTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 1 << SCREEN_EDGE_LEFT;
      o->value.action.state = CompActionStateInitEdge;
      o->value.action.state |= CompActionStateInitEdgeDnd;
      o->value.action.state |= CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeNone;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_FLIP_RIGHT];
      o->advanced = False;
      o->name = "rotate_flip_right";
      o->group = N_("Bindings");
      o->subGroup = N_("Edge Flip");
      o->displayHints = "";
      o->shortDesc = N_("Rotate Flip Right");
      o->longDesc = N_("Flip to Right Viewport and warp pointer.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateEdgeFlipRight;
      o->value.action.terminate = rotateFlipTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 1 << SCREEN_EDGE_RIGHT;
      o->value.action.state = CompActionStateInitEdge;
      o->value.action.state |= CompActionStateInitEdgeDnd;
      o->value.action.state |= CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeNone;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_EDGEFLIP_POINTER];
      o->advanced = False;
      o->name = "edge_flip_pointer";
      o->group = N_("Behaviour");
      o->subGroup = N_("Edge Flip");
      o->displayHints = "";
      o->shortDesc = N_("Edge Flip Pointer");
      o->longDesc =
                  N_("Flip to Next Viewport when moving Pointer to Screen Edge.");
      o->type = CompOptionTypeBool;
      o->value.b = ROTATE_EDGEFLIP_POINTER_DEFAULT;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_EDGEFLIP_WINDOW];
      o->advanced = False;
      o->name = "edge_flip_move";
      o->group = N_("Behaviour");
      o->subGroup = N_("Edge Flip");
      o->displayHints = "";
      o->shortDesc = N_("Edge Flip Move");
      o->longDesc =
                  N_("Flip to Next Viewport when moving Window to Screen Edge.");
      o->type = CompOptionTypeBool;
      o->value.b = ROTATE_EDGEFLIP_WINDOW_DEFAULT;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_EDGEFLIP_DND];
      o->advanced = False;
      o->name = "edge_flip_dnd";
      o->group = N_("Behaviour");
      o->subGroup = N_("Edge Flip");
      o->displayHints = "";
      o->shortDesc = N_("Edge Flip DnD");
      o->longDesc =
                  N_("Flip to Next Viewport when Dragging object "
                        "to Screen Edge.");
      o->type = CompOptionTypeBool;
      o->value.b = ROTATE_EDGEFLIP_DND_DEFAULT;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_FLIPTIME];
      o->advanced = False;
      o->name = "flip_time";
      o->group = N_("Behaviour");
      o->subGroup = N_("Edge Flip");
      o->displayHints = "";
      o->shortDesc = N_("Flip Time");
      o->longDesc = N_("Timeout before Flipping viewport.");
      o->type = CompOptionTypeInt;
      o->value.i = ROTATE_FLIPTIME_DEFAULT;
      o->rest.i.min = ROTATE_FLIPTIME_MIN;
      o->rest.i.max = ROTATE_FLIPTIME_MAX;

      o = &rd->opt[ROTATE_DISPLAY_OPTION_INITIATEDESKTOP];
      o->advanced = False;
      o->name = "initiatedesktop";
      o->group = N_("Bindings");
      o->subGroup = N_("Initiate");
      o->displayHints = "";
      o->shortDesc = N_("Initiate on Desktop");
      o->longDesc = N_("Start Rotation, but only when issued over Desktop.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = rotateInitiateDesktop;
      o->value.action.terminate = rotateTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeButton;
      o->value.action.button.modifiers =
                  ROTATE_INITIATEDESKTOP_MODIFIERS_DEFAULT;
      o->value.action.button.button = ROTATE_INITIATEDESKTOP_BUTTON_DEFAULT;


}

static CompOption *rotateGetDisplayOptions(CompDisplay * display, int *count)
{
      if (display)
      {
            ROTATE_DISPLAY(display);

            *count = NUM_OPTIONS(rd);
            return rd->opt;
      }
      else
      {
            RotateDisplay *rd = malloc(sizeof(RotateDisplay));

            rotateDisplayInitOptions(rd);
            *count = NUM_OPTIONS(rd) - 2;
            return rd->opt;
      }
}

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;
      }

      rd->leftWheelings = 0;
      rd->rightWheelings = 0;

      rotateDisplayInitOptions(rd);

      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->baseYrot = 0.0f;

      rs->moving = FALSE;
      rs->moveTo = 0.0f;

      rs->movingVert = FALSE;
      rs->moveToY = 0.0f;

      rs->moveWindow = 0;

      rs->savedPointer.x = 0;
      rs->savedPointer.y = 0;

      rs->grabbed = FALSE;
      rs->snapTop = FALSE;
      rs->snapBottom = FALSE;

      rs->slow = FALSE;
      rs->grabMask = FALSE;
      rs->grabWindow = NULL;
      rs->manualAtom =
                  IPCS_GetAtom(IPCS_OBJECT(s), IPCS_BOOL, "MOUSE_INITIATED_ROTATE",
                                     TRUE);
      rs->pointerSensitivity =
                  ROTATE_POINTER_SENSITIVITY_DEFAULT *
                  ROTATE_POINTER_SENSITIVITY_FACTOR;

      rs->zoom = ROTATE_ZOOM_DEFAULT / 30.0f;
      rs->zooming = (ROTATE_ZOOM_DEFAULT > 0.05f) ? TRUE : FALSE;
      rs->zoomTranslate = 0.0f;
      rs->zoomVelocity = 0.0f;

      rs->rotateHandle = 0;
      rs->rotating = FALSE;

      rs->previousRotationAtom = IPCS_GetAtom(IPCS_OBJECT(s), IPCS_FLOAT,
                                                                  "PREVIOUS_ROTATION", TRUE);
      rs->snapTopBottomAtom = IPCS_GetAtom(IPCS_OBJECT(s), IPCS_BOOL,
                                                             "CUBE_SNAP_TOP_BOTTOM", TRUE);

      rotateScreenInitOptions(rs);

      addScreenAction(s, &rd->opt[ROTATE_DISPLAY_OPTION_INITIATE].value.action);
      addScreenAction(s, &rd->opt[ROTATE_DISPLAY_OPTION_LEFT].value.action);
      addScreenAction(s, &rd->opt[ROTATE_DISPLAY_OPTION_RIGHT].value.action);
      addScreenAction(s, &rd->opt[ROTATE_DISPLAY_OPTION_UP].value.action);
      addScreenAction(s, &rd->opt[ROTATE_DISPLAY_OPTION_DOWN].value.action);
      addScreenAction(s,
                              &rd->opt[ROTATE_DISPLAY_OPTION_LEFT_WINDOW].value.action);
      addScreenAction(s,
                              &rd->opt[ROTATE_DISPLAY_OPTION_RIGHT_WINDOW].value.
                              action);
      addScreenAction(s,
                              &rd->opt[ROTATE_DISPLAY_OPTION_FLIP_LEFT].value.action);
      addScreenAction(s,
                              &rd->opt[ROTATE_DISPLAY_OPTION_FLIP_RIGHT].value.action);
      addScreenAction(s,
                              &rd->opt[ROTATE_DISPLAY_OPTION_LEFT_WHEEL].value.action);
      addScreenAction(s,
                              &rd->opt[ROTATE_DISPLAY_OPTION_RIGHT_WHEEL].value.action);
      addScreenAction(s,
                              &rd->opt[ROTATE_DISPLAY_OPTION_INITIATEDESKTOP].value.
                              action);

      WRAP(rs, s, preparePaintScreen, rotatePreparePaintScreen);
      WRAP(rs, s, donePaintScreen, rotateDonePaintScreen);
      WRAP(rs, s, paintScreen, rotatePaintScreen);
      WRAP(rs, s, setScreenOptionForPlugin, rotateSetScreenOptionForPlugin);
      WRAP(rs, s, windowGrabNotify, rotateWindowGrabNotify);
      WRAP(rs, s, windowUngrabNotify, rotateWindowUngrabNotify);

      s->privates[rd->screenPrivateIndex].ptr = rs;

      rotateUpdateCubeOptions(s);

      return TRUE;
}

static void rotateFiniScreen(CompPlugin * p, CompScreen * s)
{
      ROTATE_SCREEN(s);
      ROTATE_DISPLAY(s->display);

      UNWRAP(rs, s, preparePaintScreen);
      UNWRAP(rs, s, donePaintScreen);
      UNWRAP(rs, s, paintScreen);
      UNWRAP(rs, s, setScreenOptionForPlugin);
      UNWRAP(rs, s, windowGrabNotify);
      UNWRAP(rs, s, windowUngrabNotify);

      removeScreenAction(s,
                                 &rd->opt[ROTATE_DISPLAY_OPTION_INITIATE].value.action);
      removeScreenAction(s, &rd->opt[ROTATE_DISPLAY_OPTION_LEFT].value.action);
      removeScreenAction(s, &rd->opt[ROTATE_DISPLAY_OPTION_RIGHT].value.action);
      removeScreenAction(s, &rd->opt[ROTATE_DISPLAY_OPTION_UP].value.action);
      removeScreenAction(s, &rd->opt[ROTATE_DISPLAY_OPTION_DOWN].value.action);
      removeScreenAction(s,
                                 &rd->opt[ROTATE_DISPLAY_OPTION_LEFT_WINDOW].
                                 value.action);
      removeScreenAction(s,
                                 &rd->opt[ROTATE_DISPLAY_OPTION_RIGHT_WINDOW].
                                 value.action);
      removeScreenAction(s,
                                 &rd->opt[ROTATE_DISPLAY_OPTION_FLIP_LEFT].value.
                                 action);
      removeScreenAction(s,
                                 &rd->opt[ROTATE_DISPLAY_OPTION_FLIP_RIGHT].
                                 value.action);
      removeScreenAction(s,
                                 &rd->opt[ROTATE_DISPLAY_OPTION_LEFT_WHEEL].
                                 value.action);
      removeScreenAction(s,
                                 &rd->opt[ROTATE_DISPLAY_OPTION_RIGHT_WHEEL].
                                 value.action);
      removeScreenAction(s,
                                 &rd->opt[ROTATE_DISPLAY_OPTION_INITIATEDESKTOP].value.
                                 action);

      free(rs);
}

static Bool rotateInit(CompPlugin * p)
{
      displayPrivateIndex = allocateDisplayPrivateIndex();
      if (displayPrivateIndex < 0)
            return FALSE;

      return TRUE;
}

static void rotateFini(CompPlugin * p)
{
      if (displayPrivateIndex >= 0)
            freeDisplayPrivateIndex(displayPrivateIndex);
}

CompPluginDep rotateDeps[] = {
      {CompPluginRuleAfter, "cube"}
      ,
      {CompPluginRuleRequire, "cube"}
};

CompPluginVTable rotateVTable = {
      "rotate",
      N_("Rotate Cube"),
      N_("Rotate desktop cube"),
      rotateInit,
      rotateFini,
      rotateInitDisplay,
      rotateFiniDisplay,
      rotateInitScreen,
      rotateFiniScreen,
      0,                                        /* InitWindow */
      0,                                        /* FiniWindow */
      rotateGetDisplayOptions,
      rotateSetDisplayOption,
      rotateGetScreenOptions,
      rotateSetScreenOption,
      rotateDeps,
      sizeof(rotateDeps) / sizeof(rotateDeps[0]),
      0,
      0,
      BERYL_ABI_INFO,
      "beryl-plugins",
      "desktop",
      0,
      0,
      True,
};

CompPluginVTable *getCompPluginInfo(void)
{
      return &rotateVTable;
}

Generated by  Doxygen 1.6.0   Back to index