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

inputzoom.c

/*
 * Beryl Input-Enabled-Zoom-Plugin
 *
 * Copyright : (C) 2006 by Dennis Kasprzyk
 * E-mail    : onestone@beryl-project.org
 *
 * Copyright : (C) 2006 Quinn Storm
 * E-mail    : quinnstorm@beryl-project.org
 *
 *
 * 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.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xfixes.h>

#include <beryl.h>

#define ZOOM_IN_BUTTON_DEFAULT    Button4
#define ZOOM_IN_MODIFIERS_DEFAULT CompSuperMask

#define ZOOM_OUT_BUTTON_DEFAULT    Button5
#define ZOOM_OUT_MODIFIERS_DEFAULT CompSuperMask

#define ZOOM_SPEED_DEFAULT   1.00f
#define ZOOM_SPEED_MIN       0.1f
#define ZOOM_SPEED_MAX       4.0f
#define ZOOM_SPEED_PRECISION 0.1f

#define ZOOM_STEP_DEFAULT   1.25f
#define ZOOM_STEP_MIN       1.05f
#define ZOOM_STEP_MAX       5.0f
#define ZOOM_STEP_PRECISION 0.05f

#define ZOOM_MAX_FACTOR_DEFAULT   16.0f
#define ZOOM_MAX_FACTOR_MIN       1.1f
#define ZOOM_MAX_FACTOR_MAX       64.0f
#define ZOOM_MAX_FACTOR_PRECISION 0.1f

#define ZOOM_TIMESTEP_DEFAULT   1.2f
#define ZOOM_TIMESTEP_MIN       0.1f
#define ZOOM_TIMESTEP_MAX       20.0f
#define ZOOM_TIMESTEP_PRECISION 0.1f

#define ZOOM_MOUSE_UPDATE_MIN     1
#define ZOOM_MOUSE_UPDATE_MAX     500
#define ZOOM_MOUSE_UPDATE_DEFAULT 10

#define ZOOM_FILTER_LINEAR_DEFAULT TRUE

#define ZOOM_HIDE_NORMAL_CURSOR_DEFAULT FALSE
#define ZOOM_SHOW_SCALED_CURSOR_DEFAULT FALSE

#define ZOOM_OUT_ON_CUBE_DEFAULT TRUE

static int displayPrivateIndex;

#define ZOOM_DISPLAY_OPTION_IN         0
#define ZOOM_DISPLAY_OPTION_OUT         1
#define ZOOM_DISPLAY_OPTION_NUM         2

typedef struct _ZoomDisplay
{
      int screenPrivateIndex;
      HandleEventProc handleEvent;

      Bool fixesSupported;
      int fixesEventBase;
      int fixesErrorBase;
      Bool canHideCursor;

      CompOption opt[ZOOM_DISPLAY_OPTION_NUM];
} ZoomDisplay;

#define ZOOM_SCREEN_OPTION_SPEED              0
#define ZOOM_SCREEN_OPTION_STEP               1
#define ZOOM_SCREEN_OPTION_MAX_FACTOR         2
#define ZOOM_SCREEN_OPTION_TIMESTEP           3
#define ZOOM_SCREEN_OPTION_FILTER_LINEAR      4
#define ZOOM_SCREEN_OPTION_MOUSE_UPDATE       5
#define ZOOM_SCREEN_OPTION_OUT_ON_CUBE        6
#define ZOOM_SCREEN_OPTION_NUM                7
//#define ZOOM_SCREEN_OPTION_HIDE_NORMAL_CURSOR 5
//#define ZOOM_SCREEN_OPTION_SHOW_SCALED_CURSOR 6


typedef struct _CursorTexture
{
      Bool isSet;
      GLuint texture;
      int width;
      int height;
      int hotX;
      int hotY;
} CursorTexture;

typedef struct _ZoomScreen
{
      PreparePaintScreenProc preparePaintScreen;
      DonePaintScreenProc donePaintScreen;
      PaintScreenProc paintScreen;
      PaintTransformedScreenProc paintTransformedScreen;
      SetScreenOptionForPluginProc setScreenOptionForPlugin;
      ApplyScreenTransformProc applyScreenTransform;

      CompTimeoutHandle mouseTimeout;

      CompOption opt[ZOOM_SCREEN_OPTION_NUM];

      float speed;
      float step;
      float timestep;
      float maxScale;

      GLfloat currentScale;
      GLfloat newScale;
      GLfloat toScale;

      GLfloat zVelocity;

      GLfloat xscale;
      GLfloat yscale;

      Bool active;

      CursorTexture cursor;
      int mouseX;
      int mouseY;
      Bool cursorHidden;
      Bool cursorInfoSelected;
      Bool showScaled;
      Bool hideNormal;
      Bool noTimerUpdate;

      float maxTranslate;
} ZoomScreen;

#define GET_ZOOM_DISPLAY(d)                      \
    ((ZoomDisplay *) (d)->privates[displayPrivateIndex].ptr)

#define ZOOM_DISPLAY(d)                   \
    ZoomDisplay *zd = GET_ZOOM_DISPLAY (d)

#define GET_ZOOM_SCREEN(s, zd)                         \
    ((ZoomScreen *) (s)->privates[(zd)->screenPrivateIndex].ptr)

#define ZOOM_SCREEN(s)                                \
    ZoomScreen *zs = GET_ZOOM_SCREEN (s, GET_ZOOM_DISPLAY (s->display))

#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))

static void updateCursor(Display * dpy, CursorTexture * cursor)
{
      glEnable(GL_TEXTURE_RECTANGLE_ARB);
      if (!cursor->isSet)
      {
            cursor->isSet = TRUE;
            glGenTextures(1, &cursor->texture);
            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cursor->texture);
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
                                    GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
                                    GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
                                    GL_TEXTURE_WRAP_S, GL_CLAMP);
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
                                    GL_TEXTURE_WRAP_T, GL_CLAMP);
      }

      XFixesCursorImage *ci = XFixesGetCursorImage(dpy);

      cursor->width = ci->width;
      cursor->height = ci->height;
      cursor->hotX = ci->xhot;
      cursor->hotY = ci->yhot;

      unsigned char *pixels = malloc(ci->width * ci->height * 4);
      int i;

      for (i = 0; i < ci->width * ci->height; i++)
      {
            unsigned long pix = ci->pixels[i];

            pixels[i * 4] = pix & 0xff;
            pixels[(i * 4) + 1] = (pix >> 8) & 0xff;
            pixels[(i * 4) + 2] = (pix >> 16) & 0xff;
            pixels[(i * 4) + 3] = (pix >> 24) & 0xff;
      }

      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cursor->texture);
      glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, cursor->width,
                         cursor->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
      glDisable(GL_TEXTURE_RECTANGLE_ARB);
      XFree(ci);
      free(pixels);
}

static void freeCursor(CursorTexture * cursor)
{
      if (!cursor->isSet)
            return;
      cursor->isSet = FALSE;
      glDeleteTextures(1, &cursor->texture);
      cursor->texture = 0;
}

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

      ZOOM_DISPLAY(d);

      if (event->type == zd->fixesEventBase + XFixesCursorNotify)
      {
            XFixesCursorNotifyEvent *cev = (XFixesCursorNotifyEvent *) event;

            s = findScreenAtDisplay(d, cev->window);
            if (s)
            {
                  ZOOM_SCREEN(s);
                  if (zs->cursor.isSet)
                        updateCursor(d->display, &zs->cursor);
            }
      }

      UNWRAP(zd, d, handleEvent);
      (*d->handleEvent) (d, event);
      WRAP(zd, d, handleEvent, zoomHandleEvent);
}

static Bool
zoomSetScreenOption(CompScreen * screen, char *name, CompOptionValue * value)
{
      CompOption *o;
      int index;

      ZOOM_SCREEN(screen);

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

      switch (index)
      {
      case ZOOM_SCREEN_OPTION_STEP:
            if (compSetFloatOption(o, value))
            {
                  zs->step = o->value.f;
                  return TRUE;
            }
            break;
      case ZOOM_SCREEN_OPTION_MAX_FACTOR:
            if (compSetFloatOption(o, value))
            {
                  zs->maxScale = o->value.f;
                  return TRUE;
            }
            break;
      case ZOOM_SCREEN_OPTION_SPEED:
            if (compSetFloatOption(o, value))
            {
                  zs->speed = o->value.f;
                  return TRUE;
            }
            break;
      case ZOOM_SCREEN_OPTION_TIMESTEP:
            if (compSetFloatOption(o, value))
            {
                  zs->timestep = o->value.f;
                  return TRUE;
            }
            break;
      case ZOOM_SCREEN_OPTION_FILTER_LINEAR:
            if (compSetBoolOption(o, value))
                  return TRUE;
/*    case ZOOM_SCREEN_OPTION_HIDE_NORMAL_CURSOR:
            if (compSetBoolOption(o, value))
            {
                  zs->hideNormal = o->value.b;
                  return TRUE;
            }
            break;
      case ZOOM_SCREEN_OPTION_SHOW_SCALED_CURSOR:
            if (compSetBoolOption(o, value))
            {
                  zs->showScaled = o->value.b;
                  return TRUE;
            }
            break;*/
      case ZOOM_SCREEN_OPTION_MOUSE_UPDATE:
            if (compSetIntOption(o, value))
            {
                  return TRUE;
            }
            break;
      case ZOOM_SCREEN_OPTION_OUT_ON_CUBE:
            if (compSetBoolOption(o, value))
            {
                  return TRUE;
            }
            break;
      default:
            break;
      }

      return FALSE;
}

