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

move.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>
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <X11/cursorfont.h>

#include <beryl.h>

#define MOVE_INITIATE_BUTTON_DEFAULT           Button1
#define MOVE_INITIATE_BUTTON_MODIFIERS_DEFAULT CompAltMask

#define MOVE_INITIATE_KEY_DEFAULT        "F7"
#define MOVE_INITIATE_KEY_MODIFIERS_DEFAULT CompAltMask

#define MOVE_OPACITY_DEFAULT 100
#define MOVE_OPACITY_MIN     1
#define MOVE_OPACITY_MAX     100

#define MOVE_CONSTRAIN_Y_TOP_DEFAULT TRUE
#define MOVE_CONSTRAIN_Y_BOTTOM_DEFAULT FALSE

#define MOVE_SNAPOFF_MAXIMIZED_DEFAULT FALSE

#define MOVE_OPACIFY_MIN_OPACITY_DEFAULT 80
#define MOVE_OPACIFY_MIN_OPACITY_MIN     1
#define MOVE_OPACIFY_MIN_OPACITY_MAX     100

#define MOVE_SNAPOFF_DISTANCE_DEFAULT    100
#define MOVE_SNAPOFF_DISTANCE_MIN    1
#define MOVE_SNAPOFF_DISTANCE_MAX    300

#define MOVE_SNAPBACK_DISTANCE_DEFAULT     20
#define MOVE_SNAPBACK_DISTANCE_MIN   1
#define MOVE_SNAPBACK_DISTANCE_MAX   100

struct _MoveKeys
{
      char *name;
      int dx;
      int dy;
} mKeys[] =
{
      {
      "Left", -1, 0},
      {
      "Right", 1, 0},
      {
      "Up", 0, -1},
      {
      "Down", 0, 1}
};

#define NUM_KEYS (sizeof (mKeys) / sizeof (mKeys[0]))

#define KEY_MOVE_INC 24

static int displayPrivateIndex;

#define MOVE_DISPLAY_OPTION_INITIATE                  0
#define MOVE_DISPLAY_OPTION_OPACITY                   1
#define MOVE_DISPLAY_OPTION_CONSTRAIN_Y_TOP           2
#define MOVE_DISPLAY_OPTION_CONSTRAIN_Y_BOTTOM  3
#define MOVE_DISPLAY_OPTION_OPACIFY_MIN_OPACITY 4
#define MOVE_DISPLAY_OPTION_SNAPOFF_MAXIMIZED   5
#define MOVE_DISPLAY_OPTION_SNAPOFF_DISTANCE    6
#define MOVE_DISPLAY_OPTION_SNAPBACK_DISTANCE   7
#define MOVE_DISPLAY_OPTION_NUM                             8

typedef struct _MoveDisplay
{
      int screenPrivateIndex;
      HandleEventProc handleEvent;

      CompOption opt[MOVE_DISPLAY_OPTION_NUM];

      CompWindow *w;
      int x;
      int y;
      Region region;
      int status;

      KeyCode key[NUM_KEYS];
      Bool moveOpacitySet;
      GLushort moveOpacity;
      GLushort opacifyMinOpacity;
} MoveDisplay;

typedef struct _MoveScreen
{
      int grabIndex;

      Cursor moveCursor;

      unsigned int origState;

      int snapOffY;
      int snapBackY;
} MoveScreen;

#define GET_MOVE_DISPLAY(d)                     \
    ((MoveDisplay *) (d)->privates[displayPrivateIndex].ptr)

#define MOVE_DISPLAY(d)                   \
    MoveDisplay *md = GET_MOVE_DISPLAY (d)

#define GET_MOVE_SCREEN(s, md)                         \
    ((MoveScreen *) (s)->privates[(md)->screenPrivateIndex].ptr)

#define MOVE_SCREEN(s)                                \
    MoveScreen *ms = GET_MOVE_SCREEN (s, GET_MOVE_DISPLAY (s->display))

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

