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

showdesktop.c

/*
 *
 * 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.
 *
 * Authors:
 *   - Diogo Ferreira (playerX) <diogo@beryl-project.org>
 *
 *
 * Copyright (c) 2007 Diogo "playerX" Ferreira
 *
 * This wouldn't have been possible without:
 *   - Ideas from the compiz community (mainly throughnothing's)
 *   - David Reveman's work
 *
 * */

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

#include <beryl.h>
#include <beryl_ipcs.h>

#include <math.h>

#define WIN_X(w) ((w)->attrib.x - (w)->input.left)
#define WIN_Y(w) ((w)->attrib.y - (w)->input.top)
#define WIN_W(w) ((w)->width + (w)->input.left + (w)->input.right)
#define WIN_H(w) ((w)->height + (w)->input.top + (w)->input.bottom)

#define OFF_LEFT(w) ((w)->width + (w)->input.right)
#define OFF_RIGHT(w) ((w)->input.left)
#define OFF_TOP(w) ((w)->height + (w)->input.bottom)
#define OFF_BOTTOM(w) ((w)->input.top)

#define MOVE_LEFT(w) ((WIN_X(w) + (WIN_W(w)/2)) < ((w)->screen->width/2))
#define MOVE_UP(w) ((WIN_Y(w) + (WIN_H(w)/2)) < ((w)->screen->height/2))

#define SD_INITIATE_KEY_DEFAULT         "F6"
#define SD_INITIATE_MODIFIERS_DEFAULT   0

#define SD_DISPLAY_OPTION_INITIATE  0
#define SD_DISPLAY_OPTION_NUM       1

#define SD_SCREEN_OPTION_SPEED              0
#define SD_SCREEN_OPTION_TIMESTEP           1
#define SD_SCREEN_OPTION_DIRECTION          2
#define SD_SCREEN_OPTION_WINDOW_TYPE        3
#define SD_SCREEN_OPTION_USE_SCALE_SETTINGS 4
#define SD_SCREEN_OPTION_WINDOW_OPACITY     5
#define SD_SCREEN_OPTION_WINDOW_PART_SIZE 6
#define SD_SCREEN_OPTION_NUM                7

typedef enum _SdDirection
{
      SdDirectionUp,
      SdDirectionDown,
      SdDirectionLeft,
      SdDirectionRight,
      SdDirectionUpDown,
      SdDirectionLeftRight,
      SdDirectionCorners,
} SdDirection;

char *sdDirections[] = {
      N_("Up"),
      N_("Down"),
      N_("Left"),
      N_("Right"),
      N_("UpDown"),
      N_("LeftRight"),
      N_("Corners"),
};

#define SD_DIRECTION_DEFAULT SdDirectionCorners
#define NUM_SD_DIRECTIONS 7

#define SD_SPEED_DEFAULT        1.2f
#define SD_SPEED_MIN            0.1f
#define SD_SPEED_MAX            50.0f
#define SD_SPEED_PRECISION      0.1f

#define SD_TIMESTEP_DEFAULT   0.1f
#define SD_TIMESTEP_MIN       0.1f
#define SD_TIMESTEP_MAX       50.0f
#define SD_TIMESTEP_PRECISION 0.1f

#define SD_USE_SCALE_SETTINGS_DEFAULT FALSE

#define SD_WINDOW_OPACITY_DEFAULT   0.3
#define SD_WINDOW_OPACITY_MIN       0.1
#define SD_WINDOW_OPACITY_MAX       1.0
#define SD_WINDOW_OPACITY_PRECISION 0.01

#define SD_WINDOW_PART_SIZE_DEFAULT 20
#define SD_WINDOW_PART_SIZE_MIN 0
#define SD_WINDOW_PART_SIZE_MAX 300

#define SD_STATE_OFF          0
#define SD_STATE_ACTIVATING   1
#define SD_STATE_ON           2
#define SD_STATE_DEACTIVATING 3

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

/* window types */
static char *winType[] = {
      N_("Toolbar"),
      N_("Utility"),
      N_("Dialog"),
      N_("ModalDialog"),
      N_("Fullscreen"),
      N_("Normal")
};

#define N_WIN_TYPE (sizeof (winType) / sizeof (winType[0]))