static void zoomScreenInitOptions(ZoomScreen * zs)
{
      CompOption *o;

      o = &zs->opt[ZOOM_SCREEN_OPTION_SPEED];
      o->advanced = False;
      o->name = "speed";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Zoom Speed");
      o->longDesc = N_("Zoom Speed.");
      o->type = CompOptionTypeFloat;
      o->value.f = ZOOM_SPEED_DEFAULT;
      o->rest.f.min = ZOOM_SPEED_MIN;
      o->rest.f.max = ZOOM_SPEED_MAX;
      o->rest.f.precision = ZOOM_SPEED_PRECISION;

      o = &zs->opt[ZOOM_SCREEN_OPTION_STEP];
      o->advanced = False;
      o->name = "step";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Step");
      o->longDesc =
                  N_
                  ("Zoomfactor multiplier for amount of Zooming in each ZoomIn/ZoomOut.");
      o->type = CompOptionTypeFloat;
      o->value.f = ZOOM_STEP_DEFAULT;
      o->rest.f.min = ZOOM_STEP_MIN;
      o->rest.f.max = ZOOM_STEP_MAX;
      o->rest.f.precision = ZOOM_STEP_PRECISION;

      o = &zs->opt[ZOOM_SCREEN_OPTION_MAX_FACTOR];
      o->advanced = False;
      o->name = "max";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Maximum Zoom");
      o->longDesc = N_("Maximum Zoom factor.");
      o->type = CompOptionTypeFloat;
      o->value.f = ZOOM_MAX_FACTOR_DEFAULT;
      o->rest.f.min = ZOOM_MAX_FACTOR_MIN;
      o->rest.f.max = ZOOM_MAX_FACTOR_MAX;
      o->rest.f.precision = ZOOM_MAX_FACTOR_PRECISION;

      o = &zs->opt[ZOOM_SCREEN_OPTION_TIMESTEP];
      o->advanced = False;
      o->name = "timestep";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Zoom Timestep");
      o->longDesc = N_("Zoom Timestep.");
      o->type = CompOptionTypeFloat;
      o->value.f = ZOOM_TIMESTEP_DEFAULT;
      o->rest.f.min = ZOOM_TIMESTEP_MIN;
      o->rest.f.max = ZOOM_TIMESTEP_MAX;
      o->rest.f.precision = ZOOM_TIMESTEP_PRECISION;

      o = &zs->opt[ZOOM_SCREEN_OPTION_FILTER_LINEAR];
      o->advanced = False;
      o->name = "filter_linear";
      o->group = N_("Misc. options");
      o->subGroup = N_("Visual quality");
      o->displayHints = "";
      o->shortDesc = N_("Linear Filtering");
      o->longDesc = N_("Use Linear Filter when Zoomed in.");
      o->type = CompOptionTypeBool;
      o->value.b = ZOOM_FILTER_LINEAR_DEFAULT;

/*    o = &zs->opt[ZOOM_SCREEN_OPTION_HIDE_NORMAL_CURSOR];
      o->advanced = False;
      o->name = "hide_normal";
      o->group = N_("Misc. options");
      o->subGroup = N_("Cursor options");
      o->displayHints = "";
      o->shortDesc = N_("Hide Normal Cursor (May cause\nissues when switching window managers).");
      o->longDesc = N_("Hide Normal Cursor during Zoom.");
      o->type = CompOptionTypeBool;
      o->value.b = ZOOM_HIDE_NORMAL_CURSOR_DEFAULT;

      o = &zs->opt[ZOOM_SCREEN_OPTION_SHOW_SCALED_CURSOR];
      o->advanced = False;
      o->name = "show_scaled";
      o->group = N_("Misc. options");
      o->subGroup = N_("Cursor options");
      o->displayHints = "";
      o->shortDesc = N_("Show Scaled Cursor");
      o->longDesc = N_("Show Scaled Cursor during Zoom.");
      o->type = CompOptionTypeBool;
      o->value.b = ZOOM_SHOW_SCALED_CURSOR_DEFAULT;*/

      o = &zs->opt[ZOOM_SCREEN_OPTION_MOUSE_UPDATE];
      o->advanced = True;
      o->name = "mouse_update";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Mouse Update Interval");
      o->longDesc = N_("Mouse position Update Interval.");
      o->type = CompOptionTypeInt;
      o->value.i = ZOOM_MOUSE_UPDATE_DEFAULT;
      o->rest.i.min = ZOOM_MOUSE_UPDATE_MIN;
      o->rest.i.max = ZOOM_MOUSE_UPDATE_MAX;

      o = &zs->opt[ZOOM_SCREEN_OPTION_OUT_ON_CUBE];
      o->advanced = False;
      o->name = "zoomout_on_cube";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Zoom Out on Cube");
      o->longDesc = N_("Zoom Out if the Cube gets activated.");
      o->type = CompOptionTypeBool;
      o->value.b = ZOOM_OUT_ON_CUBE_DEFAULT;
}
static CompOption *zoomGetScreenOptions(CompScreen * screen, int *count)
{
      if (screen)
      {
            ZOOM_SCREEN(screen);

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

            zoomScreenInitOptions(zs);
            *count = NUM_OPTIONS(zs);
            return zs->opt;
      }
}