static Bool
moveInitiate(CompDisplay * d,
                   CompAction * action,
                   CompActionState state, CompOption * option, int nOption)
{
      CompWindow *w;
      Window xid;

      MOVE_DISPLAY(d);

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

      w = findWindowAtDisplay(d, xid);
      if (w)
      {
            XRectangle workArea;
            unsigned int mods;
            int x, y, head;

            MOVE_SCREEN(w->screen);

            head = screenGetOutputDevForWindow(w);
            screenGetOutputDevWorkArea(w->screen, head, &workArea);

            mods = getIntOptionNamed(option, nOption, "modifiers", 0);

            x = getIntOptionNamed(option, nOption, "x",
                                            w->attrib.x + (w->width / 2));
            y = getIntOptionNamed(option, nOption, "y",
                                            w->attrib.y + (w->height / 2));

            if (otherScreenGrabExist(w->screen, "move", 0))
                  return FALSE;

            if (md->w)
                  return FALSE;

            if (w->type & (CompWindowTypeDesktopMask |
                                 CompWindowTypeDockMask | CompWindowTypeFullscreenMask))
                  return FALSE;

            if (w->attrib.override_redirect)
                  return FALSE;

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

            if (md->region)
            {
                  XDestroyRegion(md->region);
                  md->region = NULL;
            }

            md->status = RectangleOut;

            md->x = 0;
            md->y = 0;

            d->lastPointerX = x;
            d->lastPointerY = y;

            ms->origState = w->state;

            ms->snapBackY = w->serverY - workArea.y;
            ms->snapOffY = y - workArea.y;

            if (!ms->grabIndex)
                  ms->grabIndex = pushScreenGrab(w->screen, ms->moveCursor, "move");

            if (ms->grabIndex)
            {
                  md->w = w;

                  (w->screen->windowGrabNotify) (w, x, y, mods,
                                                               CompWindowGrabMoveMask
                                                               | CompWindowGrabButtonMask);

                  if (md->moveOpacity != OPAQUE &&
                        w->paint.opacity >= md->opacifyMinOpacity)
                  {
                        /* modify opacity of windows that are not active */
                        setWindowOpacity(w, md->moveOpacity, PL_TEMP_HELLO);
                        md->moveOpacitySet = True;
                  }
                  else
                        md->moveOpacitySet = False;
                  if (state & CompActionStateInitKey)
                  {
                        int xRoot, yRoot;

                        xRoot = w->attrib.x + (w->width / 2);
                        yRoot = w->attrib.y + (w->height / 2);

                        warpPointer(d, xRoot - d->pointerX, yRoot - d->pointerY);
                  }
            }
      }

      return FALSE;
}

static Bool
moveTerminate(CompDisplay * d,
                    CompAction * action,
                    CompActionState state, CompOption * option, int nOption)
{
      MOVE_DISPLAY(d);

      if (md->w)
      {
            MOVE_SCREEN(md->w->screen);

            (md->w->screen->windowUngrabNotify) (md->w);

            if (state & CompActionStateCancel)
                  moveWindow(md->w,
                                 md->w->serverX - md->w->attrib.x,
                                 md->w->serverY - md->w->attrib.y, TRUE, FALSE);

            syncWindowPosition(md->w);
            if (md->moveOpacitySet)
                  resetWindowOpacity(md->w, PL_TEMP_HELLO);
            damageScreen(md->w->screen);

            if (ms->grabIndex)
            {
                  removeScreenGrab(md->w->screen, ms->grabIndex, NULL);
                  ms->grabIndex = 0;
            }

            md->w = 0;
      }

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

      return FALSE;
}

static Region moveGetYConstrainRegion(CompScreen * s)
{
      CompWindow *w;
      Region region;
      REGION r;
      int i;

      region = XCreateRegion();
      if (!region)
            return NULL;

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

      r.extents.x1 = MINSHORT;
      r.extents.y1 = 0;
      r.extents.x2 = 0;
      r.extents.y2 = s->height;

      XUnionRegion(&r, region, region);

      r.extents.x1 = s->width;
      r.extents.x2 = MAXSHORT;

      XUnionRegion(&r, region, region);

      for (i = 0; i < s->nOutputDev; i++)
            XUnionRegion(&s->outputDev[i].region, region, region);

      for (w = s->windows; w; w = w->next)
      {
            if (!w->mapNum)
                  continue;

            if (w->struts)
            {
                  r.extents.x1 = w->struts->top.x;
                  r.extents.y1 = w->struts->top.y;
                  r.extents.x2 = r.extents.x1 + w->struts->top.width;
                  r.extents.y2 = r.extents.y1 + w->struts->top.height;

                  XSubtractRegion(region, &r, region);

                  r.extents.x1 = w->struts->bottom.x;
                  r.extents.y1 = w->struts->bottom.y;
                  r.extents.x2 = r.extents.x1 + w->struts->bottom.width;
                  r.extents.y2 = r.extents.y1 + w->struts->bottom.height;

                  XSubtractRegion(region, &r, region);
            }
      }

      return region;
}