/* necessary plugin structs */
typedef struct _ShowdesktopPlacer
{
      int placed;
      int onScreenX, onScreenY;
      int offScreenX, offScreenY;
      int origViewportX;
      int origViewportY;
} ShowdesktopPlacer;
typedef struct _ShowdesktopDisplay
{
      int screenPrivateIndex;
      CompOption opt[SD_DISPLAY_OPTION_NUM];

      HandleEventProc handleEvent;
} ShowdesktopDisplay;
typedef struct _ShowdesktopScreen
{
      int windowPrivateIndex;

      PreparePaintScreenProc preparePaintScreen;
      DonePaintScreenProc donePaintScreen;
      SetScreenOptionForPluginProc setScreenOptionForPlugin;

      CompOption opt[SD_SCREEN_OPTION_NUM];

      int state;
      int moreAdjust;

      float speed;
      float timestep;
      float windowOpacity;
      int windowPartSize;

      int direction;
      int wMask;

      int sdActiveAtom;
      int grabIndex;

      Bool ignoreNextTerminateEvent;
} ShowdesktopScreen;
typedef struct _ShowdesktopWindow
{
      int sid;
      int distance;

      ShowdesktopPlacer placer;

      GLfloat xVelocity, yVelocity;
      GLfloat tx, ty;
      GLfloat oldOpacity;

      float delta;
      Bool adjust;
} ShowdesktopWindow;

/* shortcut macros, usually named X_DISPLAY, X_SCREEN and X_WINDOW
 * these might seem overly complicated but they are shortcuts so we don't have to access the privates arrays all the time
 * */
#define GET_SHOWDESKTOP_DISPLAY(d)                         \
    ((ShowdesktopDisplay *) (d)->privates[displayPrivateIndex].ptr)

#define SD_DISPLAY(d)                  \
    ShowdesktopDisplay *sd = GET_SHOWDESKTOP_DISPLAY (d)

#define GET_SHOWDESKTOP_SCREEN(s, fd)                              \
    ((ShowdesktopScreen *) (s)->privates[(fd)->screenPrivateIndex].ptr)

#define SD_SCREEN(s)                                        \
    ShowdesktopScreen *ss = GET_SHOWDESKTOP_SCREEN (s, GET_SHOWDESKTOP_DISPLAY (s->display))

#define GET_SHOWDESKTOP_WINDOW(w, ss)                               \
    ((ShowdesktopWindow *) (w)->privates[(ss)->windowPrivateIndex].ptr)

#define SD_WINDOW(w)                                   \
    ShowdesktopWindow *sw = GET_SHOWDESKTOP_WINDOW  (w,                  \
            GET_SHOWDESKTOP_SCREEN  (w->screen,        \
                GET_SHOWDESKTOP_DISPLAY (w->screen->display)))
/* plugin private index */
static int displayPrivateIndex;


/* non interfacing code, aka the logic of the plugin */
static Bool isSDWin(CompWindow * w)
{
      SD_SCREEN(w->screen);

      if (!(*w->screen->focusWindow) (w))
            return FALSE;

      if (!(ss->wMask & w->type))
            return FALSE;

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

      if (w->state & CompWindowStateSkipPagerMask)
            return FALSE;

      return TRUE;
}

static Bool
showdesktopTerminate(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)
      {
            SD_SCREEN(s);

            if (ss->state == SD_STATE_ON || ss->state == SD_STATE_ACTIVATING)
            {
                  CompWindow *w;

                  for (w = s->windows; w; w = w->next)
                  {
                        SD_WINDOW(w);
                        if (sw->placer.placed)
                        {
                              sw->adjust = TRUE;
                              sw->xVelocity = sw->yVelocity = 0.0f;
                              w->paint.opacity = sw->oldOpacity;
                              /* adjust onscreen position to 
                                 handle viewport changes
                               */
                              sw->placer.onScreenX += (sw->placer.origViewportX - 
                                          w->screen->x) * w->screen->width;
                              sw->placer.onScreenY += (sw->placer.origViewportY -
                                          w->screen->y) * w->screen->height;
                        }
                  }
                  ss->state = SD_STATE_DEACTIVATING;

                  if (ss->grabIndex)
                        removeScreenGrab(s, ss->grabIndex, NULL);
                  ss->grabIndex = pushScreenGrab(s, s->invisibleCursor, "showdesktop");
            }
            focusDefaultWindow(s->display);
      }
      return FALSE;
}