static int adjustZoomVelocity(ZoomScreen * zs)
{
      float d, adjust, amount;

      d = (zs->toScale - zs->currentScale) * 75.0f;

      adjust = d * 0.002f;
      amount = fabs(d);
      if (amount < 1.0f)
            amount = 1.0f;
      else if (amount > 5.0f)
            amount = 5.0f;

      zs->zVelocity = (amount * zs->zVelocity + adjust) / (amount + 1.0f);

      return (fabs(d) < 0.1f && fabs(zs->zVelocity) < 0.005f);
}

static void
zoomApplyScreenTransform(CompScreen * s,
                                     const ScreenPaintAttrib * sAttrib, int output)
{
      ZOOM_SCREEN(s);

      UNWRAP(zs, s, applyScreenTransform);
      (*s->applyScreenTransform) (s, sAttrib, output);
      WRAP(zs, s, applyScreenTransform, zoomApplyScreenTransform);

      Bool *pCaps = (Bool *) IPCS_GetVPtrND(IPCS_OBJECT(s),
                                                              "CUBE_PAINTING_CAPS_BOOL_PTR",
                                                              NULL);

      if (zs->active && (!pCaps || !(*pCaps)))
      {
            float ox, oy, ow, oh;

            int mmMode = IPCS_GetIntND(IPCS_OBJECT(s), "MM_MODE", 0);

            if (mmMode == 1)
            {
                  ox = 0;
                  oy = 0;
                  ow = s->width;
                  oh = s->height;
            }
            else
            {
                  ox = s->outputDev[output].region.extents.x1;
                  oy = s->outputDev[output].region.extents.y1;
                  ow = s->outputDev[output].width;
                  oh = s->outputDev[output].height;
            }

            float tx = zs->mouseX - (ox + (ow / 2.0));
            float ty = zs->mouseY - (oy + (oh / 2.0));

            tx /= ow;
            tx = -(tx * (zs->xscale - 1));
            ty /= oh;
            ty = ty * (zs->yscale - 1);

            glTranslatef(tx, ty, 0.0f);
            glScalef(zs->xscale, zs->yscale, 1.0f);
      }
}