static void moveHandleMotionEvent(CompScreen * s, int xRoot, int yRoot)
{
      MOVE_SCREEN(s);

      if (ms->grabIndex)
      {
            CompWindow *w;
            int dx, dy;

            MOVE_DISPLAY(s->display);

            w = md->w;
            md->x += xRoot - s->display->lastPointerX;
            md->y += yRoot - s->display->lastPointerY;

            if (md->w->syncWait)
                  return;

            if (w->type & CompWindowTypeFullscreenMask)
            {
                  dx = dy = 0;
            }
            else
            {
                  XRectangle workArea;
                  int min, max;
                  Bool constrainTop =
                              md->opt[MOVE_DISPLAY_OPTION_CONSTRAIN_Y_TOP].value.b;
                  Bool constrainBottom =
                              md->opt[MOVE_DISPLAY_OPTION_CONSTRAIN_Y_BOTTOM].value.b;

                  dx = md->x;
                  dy = md->y;

                  screenGetOutputDevWorkArea(s, screenGetOutputDevForWindow(w),
                                                         &workArea);

                  if (constrainTop || constrainBottom)
                  {
                        if (!md->region)
                              md->region = moveGetYConstrainRegion(s);

                        /* make sure that the top frame extents or the top row of
                           pixels are within what is currently our valid screen
                           region */
                        if (md->region)
                        {
                              int x, y, width, height;
                              int status;

                              if (constrainTop)
                              {
                                    y = w->attrib.y + dy - w->input.top;
                                    height = w->input.top ? w->input.top : 1;
                                    if (constrainBottom)
                                          height += w->height + w->input.bottom;
                              }
                              else /* if (constrainBottom) redundant */
                              {
                                    y = w->attrib.y + dy + w->height;
                                    height = w->input.bottom ? w->input.bottom : 1;
                              }

                              x = w->attrib.x + dx - w->input.left;
                              width = w->width + w->input.left + w->input.right;

                              status = XRectInRegion(md->region, x, y, width, height);

                              /* only constrain movement if previous position was valid */
                              if (md->status == RectangleIn)
                              {
                                    int xStatus = status;

                                    while (dx && xStatus != RectangleIn)
                                    {
                                          xStatus =
                                                      XRectInRegion(md->region, x, y - dy,
                                                                          width, height);

                                          if (xStatus != RectangleIn)
                                                dx += (dx < 0) ? 1 : -1;

                                          x = w->attrib.x + dx - w->input.left;
                                    }

                                    while (dy && status != RectangleIn)
                                    {
                                          status = XRectInRegion(md->region,
                                                                           x, y, width, height);

                                          if (status != RectangleIn)
                                                dy += (dy < 0) ? 1 : -1;

                                          y = w->attrib.y + dy +
                                                      (constrainTop ? (-w->input.top) : w->
                                                       height);
                                    }
                              }
                              else
                              {
                                    md->status = status;
                              }
                        }
                  }

                  if (md->opt[MOVE_DISPLAY_OPTION_SNAPOFF_MAXIMIZED].value.b)
                  {
                        if (w->state & CompWindowStateMaximizedVertMask)
                        {
                              if ((yRoot - workArea.y) -
                                    ms->snapOffY >=
                                    md->opt[MOVE_DISPLAY_OPTION_SNAPOFF_DISTANCE].value.i)
                              {
                                    XWindowChanges xwc;

                                    syncWindowPosition(w);

                                    xwc.x = w->serverX;
                                    xwc.y = w->serverY;
                                    xwc.width = w->serverWidth;
                                    xwc.height = w->serverHeight;

                                    restoreHorzRestoreData(w, &xwc);
                                    restoreVertRestoreData(w, &xwc);

                                    xwc.x = xRoot - (xwc.width >> 1);
                                    xwc.y = yRoot + (w->input.top >> 1);

                                    saveHorzRestoreData(w, &xwc);
                                    saveVertRestoreData(w, &xwc);

                                    md->x = md->y = 0;

                                    maximizeWindow(w, 0);

                                    ms->snapOffY = ms->snapBackY;

                                    return;
                              }
                        }
                        else if (ms->origState & CompWindowStateMaximizedVertMask)
                        {
                              if ((yRoot - workArea.y) -
                                    ms->snapBackY <
                                    md->
                                    opt[MOVE_DISPLAY_OPTION_SNAPBACK_DISTANCE].value.i)
                              {
                                    if (!otherScreenGrabExist(s, "move", 0))
                                    {
                                          int wy;

                                          /* update server position before maximizing window
                                             again so it is maximized on the correct output */
                                          syncWindowPosition(w);

                                          maximizeWindow(w, ms->origState);

                                          wy = workArea.y + (w->input.top >> 1);
                                          wy += w->sizeHints.height_inc >> 1;

                                          warpPointer(s->
                                                            display,
                                                            0, wy - s->display->pointerY);

                                          return;
                                    }
                              }
                        }
                  }

                  if (w->state & CompWindowStateMaximizedVertMask)
                  {
                        min = workArea.y + w->input.top;
                        max = workArea.y + workArea.height -
                                    w->input.bottom - w->serverHeight -
                                    w->serverBorderWidth * 2;

                        if (w->attrib.y + dy < min)
                              dy = min - w->attrib.y;
                        else if (w->attrib.y + dy > max)
                              dy = max - w->attrib.y;
                  }

                  if (w->state & CompWindowStateMaximizedHorzMask)
                  {
                        if (w->attrib.x + w->serverWidth + w->serverBorderWidth < 0)
                              return;

                        min = workArea.x + w->input.left;
                        max = workArea.x + workArea.width -
                                    w->input.right - w->serverWidth -
                                    w->serverBorderWidth * 2;

                        if (w->attrib.x + dx < min)
                              dx = min - w->attrib.x;
                        else if (w->attrib.x + dx > max)
                              dx = max - w->attrib.x;
                  }
            }

            moveWindow(md->w, dx, dy, TRUE, FALSE);

            damageScreen(s);

            md->x -= dx;
            md->y -= dy;
      }
}

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

      MOVE_DISPLAY(d);

      switch (event->type)
      {
      case ButtonPress:
      case ButtonRelease:
            s = findScreenAtDisplay(d, event->xbutton.root);
            if (s)
            {
                  MOVE_SCREEN(s);

                  if (ms->grabIndex)
                  {
                        moveTerminate(d,
                                            &md->
                                            opt
                                            [MOVE_DISPLAY_OPTION_INITIATE].
                                            value.action, 0, NULL, 0);
                  }
            }
            break;
      case KeyPress:
      case KeyRelease:
            s = findScreenAtDisplay(d, event->xkey.root);
            if (s)
            {
                  MOVE_SCREEN(s);

                  if (ms->grabIndex && event->type == KeyPress)
                  {
                        int i;

                        for (i = 0; i < NUM_KEYS; i++)
                        {
                              if (event->xkey.keycode == md->key[i])
                              {
                                    XWarpPointer(d->display,
                                                       None, None, 0,
                                                       0, 0, 0,
                                                       mKeys[i].dx *
                                                       KEY_MOVE_INC,
                                                       mKeys[i].dy * KEY_MOVE_INC);
                                    break;
                              }
                        }
                  }
            }
            break;
      case MotionNotify:
            s = findScreenAtDisplay(d, event->xmotion.root);
            if (s)
                  moveHandleMotionEvent(s, d->pointerX, d->pointerY);
            break;
      case EnterNotify:
      case LeaveNotify:
            s = findScreenAtDisplay(d, event->xcrossing.root);
            if (s)
                  moveHandleMotionEvent(s, d->pointerX, d->pointerY);
            break;
      case ClientMessage:
            if (event->xclient.message_type == d->wmMoveResizeAtom)
            {
                  CompWindow *w;

                  if (event->xclient.data.l[2] == WmMoveResizeMove ||
                        event->xclient.data.l[2] == WmMoveResizeMoveKeyboard)
                  {
                        w = findWindowAtDisplay(d, event->xclient.window);
                        if (w)
                        {
                              CompOption o[4];
                              int xRoot, yRoot;
                              CompAction *action =
                                          &md->opt[MOVE_DISPLAY_OPTION_INITIATE].value.
                                          action;

                              o[0].type = CompOptionTypeInt;
                              o[0].name = "window";
                              o[0].value.i = event->xclient.window;

                              if (event->xclient.data.l[2] == WmMoveResizeMoveKeyboard)
                              {
                                    moveInitiate(d, action, CompActionStateInitKey, o, 1);
                              }
                              else
                              {
                                    unsigned int mods;
                                    Window root, child;
                                    int i;

                                    XQueryPointer(d->display,
                                                        w->screen->
                                                        root, &root,
                                                        &child, &xRoot, &yRoot, &i, &i, &mods);

                                    /* TODO: not only button 1 */
                                    if (mods & Button1Mask)
                                    {
                                          o[1].type = CompOptionTypeInt;
                                          o[1].name = "modifiers";
                                          o[1].value.i = mods;

                                          o[2].type = CompOptionTypeInt;
                                          o[2].name = "x";
                                          o[2].value.i = event->xclient.data.l[0];

                                          o[3].type = CompOptionTypeInt;
                                          o[3].name = "y";
                                          o[3].value.i = event->xclient.data.l[1];

                                          moveInitiate(d,
                                                             action,
                                                             CompActionStateInitButton, o, 4);

                                          moveHandleMotionEvent(w->screen, xRoot, yRoot);
                                    }
                              }
                        }
                  }
            }
            break;
      case DestroyNotify:
            if (md->w && md->w->id == event->xdestroywindow.window)
                  moveTerminate(d,
                                      &md->
                                      opt[MOVE_DISPLAY_OPTION_INITIATE].
                                      value.action, 0, NULL, 0);
            break;
      case UnmapNotify:
            if (md->w && md->w->id == event->xunmap.window)
                  moveTerminate(d,
                                      &md->
                                      opt[MOVE_DISPLAY_OPTION_INITIATE].
                                      value.action, 0, NULL, 0);
      default:
            break;
      }

      UNWRAP(md, d, handleEvent);
      (*d->handleEvent) (d, event);
      WRAP(md, d, handleEvent, moveHandleEvent);
}