static void repositionSDPlacer(CompWindow * w, int oldState)
{
      SD_SCREEN(w->screen);
      SD_WINDOW(w);

      if (oldState == SD_STATE_OFF)
      {
            sw->placer.onScreenX = w->attrib.x;
            sw->placer.onScreenY = w->attrib.y;
            sw->placer.origViewportX = w->screen->x;
            sw->placer.origViewportY = w->screen->y;
      }

      switch (ss->direction)
      {
      case SdDirectionUp:
            sw->placer.offScreenX = w->attrib.x;
            sw->placer.offScreenY =
                        w->screen->workArea.y - OFF_TOP(w) + ss->windowPartSize;
            break;
      case SdDirectionDown:
            sw->placer.offScreenX = w->attrib.x;
            sw->placer.offScreenY =
                        w->screen->workArea.y + w->screen->workArea.height +
                        OFF_BOTTOM(w) - ss->windowPartSize;
            break;
      case SdDirectionLeft:
            sw->placer.offScreenX =
                        w->screen->workArea.x - OFF_LEFT(w) + ss->windowPartSize;
            sw->placer.offScreenY = w->attrib.y;
            break;
      case SdDirectionRight:
            sw->placer.offScreenX =
                        w->screen->workArea.x + w->screen->workArea.width +
                        OFF_RIGHT(w) - ss->windowPartSize;
            sw->placer.offScreenY = w->attrib.y;
            break;
      case SdDirectionUpDown:
            sw->placer.offScreenX = w->attrib.x;
            if (MOVE_UP(w))
                  sw->placer.offScreenY =
                              w->screen->workArea.y - OFF_TOP(w) + ss->windowPartSize;
            else
                  sw->placer.offScreenY =
                              w->screen->workArea.y +
                              w->screen->workArea.height + OFF_BOTTOM(w) -
                              ss->windowPartSize;
            break;
      case SdDirectionLeftRight:
            sw->placer.offScreenY = w->attrib.y;
            if (MOVE_LEFT(w))
                  sw->placer.offScreenX =
                              w->screen->workArea.x - OFF_LEFT(w) + ss->windowPartSize;
            else
                  sw->placer.offScreenX =
                              w->screen->workArea.x +
                              w->screen->workArea.width + OFF_RIGHT(w) -
                              ss->windowPartSize;
            break;
      case SdDirectionCorners:
            if (MOVE_LEFT(w))
                  sw->placer.offScreenX =
                              w->screen->workArea.x - OFF_LEFT(w) + ss->windowPartSize;
            else
                  sw->placer.offScreenX =
                              w->screen->workArea.x +
                              w->screen->workArea.width + OFF_RIGHT(w) -
                              ss->windowPartSize;
            if (MOVE_UP(w))
                  sw->placer.offScreenY =
                              w->screen->workArea.y - OFF_TOP(w) + ss->windowPartSize;
            else
                  sw->placer.offScreenY =
                              w->screen->workArea.y +
                              w->screen->workArea.height + OFF_BOTTOM(w) -
                              ss->windowPartSize;
            break;
      }
}

static Bool prepareSDWindows(CompScreen * s, int oldState)
{
      CompWindow *w;
      CompWindow *desktopWindow;

      SD_SCREEN(s);

      desktopWindow = 0;

      for (w = s->windows; w; w = w->next)
      {
            SD_WINDOW(w);

            if (getWindowType(s->display, w->id) == CompWindowTypeDesktopMask)
                  desktopWindow = w;

            if (!isSDWin(w))
                  continue;

            if (sw->placer.placed)
            {
                  sw->tx = sw->ty = 0;
                  syncWindowPosition(w);
                  sw->placer.placed = FALSE;
            }

            repositionSDPlacer(w, oldState);

            sw->tx = sw->ty = sw->xVelocity = sw->yVelocity = 0.0f;
            sw->adjust = TRUE;
            sw->placer.placed = TRUE;

            sw->oldOpacity = w->paint.opacity;
            w->paint.opacity = ss->windowOpacity * OPAQUE;
      }

      if (desktopWindow)
            activateWindow(desktopWindow);

      return TRUE;
}

static Bool
showdesktopInitiate(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 && !otherScreenGrabExist(s, 0))
      {
            SD_SCREEN(s);

            if (ss->state == SD_STATE_OFF || ss->state == SD_STATE_DEACTIVATING)
            {
                  if (prepareSDWindows(s, ss->state))
                  {
                        XSetInputFocus(d->display,
                                             d->screens->root,
                                             RevertToPointerRoot, CurrentTime);
                        ss->state = SD_STATE_ACTIVATING;
                        IPCS_SetBool(IPCS_OBJECT(s), ss->sdActiveAtom, TRUE);

                        if (ss->grabIndex)
                              removeScreenGrab(s, ss->grabIndex, NULL);
                        ss->grabIndex = pushScreenGrab(s, s->invisibleCursor, "showdesktop");
                  }
                  if (state & CompActionStateInitButton)
                        action->state |= CompActionStateTermButton;

                  if (state & CompActionStateInitKey)
                        action->state |= CompActionStateTermKey;
            }
            else
            {
                  return showdesktopTerminate(d, action, state, option, nOption);
            }
      }

      return FALSE;
}