static Bool zoomUpdateMouse(void *vs)
{
      CompScreen *s = (CompScreen *) vs;

      ZOOM_SCREEN(s);

      if (zs->active &&
            !otherScreenGrabExist(s, "scale", "switcher", "move", "resize", 0))
      {
            int winX, winY;
            int rootX, rootY;
            unsigned int mask_return;
            Window root_return;
            Window child_return;

            XQueryPointer(s->display->display, s->root,
                                &root_return, &child_return,
                                &rootX, &rootY, &winX, &winY, &mask_return);

            if (rootX != zs->mouseX || rootY != zs->mouseY)
            {
                  zs->mouseX = rootX;
                  zs->mouseY = rootY;
                  damageScreen(s);
            }
      }

      if (!zs->noTimerUpdate)
            zs->mouseTimeout =
                  compAddTimeout(zs->opt[ZOOM_SCREEN_OPTION_MOUSE_UPDATE].value.i,
                                       zoomUpdateMouse, s);
      return FALSE;
}

static void zoomPreparePaintScreen(CompScreen * s, int msSinceLastPaint)
{
      ZOOM_SCREEN(s);
      ZOOM_DISPLAY(s->display);

      if (screenGrabExist(s, "rotate", "cube", 0) &&
            zs->opt[ZOOM_SCREEN_OPTION_OUT_ON_CUBE].value.b)
            zs->toScale = 1.0f;
      else
            zs->toScale = zs->newScale;

      if (zs->active)
      {
            int steps;
            float amount, chunk;

            amount = msSinceLastPaint * 0.05f * zs->speed;
            steps = amount / (0.5f * zs->timestep);
            if (!steps)
                  steps = 1;
            chunk = amount / (float)steps;

            while (steps--)
            {

                  if (adjustZoomVelocity(zs))
                  {
                        zs->currentScale = zs->toScale;
                        zs->zVelocity = 0.0f;
                  }
                  else
                  {
                        zs->currentScale +=
                                    (zs->zVelocity * msSinceLastPaint) / s->redrawTime;
                  }

                  zs->xscale = zs->currentScale;
                  zs->yscale = zs->currentScale;

                  if (zs->currentScale == 1.0f && zs->zVelocity == 0.0f &&
                        zs->newScale == 1.0)
                  {
                        zs->active = FALSE;
                        if (zs->mouseTimeout)
                        {
                              compRemoveTimeout(zs->mouseTimeout);
                              zs->mouseTimeout = 0;
                        }
                        break;
                  }

            }

            if (zs->currentScale == 1.0f && zs->zVelocity == 0.0f &&
                  zs->newScale == 1.0)
            {
                  zs->active = FALSE;
                  if (zs->mouseTimeout)
                  {
                        compRemoveTimeout(zs->mouseTimeout);
                        zs->mouseTimeout = 0;
                  }
            }
      }

      if (!zs->active && zd->fixesSupported && zs->cursorInfoSelected)
      {
            zs->cursorInfoSelected = FALSE;
            XFixesSelectCursorInput(s->display->display, s->root, 0);
      }
      if (!zs->active && zs->cursor.isSet)
      {
            freeCursor(&zs->cursor);
      }
      if (zd->canHideCursor && !zs->active && zs->cursorHidden)
      {
            zs->cursorHidden = FALSE;
            XFixesShowCursor(s->display->display, s->root);
      }

      UNWRAP(zs, s, preparePaintScreen);
      (*s->preparePaintScreen) (s, msSinceLastPaint);
      WRAP(zs, s, preparePaintScreen, zoomPreparePaintScreen);
}