static void moveDisplayInitOptions(MoveDisplay * md)
{
      CompOption *o;

      o = &md->opt[MOVE_DISPLAY_OPTION_INITIATE];
      o->advanced = False;
      o->name = "initiate";
      o->group = N_("Bindings");
      o->subGroup = N_("Move window");
      o->displayHints = "";
      o->shortDesc = N_("Initiate Window Move");
      o->longDesc = N_("Start moving Window.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = moveInitiate;
      o->value.action.terminate = moveTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.type = CompBindingTypeButton;
      o->value.action.state = CompActionStateInitButton;
      o->value.action.button.modifiers = MOVE_INITIATE_BUTTON_MODIFIERS_DEFAULT;
      o->value.action.button.button = MOVE_INITIATE_BUTTON_DEFAULT;
      o->value.action.type |= CompBindingTypeKey;
      o->value.action.state |= CompActionStateInitKey;
      o->value.action.key.modifiers = MOVE_INITIATE_KEY_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(MOVE_INITIATE_KEY_DEFAULT);

      o = &md->opt[MOVE_DISPLAY_OPTION_OPACIFY_MIN_OPACITY];
      o->advanced = False;
      o->name = "opacify_min_opacity";
      o->group = N_("Appearance");
      o->subGroup = N_("Opacity");
      o->displayHints = "";
      o->shortDesc = N_("Minimum Opacity for Opacify");
      o->longDesc =
                  N_
                  ("Opacify only windows whose Opacity is higher than this value.");
      o->type = CompOptionTypeInt;
      o->value.i = MOVE_OPACIFY_MIN_OPACITY_DEFAULT;
      o->rest.i.min = MOVE_OPACIFY_MIN_OPACITY_MIN;
      o->rest.i.max = MOVE_OPACIFY_MIN_OPACITY_MAX;

      o = &md->opt[MOVE_DISPLAY_OPTION_OPACITY];
      o->advanced = False;
      o->name = "opacity";
      o->group = N_("Appearance");
      o->subGroup = N_("Opacity");
      o->displayHints = "";
      o->shortDesc = N_("Opacity");
      o->longDesc = N_("Opacity level of Moving windows.");
      o->type = CompOptionTypeInt;
      o->value.i = MOVE_OPACITY_DEFAULT;
      o->rest.i.min = MOVE_OPACITY_MIN;
      o->rest.i.max = MOVE_OPACITY_MAX;

      o = &md->opt[MOVE_DISPLAY_OPTION_CONSTRAIN_Y_TOP];
      o->advanced = False;
      o->name = "constrain_y_top";
      o->group = N_("Misc. options");
      o->subGroup = N_("Movement constraints");
      o->displayHints = "";
      o->shortDesc = N_("Constrain Y to Top of Screen");
      o->longDesc =
                  N_("Prevent windows from Moving over the Top of the Screen.");
      o->type = CompOptionTypeBool;
      o->value.b = MOVE_CONSTRAIN_Y_TOP_DEFAULT;

      o = &md->opt[MOVE_DISPLAY_OPTION_CONSTRAIN_Y_BOTTOM];
      o->advanced = False;
      o->name = "constrain_y_bottom";
      o->group = N_("Misc. options");
      o->subGroup = N_("Movement constraints");
      o->displayHints = "";
      o->shortDesc = N_("Constrain Y to Bottom of Screen");
      o->longDesc =
                  N_("Prevent windows from Moving past the Bottom of the Screen.");
      o->type = CompOptionTypeBool;
      o->value.b = MOVE_CONSTRAIN_Y_BOTTOM_DEFAULT;

      o = &md->opt[MOVE_DISPLAY_OPTION_SNAPOFF_MAXIMIZED];
      o->advanced = False;
      o->name = "snapoff_maximized";
      o->group = N_("Misc. options");
      o->subGroup = N_("Snapoff/snapback");
      o->displayHints = "";
      o->shortDesc = N_("Snapoff Maximized Windows");
      o->longDesc = N_("Snap off and unMaximize Maximized Windows "
                               "when dragging.");
      o->type = CompOptionTypeBool;
      o->value.b = MOVE_SNAPOFF_MAXIMIZED_DEFAULT;

      o = &md->opt[MOVE_DISPLAY_OPTION_SNAPOFF_DISTANCE];
      o->advanced = False;
      o->name = "snapoff_distance";
      o->group = N_("Misc. options");
      o->subGroup = N_("Snapoff/snapback");
      o->displayHints = "";
      o->shortDesc = N_("Snapoff Distance");
      o->longDesc =
                  N_("Pointer movement Distance after which window is Snapped off.");
      o->type = CompOptionTypeInt;
      o->value.i = MOVE_SNAPOFF_DISTANCE_DEFAULT;
      o->rest.i.min = MOVE_SNAPOFF_DISTANCE_MIN;
      o->rest.i.max = MOVE_SNAPOFF_DISTANCE_MAX;

      o = &md->opt[MOVE_DISPLAY_OPTION_SNAPBACK_DISTANCE];
      o->advanced = False;
      o->name = "snapback_distance";
      o->group = N_("Misc. options");
      o->subGroup = N_("Snapoff/snapback");
      o->displayHints = "";
      o->shortDesc = N_("Snapback Distance");
      o->longDesc = N_("Pointer movement Distance to Snap window back.");
      o->type = CompOptionTypeInt;
      o->value.i = MOVE_SNAPBACK_DISTANCE_DEFAULT;
      o->rest.i.min = MOVE_SNAPBACK_DISTANCE_MIN;
      o->rest.i.max = MOVE_SNAPBACK_DISTANCE_MAX;
}

static CompOption *moveGetDisplayOptions(CompDisplay * display, int *count)
{
      if (display)
      {
            MOVE_DISPLAY(display);

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

            moveDisplayInitOptions(md);
            *count = NUM_OPTIONS(md);
            return md->opt;
      }
}

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

      MOVE_DISPLAY(display);

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

      switch (index)
      {
      case MOVE_DISPLAY_OPTION_INITIATE:
            if (setDisplayAction(display, o, value))
                  return TRUE;
            break;
      case MOVE_DISPLAY_OPTION_OPACITY:
            if (compSetIntOption(o, value))
            {
                  md->moveOpacity = (o->value.i * OPAQUE) / 100;
                  return TRUE;
            }
            break;
      case MOVE_DISPLAY_OPTION_OPACIFY_MIN_OPACITY:
            if (compSetIntOption(o, value))
            {
                  md->opacifyMinOpacity = (o->value.i * OPAQUE) / 100;
                  return TRUE;
            }
            break;
      case MOVE_DISPLAY_OPTION_SNAPOFF_DISTANCE:
      case MOVE_DISPLAY_OPTION_SNAPBACK_DISTANCE:
            if (compSetIntOption(o, value))
                  return TRUE;
            break;
      case MOVE_DISPLAY_OPTION_CONSTRAIN_Y_TOP:
      case MOVE_DISPLAY_OPTION_CONSTRAIN_Y_BOTTOM:
      case MOVE_DISPLAY_OPTION_SNAPOFF_MAXIMIZED:
            if (compSetBoolOption(o, value))
                  return TRUE;
            break;
      default:
            break;
      }

      return FALSE;
}