/* gconf entries */
static void showdesktopDisplayInitOptions(ShowdesktopDisplay * sd)
{
      CompOption *o;

      o = &sd->opt[SD_DISPLAY_OPTION_INITIATE];
      o->advanced = False;
      o->name = "initiate";
      o->group = N_("Binding");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Initiate showdesktop mode");
      o->longDesc = N_("Initiate showdesktop mode");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = showdesktopInitiate;
      o->value.action.terminate = showdesktopInitiate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = (1 << SCREEN_EDGE_BOTTOMRIGHT);
      o->value.action.state = CompActionStateInitEdge;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.state |= CompActionStateInitKey;
      o->value.action.key.modifiers = SD_INITIATE_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(SD_INITIATE_KEY_DEFAULT);
}

static void showdesktopScreenInitOptions(ShowdesktopScreen * ss)
{
      CompOption *o;
      int i;

      o = &ss->opt[SD_SCREEN_OPTION_SPEED];
      o->advanced = False;
      o->name = "speed";
      o->group = N_("Misc. Options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Speed");
      o->longDesc = N_("Window speed");
      o->type = CompOptionTypeFloat;
      o->value.f = SD_SPEED_DEFAULT;
      o->rest.f.min = SD_SPEED_MIN;
      o->rest.f.max = SD_SPEED_MAX;
      o->rest.f.precision = SD_SPEED_PRECISION;

      o = &ss->opt[SD_SCREEN_OPTION_TIMESTEP];
      o->advanced = False;
      o->name = "timestep";
      o->group = N_("Misc. Options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Timestep");
      o->longDesc = N_("Showdesktop timestep");
      o->type = CompOptionTypeFloat;
      o->value.f = SD_TIMESTEP_DEFAULT;
      o->rest.f.min = SD_TIMESTEP_MIN;
      o->rest.f.max = SD_TIMESTEP_MAX;
      o->rest.f.precision = SD_TIMESTEP_PRECISION;

      o = &ss->opt[SD_SCREEN_OPTION_DIRECTION];
      o->advanced = False;
      o->name = "direction";
      o->group = N_("Behaviour");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Window direction");
      o->longDesc =
                  N_
                  ("0 - Up, 1 - Down, 2 - Left, 3 - Right, 4 - Up/Down, 5 - Left/Right");
      o->type = CompOptionTypeString;
      o->value.s = strdup(sdDirections[SD_DIRECTION_DEFAULT]);
      o->rest.s.string = sdDirections;
      o->rest.s.nString = NUM_SD_DIRECTIONS;

      o = &ss->opt[SD_SCREEN_OPTION_WINDOW_TYPE];
      o->advanced = False;
      o->name = "window_types";
      o->group = N_("Behaviour");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Window Types");
      o->longDesc = N_("Window types that should go away in showdesktop mode");
      o->type = CompOptionTypeList;
      o->value.list.type = CompOptionTypeString;
      o->value.list.nValue = N_WIN_TYPE;
      o->value.list.value = malloc(sizeof(CompOptionValue) * N_WIN_TYPE);
      for (i = 0; i < N_WIN_TYPE; i++)
            o->value.list.value[i].s = strdup(winType[i]);
      o->rest.s.string = (char **)windowTypeString;
      o->rest.s.nString = nWindowTypeString;
      ss->wMask = compWindowTypeMaskFromStringList(&o->value);

      o = &ss->opt[SD_SCREEN_OPTION_USE_SCALE_SETTINGS];
      o->advanced = False;
      o->name = "use_scale_settings";
      o->group = N_("Misc. Options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Use scale settings");
      o->longDesc =
                  N_
                  ("Use scale speed/timestep settings instead of the ones specified here");
      o->type = CompOptionTypeBool;
      o->value.b = SD_USE_SCALE_SETTINGS_DEFAULT;

      o = &ss->opt[SD_SCREEN_OPTION_WINDOW_OPACITY];
      o->advanced = False;
      o->name = "window_opacity";
      o->group = N_("Appearance");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Window opacity when showdesktop'd");
      o->longDesc = N_("Window opacity when showdesktop'd");
      o->type = CompOptionTypeFloat;
      o->value.f = SD_WINDOW_OPACITY_DEFAULT;
      o->rest.f.min = SD_WINDOW_OPACITY_MIN;
      o->rest.f.max = SD_WINDOW_OPACITY_MAX;
      o->rest.f.precision = SD_WINDOW_OPACITY_PRECISION;

      o = &ss->opt[SD_SCREEN_OPTION_WINDOW_PART_SIZE];
      o->advanced = False;
      o->name = "window_part_size";
      o->group = N_("Appearance");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Window part size when showdesktop'd");
      o->longDesc = N_("Window part size when showdesktop'd");
      o->type = CompOptionTypeInt;
      o->value.i = SD_WINDOW_PART_SIZE_DEFAULT;
      o->rest.i.min = SD_WINDOW_PART_SIZE_MIN;
      o->rest.i.max = SD_WINDOW_PART_SIZE_MAX;
}