static void zoomDonePaintScreen(CompScreen * s)
{
      ZOOM_SCREEN(s);

      if (zs->active && zs->zVelocity != 0.0f)
      {
            damageScreen(s);
      }
      zs->noTimerUpdate = TRUE;
      zoomUpdateMouse(s);
      zs->noTimerUpdate = FALSE;

      UNWRAP(zs, s, donePaintScreen);
      (*s->donePaintScreen) (s);
      WRAP(zs, s, donePaintScreen, zoomDonePaintScreen);
}

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

      ZOOM_SCREEN(s);

      if (zs->active)
      {
            mask &= ~PAINT_SCREEN_REGION_MASK;
            mask |= PAINT_SCREEN_TRANSFORMED_MASK | PAINT_SCREEN_CLEAR_MASK;

            int saveFilter = s->filter[SCREEN_TRANS_FILTER];

            if (zs->opt[ZOOM_SCREEN_OPTION_FILTER_LINEAR].value.b ||
                  zs->zVelocity != 0.0f)
                  s->filter[SCREEN_TRANS_FILTER] = COMP_TEXTURE_FILTER_GOOD;
            else
                  s->filter[SCREEN_TRANS_FILTER] = COMP_TEXTURE_FILTER_FAST;

            UNWRAP(zs, s, paintScreen);
            status = (*s->paintScreen) (s, sAttrib, region, output, mask);
            WRAP(zs, s, paintScreen, zoomPaintScreen);

            s->filter[SCREEN_TRANS_FILTER] = saveFilter;
      }
      else
      {
            UNWRAP(zs, s, paintScreen);
            status = (*s->paintScreen) (s, sAttrib, region, output, mask);
            WRAP(zs, s, paintScreen, zoomPaintScreen);
      }

      return status;
}