static Bool moveInitDisplay(CompPlugin * p, CompDisplay * d)
{
      MoveDisplay *md;
      int i;

      md = malloc(sizeof(MoveDisplay));
      if (!md)
            return FALSE;

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

      md->moveOpacity = (MOVE_OPACITY_DEFAULT * OPAQUE) / 100;

      md->opacifyMinOpacity = (MOVE_OPACIFY_MIN_OPACITY_DEFAULT * OPAQUE) / 100;

      moveDisplayInitOptions(md);

      md->w = 0;
      md->region = NULL;

      for (i = 0; i < NUM_KEYS; i++)
            md->key[i] = XKeysymToKeycode(d->display,
                                                        XStringToKeysym(mKeys[i].name));

      WRAP(md, d, handleEvent, moveHandleEvent);

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

      return TRUE;
}

static void moveFiniDisplay(CompPlugin * p, CompDisplay * d)
{
      MOVE_DISPLAY(d);

      freeScreenPrivateIndex(d, md->screenPrivateIndex);

      UNWRAP(md, d, handleEvent);

      free(md);
}

static Bool moveInitScreen(CompPlugin * p, CompScreen * s)
{
      MoveScreen *ms;

      MOVE_DISPLAY(s->display);

      ms = malloc(sizeof(MoveScreen));
      if (!ms)
            return FALSE;

      ms->grabIndex = 0;

      ms->moveCursor = XCreateFontCursor(s->display->display, XC_fleur);

      addScreenAction(s, &md->opt[MOVE_DISPLAY_OPTION_INITIATE].value.action);

      s->privates[md->screenPrivateIndex].ptr = ms;

      return TRUE;
}

static void moveFiniScreen(CompPlugin * p, CompScreen * s)
{
      MOVE_SCREEN(s);
      MOVE_DISPLAY(s->display);

      removeScreenAction(s,
                                 &md->opt[MOVE_DISPLAY_OPTION_INITIATE].value.action);

      XFreeCursor(s->display->display, ms->moveCursor);

      free(ms);
}

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

      return TRUE;
}

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

CompPluginVTable moveVTable = {
      "move",
      N_("Move Window"),
      N_("Move window"),
      moveInit,
      moveFini,
      moveInitDisplay,
      moveFiniDisplay,
      moveInitScreen,
      moveFiniScreen,
      0,                                        /* InitWindow */
      0,                                        /* FiniWindow */
      moveGetDisplayOptions,
      moveSetDisplayOption,
      0,                                        /* GetScreenOptions */
      0,                                        /* SetScreenOption */
      NULL,
      0,
      0,
      0,
      BERYL_ABI_INFO,
      "beryl-plugins",
      "wm",
      0,
      0,
      True,
};

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

Generated by  Doxygen 1.6.0   Back to index