/* plugin initialization */

static Bool showdesktopInit(CompPlugin * p)
{
      displayPrivateIndex = allocateDisplayPrivateIndex();

      if (displayPrivateIndex < 0)
            return FALSE;

      return TRUE;
}

/* plugin finalization */
static void showdesktopFini(CompPlugin * p)
{

      if (displayPrivateIndex >= 0)
            freeDisplayPrivateIndex(displayPrivateIndex);
}

/* Handle event function
 * I have intentions of using this in the future
 **/
static void showdesktopHandleEvent(CompDisplay * d, XEvent * event)
{
      SD_DISPLAY(d);
      CompWindow *w;

      switch (event->type)
      {
      case DestroyNotify:
            w = findWindowAtDisplay(d, event->xdestroywindow.window);
            if (w)
            {
                  SD_SCREEN(w->screen);
                  ss->ignoreNextTerminateEvent = TRUE;
            }
            break;
      case ReparentNotify:
      {
            w = findWindowAtDisplay(d, event->xreparent.window);
            if (w)
            {
                  SD_SCREEN(w->screen);
                  ss->ignoreNextTerminateEvent = TRUE;
            }
            break;
      }
      case FocusIn:
      {

            w = findWindowAtDisplay(d, event->xfocus.window);

            if (w && w->managed && w->id != d->activeWindow)
            {
                  SD_SCREEN(w->screen);
                  SD_WINDOW(w);

                  if (ss->ignoreNextTerminateEvent)
                  {
                        ss->ignoreNextTerminateEvent = FALSE;
                        break;
                  }

                  if (sw->placer.placed
                        && (ss->state == SD_STATE_ON
                              || ss->state == SD_STATE_ACTIVATING))
                  {
                        CompOption o[1];

                        o[0].type = CompOptionTypeInt;
                        o[0].name = "root";
                        o[0].value.i = w->screen->root;

                        showdesktopTerminate(d, NULL, 0, o, 1);
                  }
            }
            break;
      }
      }


      UNWRAP(sd, d, handleEvent);
      (*d->handleEvent) (d, event);
      WRAP(sd, d, handleEvent, showdesktopHandleEvent);
}

/* adjust velocity for each animation step (adapted from the scale plugin) */
static int adjustSDVelocity(CompWindow * w)
{
      float dx, dy, adjust, amount;
      float x1, y1;

      SD_WINDOW(w);
      SD_SCREEN(w->screen);

      x1 = y1 = 0.0;

      if (!sw->placer.placed)
            return 0;

      if (ss->state == SD_STATE_ACTIVATING)
      {
            x1 = sw->placer.offScreenX;
            y1 = sw->placer.offScreenY;
      }
      else if (ss->state == SD_STATE_DEACTIVATING)
      {
            x1 = sw->placer.onScreenX;
            y1 = sw->placer.onScreenY;
      }

      dx = x1 - (w->serverX + sw->tx);

      adjust = dx * 0.15f;
      amount = fabs(dx) * 1.5f;
      if (amount < 0.5f)
            amount = 0.5f;
      else if (amount > 5.0f)
            amount = 5.0f;

      sw->xVelocity = (amount * sw->xVelocity + adjust) / (amount + 1.0f);

      dy = y1 - (w->serverY + sw->ty);

      adjust = dy * 0.15f;
      amount = fabs(dy) * 1.5f;
      if (amount < 0.5f)
            amount = 0.5f;
      else if (amount > 5.0f)
            amount = 5.0f;

      sw->yVelocity = (amount * sw->yVelocity + adjust) / (amount + 1.0f);

      if (fabs(dx) < 0.1f && fabs(sw->xVelocity) < 0.2f &&
            fabs(dy) < 0.1f && fabs(sw->yVelocity) < 0.2f)
      {
            sw->xVelocity = sw->yVelocity = 0.0f;
            sw->tx = x1 - w->serverX;
            sw->ty = y1 - w->serverY;

            return 0;
      }
      return 1;
}