static void
zoomPaintTransformedScreen(CompScreen * s, const ScreenPaintAttrib * sa,
                                       Region region, int output, unsigned int mask)
{
      ZOOM_SCREEN(s);
      if (zs->active)
      {
            REGION r;

            r.rects = &r.extents;
            r.numRects = 1;

            if (screenGrabExist(s, "rotate", "cube", 0) &&
                  IPCS_GetIntND(IPCS_OBJECT(s), "MM_MODE", 0) == 1)
            {
                  r.extents.x1 = zs->mouseX - (zs->mouseX / zs->xscale);
                  r.extents.y1 = zs->mouseY - (zs->mouseY / zs->yscale);
                  r.extents.x2 = r.extents.x1 + ceil(s->width / zs->xscale) + 1;
                  r.extents.y2 = r.extents.y1 + ceil(s->height / zs->yscale) + 1;
            }
            else
            {
                  r.extents.x1 = zs->mouseX - (zs->mouseX / zs->xscale) +
                              (s->outputDev[output].region.extents.x1 / zs->xscale);
                  r.extents.y1 = zs->mouseY - (zs->mouseY / zs->yscale) +
                              (s->outputDev[output].region.extents.y1 / zs->yscale);
                  r.extents.x2 = r.extents.x1 +
                              ceil(s->outputDev[output].width / zs->xscale) + 1;
                  r.extents.y2 = r.extents.y1 +
                              ceil(s->outputDev[output].height / zs->yscale) + 1;
            }


            r.extents.x1 = MAX(0, r.extents.x1);
            r.extents.y1 = MAX(0, r.extents.y1);
            r.extents.x2 = MIN(s->width, r.extents.x2);
            r.extents.y2 = MIN(s->height, r.extents.y2);

            UNWRAP(zs, s, paintTransformedScreen);
            (*s->paintTransformedScreen) (s, sa, &r, output, mask);
            WRAP(zs, s, paintTransformedScreen, zoomPaintTransformedScreen);

            if (zs->cursor.isSet)
            {
                  glPushMatrix();
                  glLoadIdentity();
                  prepareXCoords(s, output, -DEFAULT_Z_CAMERA);

                  glTranslatef(zs->mouseX, zs->mouseY, 0.0);
                  glScalef(zs->xscale, zs->yscale, 1.0f);
                  int x = -zs->cursor.hotX;
                  int y = -zs->cursor.hotY;

                  glEnable(GL_BLEND);
                  glBindTexture(GL_TEXTURE_RECTANGLE_ARB, zs->cursor.texture);
                  glEnable(GL_TEXTURE_RECTANGLE_ARB);

                  glBegin(GL_QUADS);
                  glTexCoord2d(0, 0);
                  glVertex2f(x, y);
                  glTexCoord2d(0, zs->cursor.height);
                  glVertex2f(x, y + zs->cursor.height);
                  glTexCoord2d(zs->cursor.width, zs->cursor.height);
                  glVertex2f(x + zs->cursor.width, y + zs->cursor.height);
                  glTexCoord2d(zs->cursor.width, 0);
                  glVertex2f(x + zs->cursor.width, y);
                  glEnd();

                  glDisable(GL_BLEND);

                  glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
                  glDisable(GL_TEXTURE_RECTANGLE_ARB);
                  glPopMatrix();
            }
      }
      else
      {
            UNWRAP(zs, s, paintTransformedScreen);
            (*s->paintTransformedScreen) (s, sa, region, output, mask);
            WRAP(zs, s, paintTransformedScreen, zoomPaintTransformedScreen);
      }
}

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

      ZOOM_DISPLAY(d);

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

      s = findScreenAtDisplay(d, xid);
      if (s)
      {
            ZOOM_SCREEN(s);

            zs->active = TRUE;

            if (!zs->mouseTimeout)
                  zs->mouseTimeout =
                              compAddTimeout(zs->opt[ZOOM_SCREEN_OPTION_MOUSE_UPDATE].
                                                   value.i, zoomUpdateMouse, s);

            if (zd->fixesSupported && !zs->cursorInfoSelected && zs->showScaled)
            {
                  zs->cursorInfoSelected = TRUE;
                  XFixesSelectCursorInput(s->display->display,
                                                      s->root, XFixesDisplayCursorNotifyMask);
                  updateCursor(d->display, &zs->cursor);
            }
            if (zd->canHideCursor && !zs->cursorHidden && zs->hideNormal)
            {
                  zs->cursorHidden = TRUE;
                  XFixesHideCursor(d->display, s->root);
            }

            zs->newScale *= zs->step;
            if (zs->newScale > zs->maxScale)
                  zs->newScale = zs->maxScale;

            damageScreen(s);
      }

      return TRUE;
}

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

      ZOOM_DISPLAY(d);

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

      s = findScreenAtDisplay(d, xid);
      if (s)
      {
            ZOOM_SCREEN(s);

            zs->active = TRUE;

            if (!zs->mouseTimeout)
                  zs->mouseTimeout =
                              compAddTimeout(zs->opt[ZOOM_SCREEN_OPTION_MOUSE_UPDATE].
                                                   value.i, zoomUpdateMouse, s);

            if (zd->fixesSupported && !zs->cursorInfoSelected && zs->showScaled)
            {
                  zs->cursorInfoSelected = TRUE;
                  XFixesSelectCursorInput(s->display->display,
                                                      s->root, XFixesDisplayCursorNotifyMask);
                  updateCursor(d->display, &zs->cursor);
            }
            if (zd->canHideCursor && !zs->cursorHidden && zs->hideNormal)
            {
                  zs->cursorHidden = TRUE;
                  XFixesHideCursor(d->display, s->root);
            }

            zs->newScale /= zs->step;
            if (zs->newScale < 1.0)
                  zs->newScale = 1.0;

            damageScreen(s);
      }

      return TRUE;
}

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

      ZOOM_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)
                  zs->maxTranslate = option->value.b ? 0.85f : 1.5f;
      }
      else
      {
            zs->maxTranslate = 1.5f;
      }
}

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

      ZOOM_SCREEN(s);

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

      if (status && strcmp(plugin, "cube") == 0)
            zoomUpdateCubeOptions(s);

      return status;
}

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

      ZOOM_DISPLAY(display);

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

      switch (index)
      {
      case ZOOM_DISPLAY_OPTION_IN:
      case ZOOM_DISPLAY_OPTION_OUT:
            if (setDisplayAction(display, o, value))
                  return TRUE;
      default:
            break;
      }

      return FALSE;
}