/* this function gets called periodically (about every 15ms on this machine),
 * animation takes place here */
static void
showdesktopPreparePaintScreen(CompScreen * s, int msSinceLastPaint)
{
      SD_SCREEN(s);

      if ((ss->state != SD_STATE_OFF) && screenGrabExist(s, "scale", 0))
      {
            CompOption o[1];

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

            showdesktopTerminate(s->display, NULL, 0, o, 1);
      }

      UNWRAP(ss, s, preparePaintScreen);
      (*s->preparePaintScreen) (s, msSinceLastPaint);
      WRAP(ss, s, preparePaintScreen, showdesktopPreparePaintScreen);

      if (ss->state == SD_STATE_ACTIVATING
            || ss->state == SD_STATE_DEACTIVATING)
      {
            CompWindow *w;
            int steps, dx, dy;
            float amount, chunk;

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

            while (steps--)
            {
                  ss->moreAdjust = 0;

                  for (w = s->windows; w; w = w->next)
                  {
                        SD_WINDOW(w);

                        if (sw->placer.placed && sw->adjust)
                        {
                              sw->adjust = adjustSDVelocity(w);

                              ss->moreAdjust |= sw->adjust;

                              sw->tx += sw->xVelocity * chunk;
                              sw->ty += sw->yVelocity * chunk;

                              dx = (w->serverX + sw->tx) - w->attrib.x;
                              dy = (w->serverY + sw->ty) - w->attrib.y;

                              moveWindow(w, dx, dy, FALSE, FALSE);
                        }
                  }
                  if (!ss->moreAdjust)
                        break;
            }

      }
}

/* this one gets called after the one above and periodically,
 * here the plugin checks if windows reached the end */
static void showdesktopDonePaintScreen(CompScreen * s)
{
      SD_SCREEN(s);

      if (ss->moreAdjust)
      {
            damageScreen(s);
      }
      else
      {
            if (ss->state == SD_STATE_ACTIVATING
                  || ss->state == SD_STATE_DEACTIVATING)
            {
                  CompWindow *w;

                  for (w = s->windows; w; w = w->next)
                  {
                        SD_WINDOW(w);
                        syncWindowPosition(w);
                        if (ss->state == SD_STATE_DEACTIVATING)
                              sw->placer.placed = FALSE;
                  }
                  if (ss->state == SD_STATE_ACTIVATING)
                        ss->state = SD_STATE_ON;

                  if (ss->state == SD_STATE_DEACTIVATING)
                  {
                        ss->state = SD_STATE_OFF;
                        IPCS_SetBool(IPCS_OBJECT(s), ss->sdActiveAtom, FALSE);
                  }

                  if (ss->grabIndex)
                  {
                        removeScreenGrab(s, ss->grabIndex, NULL);
                        ss->grabIndex = 0;
                  }
            }
      }

      UNWRAP(ss, s, donePaintScreen);
      (*s->donePaintScreen) (s);
      WRAP(ss, s, donePaintScreen, showdesktopDonePaintScreen);
}

/* display initialization */

static Bool showdesktopInitDisplay(CompPlugin * p, CompDisplay * d)
{
      ShowdesktopDisplay *sd;

      sd = malloc(sizeof(ShowdesktopDisplay));  /* allocate the display */
      if (!sd)
            return FALSE;

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

      WRAP(sd, d, handleEvent, showdesktopHandleEvent);

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

      return TRUE;
}

/* display finalization
 * free resources
 * */
static void showdesktopFiniDisplay(CompPlugin * p, CompDisplay * d)
{
      SD_DISPLAY(d);

      freeScreenPrivateIndex(d, sd->screenPrivateIndex);

      UNWRAP(sd, d, handleEvent);

      free(sd);
}

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

      SD_SCREEN(s);

      if (!ss->opt[SD_SCREEN_OPTION_USE_SCALE_SETTINGS].value.b)
            return;

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

            options = (*p->vTable->getScreenOptions) (s, &nOptions);

            option = compFindOption(options, nOptions, "speed", 0);
            if (option)
                  ss->speed = option->value.f;

            option = compFindOption(options, nOptions, "timestep", 0);
            if (option)
                  ss->timestep = option->value.f;

            option = compFindOption(options, nOptions, "window_types", 0);
            if (option)
                  ss->wMask = compWindowTypeMaskFromStringList(&option->value);

      }
}

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

      SD_SCREEN(s);

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

      if (status && strcmp(plugin, "scale") == 0)
            if (strcmp(name, "speed") == 0
                  || strcmp(name, "timestep") == 0
                  || strcmp(name, "window_types") == 0)
                  showdesktopUpdateScaleOptions(s);

      return status;
}

/* screen initialization
 * */
static Bool showdesktopInitScreen(CompPlugin * p, CompScreen * s)
{
      ShowdesktopScreen *ss;

      SD_DISPLAY(s->display);

      ss = malloc(sizeof(ShowdesktopScreen));
      if (!ss)
            return FALSE;

      ss->windowPrivateIndex = allocateWindowPrivateIndex(s);
      if (ss->windowPrivateIndex < 0)
      {
            free(ss);
            return FALSE;
      }

      showdesktopScreenInitOptions(ss);

      ss->state = SD_STATE_OFF;

      ss->moreAdjust = 0;

      ss->speed = SD_SPEED_DEFAULT;
      ss->timestep = SD_TIMESTEP_DEFAULT;
      ss->direction = SD_DIRECTION_DEFAULT;
      ss->windowOpacity = SD_WINDOW_OPACITY_DEFAULT;
      ss->windowPartSize = SD_WINDOW_PART_SIZE_DEFAULT;

      ss->ignoreNextTerminateEvent = FALSE;
      ss->grabIndex = 0;

      ss->sdActiveAtom =
                  IPCS_GetAtom(IPCS_OBJECT(s), IPCS_BOOL, "SHOWDESKTOP_ACTIVE",
                                     TRUE);
      IPCS_SetBool(IPCS_OBJECT(s), ss->sdActiveAtom, FALSE);

      addScreenAction(s, &sd->opt[SD_DISPLAY_OPTION_INITIATE].value.action);

      WRAP(ss, s, preparePaintScreen, showdesktopPreparePaintScreen);
      WRAP(ss, s, donePaintScreen, showdesktopDonePaintScreen);
      WRAP(ss, s, setScreenOptionForPlugin,
             showdesktopSetScreenOptionForPlugin);

      s->privates[sd->screenPrivateIndex].ptr = ss;

      showdesktopUpdateScaleOptions(s);

      return TRUE;

}

/* Free screen resources */
static void showdesktopFiniScreen(CompPlugin * p, CompScreen * s)
{
      SD_SCREEN(s);
      SD_DISPLAY(s->display);

      UNWRAP(ss, s, preparePaintScreen);
      UNWRAP(ss, s, donePaintScreen);
      UNWRAP(ss, s, setScreenOptionForPlugin);

      removeScreenAction(s, &sd->opt[SD_DISPLAY_OPTION_INITIATE].value.action);

      IPCS_Unset(IPCS_OBJECT(s), ss->sdActiveAtom);

      freeWindowPrivateIndex(s, ss->windowPrivateIndex);

      free(ss);
}


/* window init */
static Bool showdesktopInitWindow(CompPlugin * p, CompWindow * w)
{
      ShowdesktopWindow *sw;

      SD_SCREEN(w->screen);

      sw = malloc(sizeof(ShowdesktopWindow));
      if (!sw)
            return FALSE;

      sw->tx = sw->ty = 0.0f;
      sw->adjust = FALSE;
      sw->xVelocity = sw->yVelocity = 0.0f;
      sw->delta = 1.0f;
      sw->placer.placed = FALSE;
      sw->placer.offScreenX = sw->placer.offScreenY = 0;
      sw->placer.onScreenX = sw->placer.onScreenY = 0;

      w->privates[ss->windowPrivateIndex].ptr = sw;

      return TRUE;
}

/* Free window resources */
static void showdesktopFiniWindow(CompPlugin * p, CompWindow * w)
{
      SD_WINDOW(w);

      free(sw);
}