static void zoomDisplayInitOptions(ZoomDisplay * zd)
{
      CompOption *o;

      o = &zd->opt[ZOOM_DISPLAY_OPTION_IN];
      o->advanced = False;
      o->name = "zoom_in";
      o->group = N_("Bindings");
      o->subGroup = N_("Zoom In");
      o->displayHints = "";
      o->shortDesc = N_("Zoom In");
      o->longDesc = N_("Zoom In.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = zoomIn;
      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 = ZOOM_IN_MODIFIERS_DEFAULT;
      o->value.action.button.button = ZOOM_IN_BUTTON_DEFAULT;

      o = &zd->opt[ZOOM_DISPLAY_OPTION_OUT];
      o->advanced = False;
      o->name = "zoom_out";
      o->group = N_("Bindings");
      o->subGroup = N_("Zoom Out");
      o->displayHints = "";
      o->shortDesc = N_("Zoom Out");
      o->longDesc = N_("Zoom Out.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = zoomOut;
      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 = ZOOM_OUT_MODIFIERS_DEFAULT;
      o->value.action.button.button = ZOOM_OUT_BUTTON_DEFAULT;
}

static CompOption *zoomGetDisplayOptions(CompDisplay * display, int *count)
{
      if (display)
      {
            ZOOM_DISPLAY(display);

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

            zoomDisplayInitOptions(zd);
            *count = NUM_OPTIONS(zd);
            return zd->opt;
      }
}

static Bool zoomInitDisplay(CompPlugin * p, CompDisplay * d)
{
      ZoomDisplay *zd;

      zd = malloc(sizeof(ZoomDisplay));
      if (!zd)
            return FALSE;

      zd->screenPrivateIndex = allocateScreenPrivateIndex(d);
      if (zd->screenPrivateIndex < 0)
      {
            free(zd);
            return FALSE;
      }

      zoomDisplayInitOptions(zd);

      WRAP(zd, d, handleEvent, zoomHandleEvent);

      d->privates[displayPrivateIndex].ptr = zd;


      zd->fixesSupported =
                  XFixesQueryExtension(d->display, &zd->fixesEventBase,
                                                 &zd->fixesErrorBase);

      int minor, major;

      XFixesQueryVersion(d->display, &major, &minor);

      if (major >= 4)
            zd->canHideCursor = TRUE;
      else
            zd->canHideCursor = FALSE;

      return TRUE;
}

static void zoomFiniDisplay(CompPlugin * p, CompDisplay * d)
{
      ZOOM_DISPLAY(d);

      UNWRAP(zd, d, handleEvent);
      freeScreenPrivateIndex(d, zd->screenPrivateIndex);

      free(zd);
}

static Bool zoomInitScreen(CompPlugin * p, CompScreen * s)
{
      ZoomScreen *zs;

      ZOOM_DISPLAY(s->display);

      zs = malloc(sizeof(ZoomScreen));
      if (!zs)
            return FALSE;

      zs->active = FALSE;

      zs->mouseTimeout = 0;

      zs->currentScale = 1.0f;
      zs->newScale = 1.0f;

      zs->zVelocity = 0.0f;

      zs->maxTranslate = 0.85f;

      zs->speed = ZOOM_SPEED_DEFAULT;
      zs->step = ZOOM_STEP_DEFAULT;
      zs->maxScale = ZOOM_MAX_FACTOR_DEFAULT;
      zs->timestep = ZOOM_TIMESTEP_DEFAULT;

      zoomScreenInitOptions(zs);

      addScreenAction(s, &zd->opt[ZOOM_DISPLAY_OPTION_IN].value.action);
      addScreenAction(s, &zd->opt[ZOOM_DISPLAY_OPTION_OUT].value.action);

      WRAP(zs, s, preparePaintScreen, zoomPreparePaintScreen);
      WRAP(zs, s, donePaintScreen, zoomDonePaintScreen);
      WRAP(zs, s, paintScreen, zoomPaintScreen);
      WRAP(zs, s, paintTransformedScreen, zoomPaintTransformedScreen);
      WRAP(zs, s, setScreenOptionForPlugin, zoomSetScreenOptionForPlugin);
      WRAP(zs, s, applyScreenTransform, zoomApplyScreenTransform);

      s->privates[zd->screenPrivateIndex].ptr = zs;

      zoomUpdateCubeOptions(s);

      zs->cursor.isSet = FALSE;
      zs->cursorHidden = FALSE;
      zs->cursorInfoSelected = FALSE;

      zs->showScaled = ZOOM_SHOW_SCALED_CURSOR_DEFAULT;
      zs->hideNormal = ZOOM_HIDE_NORMAL_CURSOR_DEFAULT;

      zs->noTimerUpdate = FALSE;

      return TRUE;
}

static void zoomFiniScreen(CompPlugin * p, CompScreen * s)
{
      ZOOM_SCREEN(s);
      ZOOM_DISPLAY(s->display);

      if (zs->mouseTimeout)
      {
            compRemoveTimeout(zs->mouseTimeout);
            zs->mouseTimeout = 0;
      }

      UNWRAP(zs, s, preparePaintScreen);
      UNWRAP(zs, s, donePaintScreen);
      UNWRAP(zs, s, paintScreen);
      UNWRAP(zs, s, paintTransformedScreen);
      UNWRAP(zs, s, setScreenOptionForPlugin);
      UNWRAP(zs, s, applyScreenTransform);

      removeScreenAction(s, &zd->opt[ZOOM_DISPLAY_OPTION_IN].value.action);
      removeScreenAction(s, &zd->opt[ZOOM_DISPLAY_OPTION_OUT].value.action);

      free(zs);
}


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

      return TRUE;
}

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

CompPluginDep zoomDeps[] = {
      {CompPluginRuleBefore, "cube"}
      ,
};

CompPluginFeature zoomFeatures[] = {
      {"zoom"}
};

CompPluginVTable zoomVTable = {
      "inputzoom",
      N_("Input enabled Zoom"),
      N_("Input Enabled Zoom"),
      zoomInit,
      zoomFini,
      zoomInitDisplay,
      zoomFiniDisplay,
      zoomInitScreen,
      zoomFiniScreen,
      0,
      0,
      zoomGetDisplayOptions,
      zoomSetDisplayOption,
      zoomGetScreenOptions,
      zoomSetScreenOption,
      zoomDeps,
      sizeof(zoomDeps) / sizeof(zoomDeps[0]),
      zoomFeatures,
      sizeof(zoomFeatures) / sizeof(zoomFeatures[0]),
      BERYL_ABI_INFO,
      "beryl-plugins",
      "accessibility",
      0,
      0,
      True,
};

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

Generated by  Doxygen 1.6.0   Back to index