static CompOption *showdesktopGetDisplayOptions(CompDisplay * display,
                                                                        int *count)
{
      if (display)
      {
            SD_DISPLAY(display);

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

            showdesktopDisplayInitOptions(sd);
            *count = NUM_OPTIONS(sd);
            return sd->opt;
      }
}

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

      SD_DISPLAY(display);

      o = compFindOption(sd->opt, NUM_OPTIONS(sd), name, &index);

      if (!o)
            return FALSE;

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

      return FALSE;
}

static CompOption *showdesktopGetScreenOptions(CompScreen * screen,
                                                                     int *count)
{
      if (screen)
      {
            SD_SCREEN(screen);

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

            showdesktopScreenInitOptions(ss);
            *count = NUM_OPTIONS(ss);
            return ss->opt;
      }
}

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

      SD_SCREEN(screen);

      o = compFindOption(ss->opt, NUM_OPTIONS(ss), name, &index);

      if (!o)
            return FALSE;

      switch (index)
      {
      case SD_SCREEN_OPTION_SPEED:
            if (compSetFloatOption(o, value))
            {
                  if (!ss->opt[SD_SCREEN_OPTION_USE_SCALE_SETTINGS].value.b)
                        ss->speed = o->value.f;
                  return TRUE;
            }
            break;
      case SD_SCREEN_OPTION_TIMESTEP:
            if (compSetFloatOption(o, value))
            {
                  if (!ss->opt[SD_SCREEN_OPTION_USE_SCALE_SETTINGS].value.b)
                        ss->timestep = o->value.f;
                  return TRUE;
            }
            break;
      case SD_SCREEN_OPTION_DIRECTION:
            if (compSetStringOption(o, value))
            {
                  int i;

                  for (i = 0; i < o->rest.s.nString; i++)
                  {
                        if (strcmp(sdDirections[i], o->value.s) == 0)
                              ss->direction = (SdDirection) i;
                  }
                  return TRUE;
            }
            break;
      case SD_SCREEN_OPTION_WINDOW_TYPE:
            if (compSetOptionList(o, value))
            {
                  if (!ss->opt[SD_SCREEN_OPTION_USE_SCALE_SETTINGS].value.b)
                        ss->wMask = compWindowTypeMaskFromStringList(&o->value);
                  return TRUE;
            }
            break;
      case SD_SCREEN_OPTION_USE_SCALE_SETTINGS:
            if (compSetBoolOption(o, value))
            {
                  if (o->value.b)
                  {
                        showdesktopUpdateScaleOptions(screen);
                  }
                  else
                  {
                        ss->speed = ss->opt[SD_SCREEN_OPTION_SPEED].value.f;
                        ss->timestep = ss->opt[SD_SCREEN_OPTION_TIMESTEP].value.f;
                        ss->wMask =
                                    compWindowTypeMaskFromStringList(&
                                                                                     (ss->
                                                                                      opt
                                                                                      [SD_SCREEN_OPTION_WINDOW_TYPE].
                                                                                      value));
                  }
                  return TRUE;
            }
            break;
      case SD_SCREEN_OPTION_WINDOW_OPACITY:
            if (compSetFloatOption(o, value))
            {
                  ss->windowOpacity = o->value.f;
                  return TRUE;
            }
            break;
      case SD_SCREEN_OPTION_WINDOW_PART_SIZE:
            if (compSetIntOption(o, value))
            {
                  ss->windowPartSize = o->value.i;
                  return TRUE;
            }
            break;
      }
      return FALSE;
}

CompPluginFeature sdFeatures[] = {
      {"showdesktop"}
      ,
};

/* plugin vtable */
static CompPluginVTable showdesktopVTable = {
      "showdesktop",
      N_("Show desktop"),
      N_("Access your desktop easily"),
      showdesktopInit,
      showdesktopFini,
      showdesktopInitDisplay,
      showdesktopFiniDisplay,
      showdesktopInitScreen,
      showdesktopFiniScreen,
      showdesktopInitWindow,
      showdesktopFiniWindow,
      showdesktopGetDisplayOptions,
      showdesktopSetDisplayOption,
      showdesktopGetScreenOptions,
      showdesktopSetScreenOption,
      0,                                        /* deps fade */
      0,                                        /* sizeof (fadeDeps) / sizeof (fadeDeps[0]) */
      sdFeatures,
      sizeof(sdFeatures)/sizeof(sdFeatures[0]),
      BERYL_ABI_INFO,
      "beryl-plugins-unsupported",
      "desktop",
      0,
      0,
      False,
};

/* send plugin info */
CompPluginVTable *getCompPluginInfo(void)
{
      return &showdesktopVTable;
}

Generated by  Doxygen 1.6.0   Back to index