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

switcher.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 <math.h>
#include <sys/types.h>
#include <unistd.h>

#include <X11/Xatom.h>
#include <X11/extensions/Xrender.h>

#include <beryl.h>

#define SWITCH_NEXT_KEY_DEFAULT       "Tab"
#define SWITCH_NEXT_MODIFIERS_DEFAULT CompAltMask

#define SWITCH_PREV_KEY_DEFAULT       "Tab"
#define SWITCH_PREV_MODIFIERS_DEFAULT (CompAltMask | ShiftMask)

#define SWITCH_NEXT_ALL_KEY_DEFAULT       "Tab"
#define SWITCH_NEXT_ALL_MODIFIERS_DEFAULT (CompAltMask | ControlMask)

#define SWITCH_PREV_ALL_KEY_DEFAULT       "Tab"
#define SWITCH_PREV_ALL_MODIFIERS_DEFAULT \
    (CompAltMask | ControlMask | ShiftMask)

#define SWITCH_RING_NEXT_KEY_DEFAULT       "Tab"
#define SWITCH_RING_NEXT_MODIFIERS_DEFAULT CompSuperMask

#define SWITCH_RING_PREV_KEY_DEFAULT       "Tab"
#define SWITCH_RING_PREV_MODIFIERS_DEFAULT (CompSuperMask | ShiftMask)

#define SWITCH_RING_NEXT_ALL_KEY_DEFAULT       "Tab"
#define SWITCH_RING_NEXT_ALL_MODIFIERS_DEFAULT (CompSuperMask | ControlMask)

#define SWITCH_RING_PREV_ALL_KEY_DEFAULT       "Tab"
#define SWITCH_RING_PREV_ALL_MODIFIERS_DEFAULT \
    (CompSuperMask | ControlMask | ShiftMask)

#define SWITCH_SPEED_DEFAULT   2.5f
#define SWITCH_SPEED_MIN       0.1f
#define SWITCH_SPEED_MAX       50.0f
#define SWITCH_SPEED_PRECISION 0.1f

#define SWITCH_TIMESTEP_DEFAULT   1.1f
#define SWITCH_TIMESTEP_MIN       0.1f
#define SWITCH_TIMESTEP_MAX       50.0f
#define SWITCH_TIMESTEP_PRECISION 0.1f

#define SWITCH_MIPMAP_DEFAULT FALSE

#define SWITCH_BRINGTOFRONT_DEFAULT TRUE
#define SWITCH_SWITCH_FOCUS_INSTANTLY_DEFAULT FALSE

#define SWITCH_SATURATION_DEFAULT 100
#define SWITCH_SATURATION_MIN     0
#define SWITCH_SATURATION_MAX     100

#define SWITCH_BRIGHTNESS_DEFAULT 65
#define SWITCH_BRIGHTNESS_MIN     0
#define SWITCH_BRIGHTNESS_MAX     100

#define SWITCH_OPACITY_DEFAULT    40
#define SWITCH_OPACITY_MIN        0
#define SWITCH_OPACITY_MAX        100

#define SWITCH_ZOOM_DEFAULT   0.0f
#define SWITCH_ZOOM_MIN       0.0f
#define SWITCH_ZOOM_MAX       50.0f
#define SWITCH_ZOOM_PRECISION 0.1f

#define SWITCH_ICON_DEFAULT TRUE

#define SWITCH_MINIMIZED_DEFAULT TRUE

#define SWITCH_SHOW_WINDOW_LIST_DEFAULT TRUE
#define SWITCH_TEMP_UNMINIMIZE_DEFAULT FALSE
#define SWITCH_AUTO_ROTATE_DEFAULT FALSE

#define SWITCH_RING_ALL_TRANSPARENT_DEFAULT TRUE

#define SWITCH_ELLIPSE_WIDTH_MIN    0.01f
#define SWITCH_ELLIPSE_WIDTH_MAX    1.0f
#define SWITCH_ELLIPSE_WIDTH_DEFAULT      0.6f

#define SWITCH_ELLIPSE_HEIGHT_MIN   0.01f
#define SWITCH_ELLIPSE_HEIGHT_MAX   1.0f
#define SWITCH_ELLIPSE_HEIGHT_DEFAULT     0.25f
#define SWITCH_ELLIPSE_PRECISION    0.001f

#define SWITCH_THUMBNAIL_WIDTH_MIN  10
#define SWITCH_THUMBNAIL_WIDTH_MAX  1024
#define SWITCH_THUMBNAIL_WIDTH_DEFAULT    212

#define SWITCH_THUMBNAIL_HEIGHT_MIN 10
#define SWITCH_THUMBNAIL_HEIGHT_MAX 1024
#define SWITCH_THUMBNAIL_HEIGHT_DEFAULT   192

typedef enum _SwitcherMode
{
      ApplicationSwitcher = 0,
      RingSwitcher
} SwitcherMode;

typedef enum _IconCornerMode
{
      BottomRight = 0,
      BottomLeft,
      TopRight,
      TopLeft,
      Center
} IconCornerMode;

static char *iconCornerModes[] = {
      N_("Bottom Right"),
      N_("Bottom Left"),
      N_("Top Right"),
      N_("Top Left"),
      N_("Center")
};

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

#define SWITCH_ICON_CORNER_DEFAULT BottomRight

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

static int displayPrivateIndex;

#define SWITCH_DISPLAY_OPTION_NEXT                    0
#define SWITCH_DISPLAY_OPTION_PREV                    1
#define SWITCH_DISPLAY_OPTION_NEXT_ALL                2
#define SWITCH_DISPLAY_OPTION_PREV_ALL                3
#define SWITCH_DISPLAY_OPTION_RING_NEXT         4
#define SWITCH_DISPLAY_OPTION_RING_PREV         5
#define SWITCH_DISPLAY_OPTION_RING_NEXT_ALL     6
#define SWITCH_DISPLAY_OPTION_RING_PREV_ALL           7
#define SWITCH_DISPLAY_OPTION_NUM                     8

typedef struct _SwitchDisplay
{
      int screenPrivateIndex;
      HandleEventProc handleEvent;

      CompOption opt[SWITCH_DISPLAY_OPTION_NUM];

      Atom selectWinAtom;
} SwitchDisplay;

#define SWITCH_SCREEN_OPTION_SHOW_WINDOW_LIST         0
#define SWITCH_SCREEN_OPTION_SPEED                    1
#define SWITCH_SCREEN_OPTION_TIMESTEP                       2
#define SWITCH_SCREEN_OPTION_BRINGTOFRONT                   3
#define SWITCH_SCREEN_OPTION_AUTO_ROTATE              4
#define SWITCH_SCREEN_OPTION_SWITCH_FOCUS_INSTANTLY   5
#define SWITCH_SCREEN_OPTION_ZOOM                           6
#define SWITCH_SCREEN_OPTION_WINDOW_TYPE                    7
#define SWITCH_SCREEN_OPTION_MINIMIZED                8
#define SWITCH_SCREEN_OPTION_TEMP_UNMINIMIZE          9
#define SWITCH_SCREEN_OPTION_SATURATION               10
#define SWITCH_SCREEN_OPTION_BRIGHTNESS               11
#define SWITCH_SCREEN_OPTION_OPACITY                        12
#define SWITCH_SCREEN_OPTION_MIPMAP                   13
#define SWITCH_SCREEN_OPTION_ICON                           14
#define SWITCH_SCREEN_OPTION_ICON_CORNER              15
#define SWITCH_SCREEN_OPTION_ELLIPSE_WIDTH                  16
#define SWITCH_SCREEN_OPTION_ELLIPSE_HEIGHT                 17
#define SWITCH_SCREEN_OPTION_THUMBNAIL_WIDTH          18
#define SWITCH_SCREEN_OPTION_THUMBNAIL_HEIGHT         19
#define SWITCH_SCREEN_OPTION_RING_TRANSPARENT_ALL     20
#define SWITCH_SCREEN_OPTION_NUM                            21

typedef struct _SwitchScreen
{
      PreparePaintScreenProc preparePaintScreen;
      DonePaintScreenProc donePaintScreen;
      PaintScreenProc paintScreen;
      PaintWindowProc paintWindow;
      DamageWindowRectProc damageWindowRect;

      CompOption opt[SWITCH_SCREEN_OPTION_NUM];

      Window popupWindow;

      Window selectedWindow;
      Window zoomedWindow;
      unsigned int lastActiveNum;

      float speed;
      float timestep;
      float zoom;

      unsigned int wMask;

      int grabIndex;

      Bool switching;
      Bool zooming;

      int moreAdjust;

      GLfloat mVelocity;
      GLfloat tVelocity;
      GLfloat sVelocity;

      CompWindow **windows;
      int windowsSize;
      int nWindows;

      int pos;
      int move;

      float translate;
      float sTranslate;

      GLushort saturation;
      GLushort brightness;
      GLushort opacity;

      Bool bringToFront;
      Bool allWindows;
      Bool showWindowList;
      Bool autoRotate;
      Bool tempUnMinimize;
      SwitcherMode switchMode;
      IconCornerMode iconCorner;

      int head;

      CompWindow *prevMin;

      int insideAtom;
} SwitchScreen;

#define MwmHintsDecorations (1L << 1)

typedef struct
{
      unsigned long flags;
      unsigned long functions;
      unsigned long decorations;
} MwmHints;

#define SELECT_WIN_PROP "_SWITCH_SELECT_WINDOW"

#define WIDTH  212
#define HEIGHT 192
#define SPACE  10
#define BOX_WIDTH 3

#define ELLIPSE_ROTA(outputRect) int ellipse_a = (outputRect.width*ss->opt[SWITCH_SCREEN_OPTION_ELLIPSE_WIDTH].value.f)/2.0f;
#define ELLIPSE_ROTB(outputRect) int ellipse_b = (outputRect.height*ss->opt[SWITCH_SCREEN_OPTION_ELLIPSE_HEIGHT].value.f)/2.0f;
#define ELLIPSE_ROT(outputRect) ELLIPSE_ROTA(outputRect)\
                ELLIPSE_ROTB(outputRect)
#define DIST_ROT int dist=(4*ellipse_a)/(ss->nWindows)

static float _boxVertices[] = {
      -(WIDTH >> 1), 0,
      -(WIDTH >> 1), BOX_WIDTH,
      (WIDTH >> 1), BOX_WIDTH,
      (WIDTH >> 1), 0,

      -(WIDTH >> 1), BOX_WIDTH,
      -(WIDTH >> 1), HEIGHT - BOX_WIDTH,
      -(WIDTH >> 1) + BOX_WIDTH, HEIGHT - BOX_WIDTH,
      -(WIDTH >> 1) + BOX_WIDTH, 0,

      (WIDTH >> 1) - BOX_WIDTH, BOX_WIDTH,
      (WIDTH >> 1) - BOX_WIDTH, HEIGHT - BOX_WIDTH,
      (WIDTH >> 1), HEIGHT - BOX_WIDTH,
      (WIDTH >> 1), 0,

      -(WIDTH >> 1), HEIGHT - BOX_WIDTH,
      -(WIDTH >> 1), HEIGHT,
      (WIDTH >> 1), HEIGHT,
      (WIDTH >> 1), HEIGHT - BOX_WIDTH
};

#define WINDOW_WIDTH(count) (WIDTH * (count) + (SPACE << 1))
#define WINDOW_HEIGHT (HEIGHT + (SPACE << 1))

#define GET_SWITCH_DISPLAY(d)                       \
    ((SwitchDisplay *) (d)->privates[displayPrivateIndex].ptr)

#define SWITCH_DISPLAY(d)               \
    SwitchDisplay *sd = GET_SWITCH_DISPLAY (d)

#define GET_SWITCH_SCREEN(s, sd)                   \
    ((SwitchScreen *) (s)->privates[(sd)->screenPrivateIndex].ptr)

#define SWITCH_SCREEN(s)                              \
    SwitchScreen *ss = GET_SWITCH_SCREEN (s, GET_SWITCH_DISPLAY (s->display))

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

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

      SWITCH_SCREEN(screen);

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

      switch (index)
      {
      case SWITCH_SCREEN_OPTION_SPEED:
            if (compSetFloatOption(o, value))
            {
                  ss->speed = o->value.f;
                  return TRUE;
            }
            break;
      case SWITCH_SCREEN_OPTION_TIMESTEP:
            if (compSetFloatOption(o, value))
            {
                  ss->timestep = o->value.f;
                  return TRUE;
            }
            break;
      case SWITCH_SCREEN_OPTION_WINDOW_TYPE:
            if (compSetOptionList(o, value))
            {
                  ss->wMask = compWindowTypeMaskFromStringList(&o->value);
                  return TRUE;
            }
            break;
      case SWITCH_SCREEN_OPTION_MIPMAP:
      case SWITCH_SCREEN_OPTION_ICON:
      case SWITCH_SCREEN_OPTION_MINIMIZED:
      case SWITCH_SCREEN_OPTION_SWITCH_FOCUS_INSTANTLY:
      case SWITCH_SCREEN_OPTION_RING_TRANSPARENT_ALL :
            if (compSetBoolOption(o, value))
                  return TRUE;
            break;
      case SWITCH_SCREEN_OPTION_SHOW_WINDOW_LIST:
            if (compSetBoolOption(o, value))
            {
                  ss->showWindowList = o->value.b;
                  return TRUE;
            }
            break;
      case SWITCH_SCREEN_OPTION_AUTO_ROTATE:
            if (compSetBoolOption(o, value))
            {
                  ss->autoRotate = o->value.b;
                  return TRUE;
            }
            break;
      case SWITCH_SCREEN_OPTION_TEMP_UNMINIMIZE:
            if (compSetBoolOption(o, value))
            {
                  ss->tempUnMinimize = o->value.b;
                  return TRUE;
            }
            break;
      case SWITCH_SCREEN_OPTION_ICON_CORNER:
            if (compSetStringOption(o, value))
            {
                  int i;
                  ss->iconCorner = SWITCH_ICON_CORNER_DEFAULT;

                  for (i = 0; i < o->rest.s.nString; i++)
                        if (strcmp(iconCornerModes[i], o->value.s) == 0)
                              ss->iconCorner = (IconCornerMode) i;
                  return TRUE;
            }
            break;
      case SWITCH_SCREEN_OPTION_SATURATION:
            if (compSetIntOption(o, value))
            {
                  ss->saturation = (COLOR * o->value.i) / 100;
                  return TRUE;
            }
            break;
      case SWITCH_SCREEN_OPTION_BRIGHTNESS:
            if (compSetIntOption(o, value))
            {
                  ss->brightness = (0xffff * o->value.i) / 100;
                  return TRUE;
            }
            break;
      case SWITCH_SCREEN_OPTION_OPACITY:
            if (compSetIntOption(o, value))
            {
                  ss->opacity = (OPAQUE * o->value.i) / 100;
                  return TRUE;
            }
            break;
      case SWITCH_SCREEN_OPTION_BRINGTOFRONT:
            if (compSetBoolOption(o, value))
            {
                  ss->bringToFront = o->value.b;
                  return TRUE;
            }
            break;
      case SWITCH_SCREEN_OPTION_ZOOM:
            if (compSetFloatOption(o, value))
            {
                  if (o->value.f < 0.05f)
                  {
                        ss->zooming = FALSE;
                        ss->zoom = 0.0f;
                  }
                  else
                  {
                        ss->zooming = TRUE;
                        ss->zoom = o->value.f / 30.0f;
                  }

                  return TRUE;
            }
            break;
      case SWITCH_SCREEN_OPTION_ELLIPSE_WIDTH:
      case SWITCH_SCREEN_OPTION_ELLIPSE_HEIGHT:
            if(compSetFloatOption(o, value))
                  return TRUE;
            break;
      case SWITCH_SCREEN_OPTION_THUMBNAIL_WIDTH:
      case SWITCH_SCREEN_OPTION_THUMBNAIL_HEIGHT:
            if(compSetIntOption(o, value))
                  return TRUE;
            break;
      default:
            break;
      }

      return FALSE;
}

static void switchScreenInitOptions(SwitchScreen * ss)
{
      CompOption *o;
      int i;

      o = &ss->opt[SWITCH_SCREEN_OPTION_SHOW_WINDOW_LIST];
      o->advanced = False;
      o->name = "show_window_list";
      o->group = N_("Misc. Options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Show Window List");
      o->longDesc = N_("Show the Window List box in center of the screen.");
      o->type = CompOptionTypeBool;
      o->value.b = SWITCH_SHOW_WINDOW_LIST_DEFAULT;

      o = &ss->opt[SWITCH_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_("How fast the Switcher moves thumbnails.");
      o->type = CompOptionTypeFloat;
      o->value.f = SWITCH_SPEED_DEFAULT;
      o->rest.f.min = SWITCH_SPEED_MIN;
      o->rest.f.max = SWITCH_SPEED_MAX;
      o->rest.f.precision = SWITCH_SPEED_PRECISION;

      o = &ss->opt[SWITCH_SCREEN_OPTION_TIMESTEP];
      o->advanced = False;
      o->name = "timestep";
      o->group = N_("Misc. Options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Switcher Timestep");
      o->longDesc = N_("Switcher Timestep.");
      o->type = CompOptionTypeFloat;
      o->value.f = SWITCH_TIMESTEP_DEFAULT;
      o->rest.f.min = SWITCH_TIMESTEP_MIN;
      o->rest.f.max = SWITCH_TIMESTEP_MAX;
      o->rest.f.precision = SWITCH_TIMESTEP_PRECISION;

      o = &ss->opt[SWITCH_SCREEN_OPTION_WINDOW_TYPE];
      o->advanced = False;
      o->name = "window_types";
      o->group = N_("Behaviour");
      o->subGroup = N_("Window handling");
      o->displayHints = "";
      o->shortDesc = N_("Window Types");
      o->longDesc = N_("Window Types that should be shown in Switcher.");
      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[SWITCH_SCREEN_OPTION_MIPMAP];
      o->advanced = False;
      o->name = "mipmap";
      o->group = N_("Appearance");
      o->subGroup = N_("Quality Settings");
      o->displayHints = "";
      o->shortDesc = N_("Mipmap");
      o->longDesc =
                  N_("Generate Mipmaps when possible for higher quality "
                     "Scaling.");
      o->type = CompOptionTypeBool;
      o->value.b = SWITCH_MIPMAP_DEFAULT;

      o = &ss->opt[SWITCH_SCREEN_OPTION_SATURATION];
      o->advanced = False;
      o->name = "saturation";
      o->group = N_("Appearance");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Saturation");
      o->longDesc = N_("Saturation of unfocused windows in percent.");
      o->type = CompOptionTypeInt;
      o->value.i = SWITCH_SATURATION_DEFAULT;
      o->rest.i.min = SWITCH_SATURATION_MIN;
      o->rest.i.max = SWITCH_SATURATION_MAX;

      o = &ss->opt[SWITCH_SCREEN_OPTION_BRIGHTNESS];
      o->advanced = False;
      o->name = "brightness";
      o->group = N_("Appearance");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Brightness");
      o->longDesc = N_("Brightness of the background desktop in percent.");
      o->type = CompOptionTypeInt;
      o->value.i = SWITCH_BRIGHTNESS_DEFAULT;
      o->rest.i.min = SWITCH_BRIGHTNESS_MIN;
      o->rest.i.max = SWITCH_BRIGHTNESS_MAX;

      o = &ss->opt[SWITCH_SCREEN_OPTION_OPACITY];
      o->advanced = False;
      o->name = "opacity";
      o->group = N_("Appearance");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Opacity");
      o->longDesc = N_("Opacity of unfocused windows in percent.");
      o->type = CompOptionTypeInt;
      o->value.i = SWITCH_OPACITY_DEFAULT;
      o->rest.i.min = SWITCH_OPACITY_MIN;
      o->rest.i.max = SWITCH_OPACITY_MAX;

      o = &ss->opt[SWITCH_SCREEN_OPTION_BRINGTOFRONT];
      o->advanced = False;
      o->name = "bring_to_front";
      o->group = N_("Behaviour");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Bring To Front");
      o->longDesc = N_("Bring selected window to Front.");
      o->type = CompOptionTypeBool;
      o->value.b = SWITCH_BRINGTOFRONT_DEFAULT;

      o = &ss->opt[SWITCH_SCREEN_OPTION_ICON_CORNER];
      o->advanced = False;
      o->name = "icon_corner_mode";
      o->group = N_("Appearance");
      o->subGroup = N_("Icon Options");
      o->displayHints = "";
      o->shortDesc = N_("Icon Corner");
      o->longDesc = N_("Icon Placement.");
      o->type = CompOptionTypeString;
      o->value.s = strdup(iconCornerModes[SWITCH_ICON_CORNER_DEFAULT]);
      o->rest.s.string = iconCornerModes;
      o->rest.s.nString = N_ICON_CORNER_MODES;

      o = &ss->opt[SWITCH_SCREEN_OPTION_ZOOM];
      o->advanced = False;
      o->name = "zoom";
      o->group = N_("Behaviour");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Zoom");
      o->longDesc = N_("Distance desktop should be Zoom out while "
                               "Switching windows.");
      o->type = CompOptionTypeFloat;
      o->value.f = SWITCH_ZOOM_DEFAULT;
      o->rest.f.min = SWITCH_ZOOM_MIN;
      o->rest.f.max = SWITCH_ZOOM_MAX;
      o->rest.f.precision = SWITCH_ZOOM_PRECISION;

      o = &ss->opt[SWITCH_SCREEN_OPTION_ICON];
      o->advanced = False;
      o->name = "icon";
      o->group = N_("Appearance");
      o->subGroup = N_("Icon Options");
      o->displayHints = "";
      o->shortDesc = N_("Icon");
      o->longDesc = N_("Show Icon next to thumbnail.");
      o->type = CompOptionTypeBool;
      o->value.b = SWITCH_ICON_DEFAULT;

      o = &ss->opt[SWITCH_SCREEN_OPTION_MINIMIZED];
      o->advanced = False;
      o->name = "minimized";
      o->group = N_("Behaviour");
      o->subGroup = N_("Window handling");
      o->displayHints = "";
      o->shortDesc = N_("Show Minimized");
      o->longDesc = N_("Show Minimized windows.");
      o->type = CompOptionTypeBool;
      o->value.b = SWITCH_MINIMIZED_DEFAULT;


      o = &ss->opt[SWITCH_SCREEN_OPTION_AUTO_ROTATE];
      o->advanced = False;
      o->name = "auto_rotate";
      o->group = N_("Behaviour");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Auto Rotate");
      o->longDesc = N_("Rotate to active window Automatically.");
      o->type = CompOptionTypeBool;
      o->value.b = SWITCH_AUTO_ROTATE_DEFAULT;

      o = &ss->opt[SWITCH_SCREEN_OPTION_TEMP_UNMINIMIZE];
      o->advanced = False;
      o->name = "temp_unminimize";
      o->group = N_("Behaviour");
      o->subGroup = N_("Window handling");
      o->displayHints = "";
      o->shortDesc = N_("Temp UnMinimize");
      o->longDesc = N_("Temporarily Un-Minimize minimized windows.");
      o->type = CompOptionTypeBool;
      o->value.b = SWITCH_TEMP_UNMINIMIZE_DEFAULT;

      o = &ss->opt[SWITCH_SCREEN_OPTION_SWITCH_FOCUS_INSTANTLY];
      o->advanced = False;
      o->name = "switch_focus_instantly";
      o->group = N_("Behaviour");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Switch Focus Instantly");
      o->longDesc = N_("If enabled, the Focus is Switched to the window immediately"
                               "on activation; otherwise on Application Switcher termination.");
      o->type = CompOptionTypeBool;
      o->value.b = SWITCH_SWITCH_FOCUS_INSTANTLY_DEFAULT;


      o = &ss->opt[SWITCH_SCREEN_OPTION_ELLIPSE_WIDTH];
      o->advanced = False;
      o->name = "ellipse_width";
      o->group = N_("Appearance");
      o->subGroup = N_("Rotating List");
      o->displayHints = "";
      o->shortDesc = N_("Ellipse Width");
      o->longDesc = N_("Changes the proportions of the circle (1.0 means "
                               "the width is 100% of the screen width).");
      o->type = CompOptionTypeFloat;
      o->value.f = SWITCH_ELLIPSE_WIDTH_DEFAULT;
      o->rest.f.min = SWITCH_ELLIPSE_WIDTH_MIN;
      o->rest.f.max = SWITCH_ELLIPSE_WIDTH_MAX;
      o->rest.f.precision = SWITCH_ELLIPSE_PRECISION;

      o = &ss->opt[SWITCH_SCREEN_OPTION_ELLIPSE_HEIGHT];
      o->advanced = False;
      o->name = "ellipse_height";
      o->group = N_("Appearance");
      o->subGroup = N_("Rotating List");
      o->displayHints = "";
      o->shortDesc = N_("Ellipse Height");
      o->longDesc = N_("Changes the proportions of the circle (1.0 means "
                               "the height is 100% of the screen height).");
      o->type = CompOptionTypeFloat;
      o->value.f = SWITCH_ELLIPSE_HEIGHT_DEFAULT;
      o->rest.f.min = SWITCH_ELLIPSE_HEIGHT_MIN;
      o->rest.f.max = SWITCH_ELLIPSE_HEIGHT_MAX;
      o->rest.f.precision = SWITCH_ELLIPSE_PRECISION;

      o = &ss->opt[SWITCH_SCREEN_OPTION_THUMBNAIL_WIDTH];
      o->advanced = False;
      o->name = "thumbnail_width";
      o->group = N_("Appearance");
      o->subGroup = N_("Rotating List");
      o->displayHints = "";
      o->shortDesc = N_("Thumbnail Width");
      o->longDesc = N_("Changes the horizontal size of the unscaled Thumbnail.");
      o->type = CompOptionTypeInt;
      o->value.i = SWITCH_THUMBNAIL_WIDTH_DEFAULT;
      o->rest.i.min = SWITCH_THUMBNAIL_WIDTH_MIN;
      o->rest.i.max = SWITCH_THUMBNAIL_WIDTH_MAX;

      o = &ss->opt[SWITCH_SCREEN_OPTION_THUMBNAIL_HEIGHT];
      o->advanced = False;
      o->name = "thumbnail_height";
      o->group = N_("Appearance");
      o->subGroup = N_("Rotating List");
      o->displayHints = "";
      o->shortDesc = N_("Thumbnail Height");
      o->longDesc = N_("Changes the vertical size of the unscaled Thumbnail.");
      o->type = CompOptionTypeInt;
      o->value.i = SWITCH_THUMBNAIL_HEIGHT_DEFAULT;
      o->rest.i.min = SWITCH_THUMBNAIL_HEIGHT_MIN;
      o->rest.i.max = SWITCH_THUMBNAIL_HEIGHT_MAX;
      
      o = &ss->opt[SWITCH_SCREEN_OPTION_RING_TRANSPARENT_ALL];
      o->advanced = False;
      o->name = "ring_transparent_all";
      o->group = N_("Appearance");
      o->subGroup = N_("Rotating List");
      o->displayHints = "";
      o->shortDesc = N_("Fade windows out when using Ring Switcher");
      o->longDesc = N_("When using ring switcher mode fade actual windows out");
      o->type = CompOptionTypeBool;
      o->value.b = SWITCH_RING_ALL_TRANSPARENT_DEFAULT;

}

static CompOption *switchGetScreenOptions(CompScreen * screen, int *count)
{
      if (screen)
      {
            SWITCH_SCREEN(screen);

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

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

static void setSelectedWindowHint(CompScreen * s)
{
      SWITCH_DISPLAY(s->display);
      SWITCH_SCREEN(s);

      /* if we don't set this property, the switcher window won't be
       decorated by the DM - exactly what we want for the ring switcher */

      if (ss->switchMode == ApplicationSwitcher)
      {
            XChangeProperty(s->display->display, ss->popupWindow,
                                    sd->selectWinAtom, XA_WINDOW, 32, PropModeReplace,
                                    (unsigned char *)&ss->selectedWindow, 1);
      }
      else
      {
            XDeleteProperty(s->display->display, ss->popupWindow,
                        sd->selectWinAtom);
      }
}

static Bool isSwitchWin(CompWindow * w)
{
      SWITCH_SCREEN(w->screen);

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

      if (!w->mapNum || w->attrib.map_state != IsViewable)
      {
            if (ss->opt[SWITCH_SCREEN_OPTION_MINIMIZED].value.b)
            {
                  if (!((w->minimized || w->inShowDesktopMode)
                          && (w->state & CompWindowStateHiddenMask)) && !w->shaded)
                        return FALSE;
            }
            else
            {
                  return FALSE;
            }
      }

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

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

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

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

      if (!ss->allWindows)
      {
            if (!w->mapNum || w->attrib.map_state != IsViewable)
            {
                  if (w->serverX + w->width <= 0 ||
                        w->serverY + w->height <= 0 ||
                        w->serverX >= w->screen->width ||
                        w->serverY >= w->screen->height)
                        return FALSE;
            }
            else
            {
                  if (!(*w->screen->focusWindow) (w))
                        return FALSE;
            }
      }

      return TRUE;
}

static int compareWindows(const void *elem1, const void *elem2)
{
      CompWindow *w1 = *((CompWindow **) elem1);
      CompWindow *w2 = *((CompWindow **) elem2);

      if (w1->mapNum && !w2->mapNum)
            return -1;

      if (w2->mapNum && !w1->mapNum)
            return 1;

      return w2->activeNum - w1->activeNum;
}

static void switchAddWindowToList(CompScreen * s, CompWindow * w)
{
      SWITCH_SCREEN(s);

      if (ss->windowsSize <= ss->nWindows)
      {
            ss->windows = realloc(ss->windows,
                                            sizeof(CompWindow *) * (ss->nWindows + 32));
            if (!ss->windows)
                  return;

            ss->windowsSize = ss->nWindows + 32;
      }

      ss->windows[ss->nWindows++] = w;
}

static void switchUpdateWindowList(CompScreen * s, int count)
{
      SWITCH_SCREEN(s);

      if (count > 1)
      {
            count -= (count + 1) & 1;
            if (count < 3)
                  count = 3;
      }

      if (ss->switchMode == RingSwitcher)
      {
            XRectangle outputRect;
            screenGetOutputDevRect(s, ss->head, &outputRect);
            ELLIPSE_ROTA(outputRect);
            ss->pos = ellipse_a;
      }
      else
      {
            ss->pos = ((count >> 1) - ss->nWindows) * WIDTH;
      }

      ss->move = 0;

      ss->selectedWindow = ss->windows[0]->id;

      if (ss->popupWindow)
      {
            XRectangle outputRect;

            screenGetOutputDevRect(s, ss->head, &outputRect);

            XMoveResizeWindow(s->display->display, ss->popupWindow,
                        outputRect.x + outputRect.width / 2 - WINDOW_WIDTH(count) / 2,
                        outputRect.y + outputRect.height / 2 - WINDOW_HEIGHT / 2,
                        WINDOW_WIDTH(count), WINDOW_HEIGHT);
      }

}

static void switchCreateWindowList(CompScreen * s, int count)
{
      CompWindow *w;

      SWITCH_SCREEN(s);

      ss->nWindows = 0;

      for (w = s->windows; w; w = w->next)
      {
            if (isSwitchWin(w))
                  switchAddWindowToList(s, w);
      }

      qsort(ss->windows, ss->nWindows, sizeof(CompWindow *), compareWindows);

      if ((ss->switchMode == ApplicationSwitcher) && (ss->nWindows == 2))
      {
            switchAddWindowToList(s, ss->windows[0]);
            switchAddWindowToList(s, ss->windows[1]);
      }

      switchUpdateWindowList(s, count);
}

static void switchToWindow(CompScreen * s, Bool toNext)
{
      CompWindow *w;
      int cur;

      SWITCH_SCREEN(s);

      if (!ss->grabIndex)
            return;

      for (cur = 0; cur < ss->nWindows; cur++)
      {
            if (ss->windows[cur]->id == ss->selectedWindow)
                  break;
      }

      if (cur == ss->nWindows)
            return;

      if (toNext)
            w = ss->windows[(cur + 1) % ss->nWindows];
      else
            w = ss->windows[(cur + ss->nWindows - 1) % ss->nWindows];

      if (w)
      {
            Window old = ss->selectedWindow;

            ss->lastActiveNum = w->activeNum;
            ss->selectedWindow = w->id;

            if (!ss->zoomedWindow)
                  ss->zoomedWindow = ss->selectedWindow;

            if (old != w->id)
            {
                  if (toNext)
                  {
                        if (ss->switchMode == RingSwitcher)
                        {
                              XRectangle outputRect;
                              screenGetOutputDevRect(s, ss->head, &outputRect);
                              ELLIPSE_ROTA(outputRect);
                              DIST_ROT;
                              ss->move -= dist;
                        }
                        else
                        {
                              ss->move -= WIDTH;
                        }
                  }
                  else
                  {
                        if (ss->switchMode == RingSwitcher)
                        {
                              XRectangle outputRect;
                              screenGetOutputDevRect(s, ss->head, &outputRect);
                              ELLIPSE_ROTA(outputRect);
                              DIST_ROT;
                              ss->move += dist;
                        }
                        else
                        {
                              ss->move += WIDTH;
                        }
                  }
                  ss->moreAdjust = 1;
            }

            if (ss->popupWindow)
            {
                  CompWindow *popup;

                  popup = findWindowAtScreen(s, ss->popupWindow);
                  if (popup)
                        addWindowDamage(popup);

                  setSelectedWindowHint(s);
            }


            if (ss->tempUnMinimize)
            {
                  if (ss->prevMin != NULL)
                  {
                        minimizeWindow(ss->prevMin);
                        ss->prevMin = NULL;
                  }

                  if (w->minimized)
                        ss->prevMin = w;
            }

            if (ss->autoRotate)
                  changeToWindowViewport(s, ss->selectedWindow, w);
            if (ss->tempUnMinimize && w->minimized)
                  unminimizeWindow(w);

            if (ss->opt[SWITCH_SCREEN_OPTION_SWITCH_FOCUS_INSTANTLY].value.b)
                  sendWindowActivationRequest(w->screen, w->id);

            addWindowDamage(w);

            if ((w = findWindowAtScreen(s, old)))
            {
                  addWindowDamage(w);
            }
      }
}

static int switchCountWindows(CompScreen * s)
{
      CompWindow *w;
      int count = 0;
      XRectangle outputRect;

      //    SWITCH_SCREEN(s);

      for (w = s->windows; w && count < 5; w = w->next)
            if (isSwitchWin(w))
                  count++;

      int head = screenGetCurrentOutputDev(s);

      screenGetOutputDevRect(s, head, &outputRect);

      if (count == 5 && outputRect.width <= WINDOW_WIDTH(5))
            count = 3;

      return count;
}

static Visual *findArgbVisual(Display * dpy, int scr)
{
      XVisualInfo *xvi;
      XVisualInfo template;
      int nvi;
      int i;
      XRenderPictFormat *format;
      Visual *visual;

      template.screen = scr;
      template.depth = 32;
      template.class = TrueColor;

      xvi = XGetVisualInfo(dpy,
                                     VisualScreenMask |
                                     VisualDepthMask | VisualClassMask, &template, &nvi);
      if (!xvi)
            return 0;

      visual = 0;
      for (i = 0; i < nvi; i++)
      {
            format = XRenderFindVisualFormat(dpy, xvi[i].visual);
            if (format->type == PictTypeDirect && format->direct.alphaMask)
            {
                  visual = xvi[i].visual;
                  break;
            }
      }

      XFree(xvi);

      return visual;
}

static void switchUpdatePopupWindow(CompScreen *s, int head,
            int count, SwitcherMode switchMode)
{
      SWITCH_SCREEN(s);
      Display *dpy = s->display->display;

      if ((switchMode != ss->switchMode) && ss->popupWindow)
      {
            XDestroyWindow(s->display->display, ss->popupWindow);
            ss->popupWindow = None;
      }

      if ((!ss->popupWindow && ss->showWindowList) || head != ss->head)
      {
            XRectangle outputRect;
            XSizeHints xsh;
            XWMHints xwmh;
            XSetWindowAttributes attr;
            Visual *visual;
            Atom mwmHintsAtom;
            MwmHints mwmHints;
            Atom type;
            Atom state[5];
            int nState = 0;

            visual = findArgbVisual(dpy, s->screenNum);
            if (!visual)
                  return;

            if (count > 1)
            {
                  count -= (count + 1) & 1;
                  if (count < 3)
                        count = 3;
            }

            xsh.flags = PSize | PPosition;
            xsh.width = WINDOW_WIDTH(count);
            xsh.height = WINDOW_HEIGHT;

            xwmh.flags = InputHint;
            xwmh.input = 0;

            attr.background_pixel = 0;
            attr.border_pixel = 0;
            attr.colormap = XCreateColormap(dpy, s->root, visual, AllocNone);

            if (ss->showWindowList)
            {
                  if (ss->popupWindow)
                  {
                        XDestroyWindow(s->display->display, ss->popupWindow);
                        ss->popupWindow = None;
                  }

                  screenGetOutputDevRect(s, head, &outputRect);

                  ss->popupWindow =
                              XCreateWindow(dpy, s->root,
                                                  outputRect.x + outputRect.width / 2 - xsh.width / 2,
                                                  outputRect.y + outputRect.height / 2 - xsh.height / 2,
                                                  xsh.width, xsh.height, 0, 32, InputOutput, visual,
                                                  CWBackPixel | CWBorderPixel | CWColormap, &attr);

                  XSetWMProperties(dpy, ss->popupWindow, NULL, NULL,
                                           getProgramArgv(),
                                           getProgramArgc(), &xsh, &xwmh, NULL);

                  mwmHintsAtom = XInternAtom(dpy, "_MOTIF_WM_HINTS", 0);

                  memset(&mwmHints, 0, sizeof(mwmHints));

                  mwmHints.flags = MwmHintsDecorations;
                  mwmHints.decorations = 0;

                  XChangeProperty(dpy, ss->popupWindow, mwmHintsAtom,
                                          mwmHintsAtom, 8, PropModeReplace,
                                          (unsigned char *)&mwmHints, sizeof(mwmHints));

                  type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_SPLASH", 0);
                  XChangeProperty(dpy, ss->popupWindow,
                                          XInternAtom(dpy,
                                                            "_NET_WM_WINDOW_TYPE",
                                                            0), XA_ATOM, 32,
                                          PropModeReplace, (unsigned char *)&type, 1);

                  setWindowProp(s->display, ss->popupWindow,
                                      s->display->winDesktopAtom, 0xffffffff);

                  state[nState++] = s->display->winStateAboveAtom;
                  state[nState++] = s->display->winStateStickyAtom;
                  state[nState++] = s->display->winStateSkipTaskbarAtom;
                  state[nState++] = s->display->winStateSkipPagerAtom;

                  if (switchMode == RingSwitcher)
                        state[nState++] = s->display->winStateFullscreenAtom;

                  XChangeProperty(dpy, ss->popupWindow,
                              XInternAtom(dpy, "_NET_WM_STATE", 0), XA_ATOM, 32,
                              PropModeReplace, (unsigned char *)state, nState);
            }
      }
}

static void switchInitiate(CompScreen * s, Bool allWindows, SwitcherMode switchMode)
{
      int count;

      SWITCH_SCREEN(s);

      if (otherScreenGrabExist(s, "scale", "cube", 0))
            return;

      ss->allWindows = allWindows;

      count = switchCountWindows(s);
      if (count < 1)
            return;

      int head = screenGetCurrentOutputDev(s);

      switchUpdatePopupWindow(s, head, count, switchMode);

      ss->switchMode = switchMode;
      ss->head = head;

      if (!ss->showWindowList && ss->popupWindow)
      {
            XUnmapWindow(s->display->display, ss->popupWindow);
      }

      if (!ss->grabIndex)
            ss->grabIndex = pushScreenGrab(s, s->invisibleCursor, "switcher");

      if (ss->grabIndex)
      {
            if (!ss->switching)
            {
                  ss->lastActiveNum = s->activeNum;

                  switchCreateWindowList(s, count);

                  ss->sTranslate = ss->zoom;

                  if (ss->showWindowList && ss->popupWindow)
                  {
                        CompWindow *w;

                        w = findWindowAtScreen(s, ss->popupWindow);
                        if (w && (w->state & CompWindowStateHiddenMask))
                        {
                              w->hidden = FALSE;
                              showWindow(w);
                        }
                        else
                        {
                              XMapWindow(s->display->display, ss->popupWindow);
                        }

                        setSelectedWindowHint(s);
                  }
            }

            damageScreen(s);

            ss->switching = TRUE;
            ss->moreAdjust = 1;
      }
}

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

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


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

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

            if (ss->tempUnMinimize)
                  ss->prevMin = NULL;

            if (ss->grabIndex)
            {
                  CompWindow *w;

                  if (ss->popupWindow)
                  {
                        w = findWindowAtScreen(s, ss->popupWindow);
                        if (w && w->managed && w->mapNum)
                        {
                              w->hidden = TRUE;
                              hideWindow(w);
                        }
                        else
                        {
                              XUnmapWindow(s->display->display, ss->popupWindow);
                        }
                  }

                  ss->switching = FALSE;

                  if (!ss->opt[SWITCH_SCREEN_OPTION_SWITCH_FOCUS_INSTANTLY].value.b)
                  {
                        if (state && ss->selectedWindow)
                        {
                              w = findWindowAtScreen(s, ss->selectedWindow);
                              if (w)
                                    sendWindowActivationRequest(w->screen, w->id);
                        }
                  }

                  removeScreenGrab(s, ss->grabIndex, 0);
                  ss->grabIndex = 0;

                  if (!ss->zooming)
                  {
                        ss->selectedWindow = None;
                        ss->zoomedWindow = None;
                  }
                  else
                  {
                        ss->moreAdjust = 1;
                  }

                  ss->lastActiveNum = 0;

                  damageScreen(s);
            }
      }

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


      return FALSE;
}

static Bool
switchDoSwitch(CompDisplay * d, CompAction * action, CompActionState state,
            CompOption * option, int nOption, Bool next, Bool allWindows, SwitcherMode switchMode)
{
      CompScreen *s;
      Window xid;

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

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

            if (!ss->switching)
            {
                  switchInitiate(s, allWindows, switchMode);

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

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

            switchToWindow(s, next);
      }

      return FALSE;
}

static Bool
switchNext(CompDisplay * d,
               CompAction * action,
               CompActionState state, CompOption * option, int nOption)
{
      return switchDoSwitch(d, action, state, option, nOption, TRUE, FALSE, ApplicationSwitcher);
}

static Bool
switchPrev(CompDisplay * d,
               CompAction * action,
               CompActionState state, CompOption * option, int nOption)
{
      return switchDoSwitch(d, action, state, option, nOption, FALSE, FALSE, ApplicationSwitcher);
}
static Bool
switchNextAll(CompDisplay * d,
                  CompAction * action,
                  CompActionState state, CompOption * option, int nOption)
{
      return switchDoSwitch(d, action, state, option, nOption, TRUE, TRUE, ApplicationSwitcher);
}
static Bool
switchPrevAll(CompDisplay * d,
                  CompAction * action,
                  CompActionState state, CompOption * option, int nOption)
{
      return switchDoSwitch(d, action, state, option, nOption, FALSE, TRUE, ApplicationSwitcher);
}
static Bool
switchNextRing(CompDisplay * d,
                   CompAction * action,
                   CompActionState state, CompOption * option, int nOption)
{
      return switchDoSwitch(d, action, state, option, nOption, TRUE, FALSE, RingSwitcher);
}
static Bool
switchPrevRing(CompDisplay * d,
                     CompAction * action,
                   CompActionState state, CompOption * option, int nOption)
{
      return switchDoSwitch(d, action, state, option, nOption, FALSE, FALSE, RingSwitcher);
}
static Bool
switchNextAllRing(CompDisplay * d,
                          CompAction * action,
                          CompActionState state, CompOption * option, int nOption)
{
      return switchDoSwitch(d, action, state, option, nOption, TRUE, TRUE, RingSwitcher);
}
static Bool
switchPrevAllRing(CompDisplay * d,
                          CompAction * action,
                          CompActionState state, CompOption * option, int nOption)
{
      return switchDoSwitch(d, action, state, option, nOption, FALSE, TRUE, RingSwitcher);
}

static void switchWindowRemove(CompDisplay * d, Window id)
{
      CompWindow *w;

      w = findWindowAtDisplay(d, id);
      if (w)
      {
            Bool inList = FALSE;
            int count, j, i = 0;
            Window selected, old;

            SWITCH_SCREEN(w->screen);

            if (isSwitchWin(w))
                  return;

            old = selected = ss->selectedWindow;

            while (i < ss->nWindows)
            {
                  if (ss->windows[i] == w)
                  {
                        inList = TRUE;

                        if (w->id == selected)
                        {
                              if (i < ss->nWindows)
                                    selected = ss->windows[i + 1]->id;
                              else
                                    selected = ss->windows[0]->id;
                        }

                        ss->nWindows--;
                        for (j = i; j < ss->nWindows; j++)
                              ss->windows[j] = ss->windows[j + 1];
                  }
                  else
                  {
                        i++;
                  }
            }

            if (!inList)
                  return;

            count = ss->nWindows;

            if (ss->nWindows == 2)
            {
                  if (ss->windows[0] == ss->windows[1])
                  {
                        ss->nWindows--;
                        count = 1;
                  }
                  else
                  {
                        switchAddWindowToList(w->screen, ss->windows[0]);
                        switchAddWindowToList(w->screen, ss->windows[1]);
                  }
            }

            if (ss->nWindows == 0)
            {
                  CompOption o;

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

                  switchTerminate(d, NULL, 0, &o, 1);
                  return;
            }

            if (!ss->grabIndex)
                  return;

            switchUpdateWindowList(w->screen, count);

            for (i = 0; i < ss->nWindows; i++)
            {
                  ss->selectedWindow = ss->windows[i]->id;

                  if (ss->selectedWindow == selected)
                        break;

                  ss->pos -= WIDTH;
                  if (ss->pos < -ss->nWindows * WIDTH)
                        ss->pos += ss->nWindows * WIDTH;
            }

            if (ss->popupWindow)
            {
                  CompWindow *popup;

                  popup = findWindowAtScreen(w->screen, ss->popupWindow);
                  if (popup)
                        addWindowDamage(popup);

                  setSelectedWindowHint(w->screen);
            }

            if (old != ss->selectedWindow)
            {
                  addWindowDamage(w);

                  w = findWindowAtScreen(w->screen, old);
                  if (w)
                        addWindowDamage(w);

                  ss->moreAdjust = 1;
            }
      }
}

static void switchHandleEvent(CompDisplay * d, XEvent * event)
{
      SWITCH_DISPLAY(d);

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

      switch (event->type)
      {
      case UnmapNotify:
            switchWindowRemove(d, event->xunmap.window);
            break;
      case DestroyNotify:
            switchWindowRemove(d, event->xdestroywindow.window);
      default:
            break;
      }
}

static int adjustSwitchVelocity(CompScreen * s)
{
      float dx, adjust, amount;

      SWITCH_SCREEN(s);

      dx = ss->move;

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

      ss->mVelocity = (amount * ss->mVelocity + adjust) / (amount + 1.0f);

      if (ss->zooming)
      {
            float dt, ds;

            if (ss->switching)
                  dt = ss->zoom - ss->translate;
            else
                  dt = 0.0f - ss->translate;

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

            ss->tVelocity = (amount * ss->tVelocity + adjust) / (amount + 1.0f);

            if (ss->selectedWindow == ss->zoomedWindow)
                  ds = ss->zoom - ss->sTranslate;
            else
                  ds = 0.0f - ss->sTranslate;

            adjust = ds * 0.5f;
            amount = fabs(ds) * 5.0f;
            if (amount < 1.0f)
                  amount = 1.0f;
            else if (amount > 6.0f)
                  amount = 6.0f;

            ss->sVelocity = (amount * ss->sVelocity + adjust) / (amount + 1.0f);

            if (ss->selectedWindow == ss->zoomedWindow)
            {
                  if (fabs(dx) < 0.1f && fabs(ss->mVelocity) < 0.2f
                        && fabs(dt) < 0.002f
                        && fabs(ss->tVelocity) < 0.002f
                        && fabs(ds) < 0.002f && fabs(ss->sVelocity) < 0.002f)
                  {
                        ss->mVelocity = ss->tVelocity = ss->sVelocity = 0.0f;
                        return 0;
                  }
            }
      }
      else
      {
            if (fabs(dx) < 0.1f && fabs(ss->mVelocity) < 0.2f)
            {
                  ss->mVelocity = 0.0f;
                  return 0;
            }
      }

      return 1;
}

static void switchPreparePaintScreen(CompScreen * s, int msSinceLastPaint)
{
      SWITCH_SCREEN(s);

      if (ss->moreAdjust)
      {
            int steps, m;
            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 = adjustSwitchVelocity(s);
                  if (!ss->moreAdjust)
                  {
                        ss->pos += ss->move;
                        ss->move = 0;

                        if (ss->zooming)
                        {
                              if (ss->switching)
                              {
                                    ss->translate = ss->zoom;
                                    ss->sTranslate = ss->zoom;
                              }
                              else
                              {
                                    ss->translate = 0.0f;
                                    ss->sTranslate = ss->zoom;

                                    ss->selectedWindow = None;
                                    ss->zoomedWindow = None;

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

                  m = ss->mVelocity * chunk;
                  if (!m)
                  {
                        if (ss->mVelocity)
                              m = (ss->move > 0) ? 1 : -1;
                  }

                  ss->move -= m;
                  ss->pos += m;

                  if (ss->switchMode == ApplicationSwitcher)
                  {
                        if (ss->pos < -ss->nWindows * WIDTH)
                              ss->pos += ss->nWindows * WIDTH;
                        else if (ss->pos > 0)
                              ss->pos -= ss->nWindows * WIDTH;
                  }

                  ss->translate += ss->tVelocity * chunk;
                  ss->sTranslate += ss->sVelocity * chunk;

                  if (ss->selectedWindow != ss->zoomedWindow)
                  {
                        if (ss->sTranslate < 0.01f)
                              ss->zoomedWindow = ss->selectedWindow;
                  }
            }
      }

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

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

      SWITCH_SCREEN(s);

      if (ss->grabIndex || (ss->zooming && ss->translate > 0.001f))
      {
            ScreenPaintAttrib sa = *sAttrib;
            CompWindow *zoomed;
            CompWindow *switcher;
            Window zoomedAbove = None;
            Bool saveDestroyed = FALSE;

            if (ss->zooming || (ss->switchMode == RingSwitcher))
            {
                  mask &= ~PAINT_SCREEN_REGION_MASK;
                  mask |= PAINT_SCREEN_TRANSFORMED_MASK | PAINT_SCREEN_CLEAR_MASK;

                  sa.zCamera -= ss->translate;
            }

            switcher = findWindowAtScreen(s, ss->popupWindow);
            if (switcher)
            {
                  saveDestroyed = switcher->destroyed;
                  switcher->destroyed = TRUE;
            }

            if (ss->bringToFront)
            {
                  zoomed = findWindowAtScreen(s, ss->zoomedWindow);
                  if (zoomed)
                  {
                        CompWindow *w;

                        for (w = zoomed->prev; w && w->id <= 1; w = w->prev);
                        zoomedAbove = (w) ? w->id : None;

                        unhookWindowFromScreen(s, zoomed);
                        insertWindowIntoScreen(s, zoomed, s->reverseWindows->id);
                  }
            }
            else
            {
                  zoomed = NULL;
            }

            UNWRAP(ss, s, paintScreen);
            status = (*s->paintScreen) (s, &sa, region, output, mask);
            WRAP(ss, s, paintScreen, switchPaintScreen);

            if (zoomed)
            {
                  unhookWindowFromScreen(s, zoomed);
                  insertWindowIntoScreen(s, zoomed, zoomedAbove);
            }

            if (switcher)
            {
                  switcher->destroyed = saveDestroyed;

                  glPushMatrix();

                  prepareXCoords(s, output, -DEFAULT_Z_CAMERA);

                  if (!switcher->destroyed &&
                        switcher->attrib.map_state == IsViewable && switcher->damaged)
                  {
                        (*s->paintWindow) (switcher,
                                                   &switcher->paint, getInfiniteRegion(), 0);
                  }

                  glPopMatrix();
            }
      }
      else
      {
            UNWRAP(ss, s, paintScreen);
            status = (*s->paintScreen) (s, sAttrib, region, output, mask);
            WRAP(ss, s, paintScreen, switchPaintScreen);
      }

      return status;
}

static void switchDonePaintScreen(CompScreen * s)
{
      SWITCH_SCREEN(s);

      if ((ss->grabIndex || ss->zooming) && ss->moreAdjust)
      {
            if (ss->zooming || (ss->switchMode == RingSwitcher))
            {
                  damageScreen(s);
            }
            else
            {
                  CompWindow *w;

                  w = findWindowAtScreen(s, ss->popupWindow);
                  if (w)
                        addWindowDamage(w);
            }
      }

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

static void
switchPaintThumb(CompWindow * w,
                         const WindowPaintAttrib * attrib,
                         unsigned int mask, int x, int y, int x1, int x2, float scale)
{
      DrawWindowGeometryProc oldDrawWindowGeometry;
      AddWindowGeometryProc oldAddWindowGeometry;
      WindowPaintAttrib sAttrib = *attrib;
      int wx, wy;
      float width, height;
      CompIcon *icon = NULL;

      SWITCH_SCREEN(w->screen);

      /* Wrap drawWindowGeometry to make sure the general
         drawWindowGeometry function is used */
      oldDrawWindowGeometry = w->screen->drawWindowGeometry;
      w->screen->drawWindowGeometry = getBaseDrawWindowGeometry();
      oldAddWindowGeometry = w->screen->addWindowGeometry;
      w->screen->addWindowGeometry = getBaseAddWindowGeometry();

      mask |= PAINT_WINDOW_TRANSFORMED_MASK;

      if (w->mapNum || w->thumbPixmap)
      {
            int ww, wh;

            if (ss->switchMode == RingSwitcher)
            {
                  width = ss->opt[SWITCH_SCREEN_OPTION_THUMBNAIL_WIDTH].value.i;
                  height = ss->opt[SWITCH_SCREEN_OPTION_THUMBNAIL_HEIGHT].value.i;
            }
            else
            {
                  width = WIDTH - (SPACE << 1);
                  height = HEIGHT - (SPACE << 1);
            }

            ww = w->width + w->input.left + w->input.right;
            wh = w->height + w->input.top + w->input.bottom;

            if (ww > width)
                  sAttrib.xScale = width / ww;
            else
                  sAttrib.xScale = 1.0f;

            if (wh > height)
                  sAttrib.yScale = height / wh;
            else
                  sAttrib.yScale = 1.0f;

            if (sAttrib.xScale < sAttrib.yScale)
                  sAttrib.yScale = sAttrib.xScale;
            else
                  sAttrib.xScale = sAttrib.yScale;

            width = ww * sAttrib.xScale;
            height = wh * sAttrib.yScale;

            if (ss->switchMode == RingSwitcher)
            {
                  sAttrib.xScale *= scale;
                  sAttrib.yScale *= scale;

                  x -= ((w->width * sAttrib.xScale) / 2.0f);

                  wx = x;
                  wy = y;
            }
            else
            {
                  wx = x + SPACE + ((WIDTH - (SPACE << 1)) - width) / 2;
                  wy = y + SPACE + ((HEIGHT - (SPACE << 1)) - height) / 2;
            }

            sAttrib.xTranslate =
                        wx - w->attrib.x + w->input.left * sAttrib.xScale;
            sAttrib.yTranslate = wy - w->attrib.y + w->input.top * sAttrib.yScale;

            (w->screen->drawWindow) (w, &sAttrib, getInfiniteRegion(), mask);

            if (ss->opt[SWITCH_SCREEN_OPTION_ICON].value.b)
            {
                  icon = getWindowIcon(w, 96, 96);
                  if (!icon)
                        icon = getWindowIcon(w, 128, 128);
                  if (!icon)
                        icon = getWindowIcon(w, 256, 256);
                  if (!icon)
                        icon = getWindowIcon(w, 512, 512);

                  if (icon)
                  {
                        if (icon->width > 96)
                        {
                              sAttrib.xScale = sAttrib.yScale =
                                          MIN((48.0f /
                                                 (float)icon->width),
                                                (48.0f / (float)icon->height));
                        }
                        else
                              sAttrib.xScale = sAttrib.yScale = 1.0f * scale;

                        float wwidth, wspace, iwidth;
                        float wheight, iheight;
                        if (ss->switchMode == RingSwitcher)
                        {
                              wwidth = width * scale;
                              wheight = height * scale;
                              wspace = 0;
                              iwidth = icon->width * scale;
                              iheight = icon->height * scale;
                        }
                        else
                        {
                              wx = x + WIDTH - icon->width * sAttrib.xScale - SPACE;

                              wwidth = WIDTH;
                              wheight = HEIGHT;
                              wspace = SPACE;
                              iwidth = icon->width;
                              iheight = icon->height;
                        }

                        switch(ss->iconCorner)
                        {
                        case BottomRight:
                              wx = x + (wwidth - wspace) - iwidth;
                              wy = y + (wheight - wspace) - iheight;
                              break;
                        case BottomLeft:
                              wx = x + wspace;
                              wy = y + (wheight - wspace) - iheight;
                              break;
                        case TopRight:
                              wx = x + (wwidth - wspace) - iwidth;
                              wy = y + wspace;
                              break;
                        case TopLeft:
                              wx = x + wspace;
                              wy = y + wspace;
                              break;
                        case Center:
                              wx = x + (wwidth / 2) - (iwidth / 2);
                              wy = y + (wheight / 2) - (iheight / 2);
                              break;
                        }
                  }
            }
      }
      else
      {
            if (ss->switchMode == RingSwitcher)
            {
                  width = ss->opt[SWITCH_SCREEN_OPTION_THUMBNAIL_WIDTH].value.i;
                  height = ss->opt[SWITCH_SCREEN_OPTION_THUMBNAIL_HEIGHT].value.i;
            }
            else
            {
                  width = WIDTH;
                  height = HEIGHT;
            }
            width *= 0.75f;
            height *= 0.75f;

            icon = getWindowIcon(w, width, height);
            if (!icon)
                  icon = w->screen->defaultIcon;

            if (icon)
            {
                  int iw, ih;

                  iw = width - SPACE;
                  ih = height - SPACE;

                  if (icon->width < (iw >> 1))
                        sAttrib.xScale = (iw / icon->width);
                  else
                        sAttrib.xScale = 1.0f;

                  if (icon->height < (ih >> 1))
                        sAttrib.yScale = (ih / icon->height);
                  else
                        sAttrib.yScale = 1.0f;

                  if (sAttrib.xScale < sAttrib.yScale)
                        sAttrib.yScale = sAttrib.xScale;
                  else
                        sAttrib.xScale = sAttrib.yScale;

                  width = icon->width * sAttrib.xScale;
                  height = icon->height * sAttrib.yScale;

                  if (ss->switchMode == RingSwitcher)
                  {
                        sAttrib.xScale *= scale;
                        sAttrib.yScale *= scale;

                        wx = x + SPACE + ((ss->opt[SWITCH_SCREEN_OPTION_THUMBNAIL_WIDTH].value.i - (SPACE << 1)) - width) / 2;
                        wy = y + SPACE + ((ss->opt[SWITCH_SCREEN_OPTION_THUMBNAIL_HEIGHT].value.i - (SPACE << 1)) - height) / 2;
                  }
                  else
                  {
                        wx = x + SPACE + ((WIDTH - (SPACE << 1)) - width) / 2;
                        wy = y + SPACE + ((HEIGHT - (SPACE << 1)) - height) / 2;
                  }
            }
      }

      if (icon && (icon->texture.name || iconToTexture(w->screen, icon)))
      {
            REGION iconReg;
            CompMatrix matrix;

            mask |= PAINT_WINDOW_TRANSLUCENT_MASK;

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

            iconReg.extents.x1 = w->attrib.x;
            iconReg.extents.y1 = w->attrib.y;
            iconReg.extents.x2 = w->attrib.x + icon->width;
            iconReg.extents.y2 = w->attrib.y + icon->height;

            matrix = icon->texture.matrix;
            matrix.x0 -= (w->attrib.x * icon->texture.matrix.xx);
            matrix.y0 -= (w->attrib.y * icon->texture.matrix.yy);

            sAttrib.xTranslate = wx - w->attrib.x;
            sAttrib.yTranslate = wy - w->attrib.y;

            w->vCount = 0;
            addWindowGeometry(w, &matrix, 1, &iconReg, getInfiniteRegion());

            if (w->vCount)
                  (*w->screen->drawWindowTexture) (w,
                                                                   &icon->texture, &sAttrib, mask);
      }

      w->screen->drawWindowGeometry = oldDrawWindowGeometry;
      w->screen->addWindowGeometry = oldAddWindowGeometry;
}

static float calc_ellipse(float x,float a, float b)
{
      return sqrt((b*b)*(1-((x*x)/(a*a))));
}

typedef struct
{
      float y;
      float x;
      float scale;
      int index;
} ArrayElement;

static int compareElements(const void *elem1, const void *elem2)
{
      ArrayElement *a1 = (ArrayElement *) elem1;
      ArrayElement *a2 = (ArrayElement *) elem2;

      if(a1->y < a2->y)
            return -1;
      else if(a1->y > a2->y)
            return 1;
      else
            return 0;
}

static Bool
switchPaintWindow(CompWindow * w,
                          const WindowPaintAttrib * attrib,
                          Region region, unsigned int mask)
{
      CompScreen *s = w->screen;
      Bool status;
      ArrayElement *draw_array = NULL;
      XRectangle outputRect;
      int xo, yo;

      SWITCH_SCREEN(s);

      if (ss->switchMode == RingSwitcher)
      {
            screenGetOutputDevRect(s, ss->head, &outputRect);
            xo = outputRect.x + outputRect.width/2.0f;
            yo = outputRect.y + (outputRect.height/2.0f) - (outputRect.height/5.0f);

            draw_array = malloc(ss->nWindows*sizeof(ArrayElement));
      }

      if (w->id == ss->popupWindow)
      {
            GLenum filter;
            int x, y, x1, x2, cx, i;

            if (mask & PAINT_WINDOW_SOLID_MASK)
                  return FALSE;

            UNWRAP(ss, s, paintWindow);
            status = (*s->paintWindow) (w, attrib, region, mask);
            WRAP(ss, s, paintWindow, switchPaintWindow);

            if (!(mask & PAINT_WINDOW_TRANSFORMED_MASK) && region->numRects == 0)
                  return TRUE;

            x1 = w->attrib.x + SPACE;
            x2 = w->attrib.x + w->width - SPACE;

            x = x1 + ss->pos;
            y = w->attrib.y + SPACE;

            filter = s->display->textureFilter;

            if (ss->opt[SWITCH_SCREEN_OPTION_MIPMAP].value.b)
                  s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;

            glPushAttrib(GL_SCISSOR_BIT);
            glEnable(GL_SCISSOR_TEST);
            glScissor(x1, 0, x2 - x1, w->screen->height);

            if (ss->switchMode == RingSwitcher)
            {
                  int x_pos = x;
                  Bool front = FALSE;
                  int tmp = 0;
                  ELLIPSE_ROTA(outputRect);
                  ELLIPSE_ROTB(outputRect);
                  DIST_ROT;
                  int sw = 0;
                  float y_max = calc_ellipse(0,ellipse_a,ellipse_b);

                  for (i = 0; i < ss->nWindows; i++)
                  {
                        tmp = x + (i * dist);
                        sw = (abs(tmp) / (2 * ellipse_a)) % 2;

                        switch(sw)
                        {
                        case 0:
                              x_pos = ellipse_a - (abs(tmp) % (2 * ellipse_a));
                              front = (tmp >= 0);
                              break;
                        case 1:
                              if(tmp < 0)
                              {
                                    x_pos = ((abs(tmp) % (2*ellipse_a))-ellipse_a);
                                    front = TRUE;
                              }
                              else
                              {
                                    x_pos = -1 * (ellipse_a - (abs(tmp) % (2 * ellipse_a)));
                                    front = FALSE;
                              }
                              break;
                        }

                        if (front)
                        {
                              draw_array[i].x = x_pos + xo;
                              draw_array[i].y = calc_ellipse(x_pos, ellipse_a, ellipse_b) + yo;

                              draw_array[i].scale = 1.0f + ((draw_array[i].y - yo) / y_max) / 0.9f;
                              draw_array[i].index = i;
                        }
                        else
                        {
                              draw_array[i].x = x_pos + xo;
                              draw_array[i].y = -1 * calc_ellipse(x_pos, ellipse_a, ellipse_b) + yo;

                              draw_array[i].scale = 1.0f - ((-1 * (draw_array[i].y - yo)) / y_max) + 0.4f;
                              draw_array[i].index = i;
                        }
                  }

                  qsort(draw_array, ss->nWindows, sizeof(ArrayElement), compareElements);

                  for (i = 0; i < ss->nWindows; i++)
                  {
                        switchPaintThumb(ss->windows[draw_array[i].index],
                                    &w->lastPaint, mask, draw_array[i].x,
                                    draw_array[i].y , x1, x2,draw_array[i].scale);
                  }
            }
            else
            {
                  for (i = 0; i < ss->nWindows; i++)
                  {
                        if (x + WIDTH > x1)
                              switchPaintThumb(ss->windows[i], &w->lastPaint,
                                                      mask, x, y, x1, x2, 1.0f);

                        x += WIDTH;
                  }

                  for (i = 0; i < ss->nWindows; i++)
                  {
                        if (x > x2)
                              break;

                        switchPaintThumb(ss->windows[i], &w->lastPaint,
                                                 mask, x, y, x1, x2, 1.0f);

                        x += WIDTH;
                  }
            }

            glPopAttrib();

            s->display->textureFilter = filter;

            cx = w->attrib.x + (w->width >> 1);

            if (ss->switchMode == ApplicationSwitcher)
            {
                  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
                  glEnable(GL_BLEND);
                  glColor4us(0, 0, 0, w->lastPaint.opacity);
                  glPushMatrix();
                  glTranslatef(cx, y, 0.0f);
                  glVertexPointer(2, GL_FLOAT, 0, _boxVertices);
                  glDrawArrays(GL_QUADS, 0, 16);
                  glPopMatrix();
                  glColor4usv(defaultColor);
                  glDisable(GL_BLEND);
                  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
            }
      }
      else if (w->id == ss->selectedWindow)
      {
            glPushMatrix();

            if (ss->bringToFront)
            {
                  if ((ss->selectedWindow == ss->zoomedWindow) &&
                              !IPCS_GetBool(IPCS_OBJECT(s), ss->insideAtom))
                        glTranslatef(0.0f, 0.0f, MIN(ss->translate, ss->sTranslate));
            }

            if (((ss->wMask & w->type) && ss->opacity != OPAQUE) && 
                  (ss->opt[SWITCH_SCREEN_OPTION_RING_TRANSPARENT_ALL].value.b && 
                  (ss->switchMode == RingSwitcher)))
            {
                  status = TRUE;
            }
            else
            {
                  UNWRAP(ss, s, paintWindow);
                  status = (*s->paintWindow) (w, attrib, region, mask);
                  WRAP(ss, s, paintWindow, switchPaintWindow);
            }

            glPopMatrix();
      }
      else if (ss->switching)
      {
            WindowPaintAttrib sAttrib = *attrib;

            if (ss->saturation != COLOR)
                  sAttrib.saturation = (sAttrib.saturation * ss->saturation) >> 16;

            if (ss->brightness != 0xffff)
                  sAttrib.brightness = (sAttrib.brightness * ss->brightness) >> 16;

            if ((ss->wMask & w->type) && ss->opacity != OPAQUE)
                  sAttrib.opacity = (sAttrib.opacity * ss->opacity) >> 16;

            if (((ss->wMask & w->type) && ss->opacity != OPAQUE) && 
                  (ss->opt[SWITCH_SCREEN_OPTION_RING_TRANSPARENT_ALL].value.b && 
                  (ss->switchMode == RingSwitcher)))
            {
                  status = TRUE;
            }
            else
            {
                  if (ss->bringToFront && w->id == ss->zoomedWindow)
                  {
                        glPushMatrix();
                        glTranslatef(0.0f, 0.0f, MIN(ss->translate, ss->sTranslate));

                        UNWRAP(ss, s, paintWindow);
                        status = (*s->paintWindow) (w, &sAttrib, region, mask);
                        WRAP(ss, s, paintWindow, switchPaintWindow);
      
                        glPopMatrix();
                  }
                  else
                  {
                        UNWRAP(ss, s, paintWindow);
                        status = (*s->paintWindow) (w, &sAttrib, region, mask);
                        WRAP(ss, s, paintWindow, switchPaintWindow);
                  }
            }
      }
      else
      {
            UNWRAP(ss, s, paintWindow);
            status = (*s->paintWindow) (w, attrib, region, mask);
            WRAP(ss, s, paintWindow, switchPaintWindow);
      }

      if (draw_array)
            free(draw_array);

      return status;
}

static Bool switchDamageWindowRect(CompWindow * w, Bool initial, BoxPtr rect)
{
      Bool status;

      SWITCH_SCREEN(w->screen);

      if (ss->grabIndex)
      {
            CompWindow *popup;
            int i;

            for (i = 0; i < ss->nWindows; i++)
            {
                  if (ss->windows[i] == w)
                  {
                        popup = findWindowAtScreen(w->screen, ss->popupWindow);
                        if (popup)
                              addWindowDamage(popup);

                        break;
                  }
            }
      }

      UNWRAP(ss, w->screen, damageWindowRect);
      status = (*w->screen->damageWindowRect) (w, initial, rect);
      WRAP(ss, w->screen, damageWindowRect, switchDamageWindowRect);

      return status;
}

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

      SWITCH_DISPLAY(display);

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

      switch (index)
      {
      case SWITCH_DISPLAY_OPTION_NEXT:
      case SWITCH_DISPLAY_OPTION_NEXT_ALL:
      case SWITCH_DISPLAY_OPTION_PREV:
      case SWITCH_DISPLAY_OPTION_PREV_ALL:
      case SWITCH_DISPLAY_OPTION_RING_NEXT:
      case SWITCH_DISPLAY_OPTION_RING_NEXT_ALL:
      case SWITCH_DISPLAY_OPTION_RING_PREV:
      case SWITCH_DISPLAY_OPTION_RING_PREV_ALL:
            if (setDisplayAction(display, o, value))
                  return TRUE;
      default:
            break;
      }

      return FALSE;
}

static void switchDisplayInitOptions(SwitchDisplay * sd)
{
      CompOption *o;

      o = &sd->opt[SWITCH_DISPLAY_OPTION_NEXT];
      o->advanced = False;
      o->name = "next";
      o->group = N_("Bindings");
      o->subGroup = N_("Current workspace");
      o->displayHints = "";
      o->shortDesc = N_("Next Window");
      o->longDesc = N_("Popup Switcher if not visible and "
                               "select Next Window.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = switchNext;
      o->value.action.terminate = switchTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = SWITCH_NEXT_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(SWITCH_NEXT_KEY_DEFAULT);

      o = &sd->opt[SWITCH_DISPLAY_OPTION_PREV];
      o->advanced = False;
      o->name = "prev";
      o->group = N_("Bindings");
      o->subGroup = N_("Current workspace");
      o->displayHints = "";
      o->shortDesc = N_("Prev Window");
      o->longDesc = N_("Popup Switcher if not visible and "
                               "select Previous Window.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = switchPrev;
      o->value.action.terminate = switchTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = SWITCH_PREV_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(SWITCH_PREV_KEY_DEFAULT);

      o = &sd->opt[SWITCH_DISPLAY_OPTION_NEXT_ALL];
      o->advanced = False;
      o->name = "next_all";
      o->group = N_("Bindings");
      o->subGroup = N_("All workspaces");
      o->displayHints = "";
      o->shortDesc = N_("Next Window (All Workspaces)");
      o->longDesc = N_("Popup Switcher if not visible and "
                               "select Next Window out of All Windows.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = switchNextAll;
      o->value.action.terminate = switchTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = SWITCH_NEXT_ALL_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(SWITCH_NEXT_ALL_KEY_DEFAULT);

      o = &sd->opt[SWITCH_DISPLAY_OPTION_PREV_ALL];
      o->advanced = False;
      o->name = "prev_all";
      o->group = N_("Bindings");
      o->subGroup = N_("All workspaces");
      o->displayHints = "";
      o->shortDesc = N_("Prev Window (All Workspaces)");
      o->longDesc = N_("Popup Switcher if not visible and "
                               "select Previous Window out of All Windows.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = switchPrevAll;
      o->value.action.terminate = switchTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = SWITCH_PREV_ALL_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(SWITCH_PREV_ALL_KEY_DEFAULT);

      o = &sd->opt[SWITCH_DISPLAY_OPTION_RING_NEXT];
      o->advanced = False;
      o->name = "next_ring";
      o->group = N_("Bindings (Ring)");
      o->subGroup = N_("Current workspace");
      o->displayHints = "";
      o->shortDesc = N_("Next Window");
      o->longDesc = N_("Popup Switcher if not visible and "
                               "select Next Window.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = switchNextRing;
      o->value.action.terminate = switchTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = SWITCH_RING_NEXT_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(SWITCH_RING_NEXT_KEY_DEFAULT);

      o = &sd->opt[SWITCH_DISPLAY_OPTION_RING_PREV];
      o->advanced = False;
      o->name = "prev_ring";
      o->group = N_("Bindings (Ring)");
      o->subGroup = N_("Current workspace");
      o->displayHints = "";
      o->shortDesc = N_("Prev Window");
      o->longDesc = N_("Popup Switcher if not visible and "
                               "select Previous Window.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = switchPrevRing;
      o->value.action.terminate = switchTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = SWITCH_RING_PREV_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(SWITCH_RING_PREV_KEY_DEFAULT);

      o = &sd->opt[SWITCH_DISPLAY_OPTION_RING_NEXT_ALL];
      o->advanced = False;
      o->name = "next_all_ring";
      o->group = N_("Bindings (Ring)");
      o->subGroup = N_("All workspaces");
      o->displayHints = "";
      o->shortDesc = N_("Next Window (All Workspaces)");
      o->longDesc = N_("Popup Switcher if not visible and "
                               "select Next Window out of All Windows.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = switchNextAllRing;
      o->value.action.terminate = switchTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = SWITCH_RING_NEXT_ALL_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(SWITCH_RING_NEXT_ALL_KEY_DEFAULT);

      o = &sd->opt[SWITCH_DISPLAY_OPTION_RING_PREV_ALL];
      o->advanced = False;
      o->name = "prev_all_ring";
      o->group = N_("Bindings (Ring)");
      o->subGroup = N_("All workspaces");
      o->displayHints = "";
      o->shortDesc = N_("Prev Window (All Workspaces)");
      o->longDesc = N_("Popup Switcher if not visible and "
                               "select Previous Window out of All Windows.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = switchPrevAllRing;
      o->value.action.terminate = switchTerminate;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.state |= CompActionStateInitButton;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.key.modifiers = SWITCH_RING_PREV_ALL_MODIFIERS_DEFAULT;
      o->value.action.key.keysym = XStringToKeysym(SWITCH_RING_PREV_ALL_KEY_DEFAULT);
}

static CompOption *switchGetDisplayOptions(CompDisplay * display, int *count)
{
      if (display)
      {
            SWITCH_DISPLAY(display);

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

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


static Bool switchInitDisplay(CompPlugin * p, CompDisplay * d)
{
      SwitchDisplay *sd;

      sd = malloc(sizeof(SwitchDisplay));
      if (!sd)
            return FALSE;

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

      sd->selectWinAtom = XInternAtom(d->display, SELECT_WIN_PROP, 0);

      switchDisplayInitOptions(sd);

      WRAP(sd, d, handleEvent, switchHandleEvent);

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

      return TRUE;
}

static void switchFiniDisplay(CompPlugin * p, CompDisplay * d)
{
      SWITCH_DISPLAY(d);

      freeScreenPrivateIndex(d, sd->screenPrivateIndex);

      UNWRAP(sd, d, handleEvent);

      free(sd);
}

static Bool switchInitScreen(CompPlugin * p, CompScreen * s)
{
      SwitchScreen *ss;

      SWITCH_DISPLAY(s->display);

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

      ss->popupWindow = None;

      ss->selectedWindow = None;
      ss->zoomedWindow = None;

      ss->lastActiveNum = 0;

      ss->windows = 0;
      ss->nWindows = 0;
      ss->windowsSize = 0;

      ss->pos = ss->move = 0;

      ss->switching = FALSE;
      ss->prevMin = NULL;

      ss->grabIndex = 0;

      ss->speed = SWITCH_SPEED_DEFAULT;
      ss->timestep = SWITCH_TIMESTEP_DEFAULT;
      ss->zoom = SWITCH_ZOOM_DEFAULT / 30.0f;

      ss->zooming = (SWITCH_ZOOM_DEFAULT > 0.05f) ? TRUE : FALSE;

      ss->moreAdjust = 0;

      ss->mVelocity = 0.0f;
      ss->tVelocity = 0.0f;
      ss->sVelocity = 0.0f;

      ss->translate = 0.0f;
      ss->sTranslate = 0.0f;

      ss->saturation = (COLOR * SWITCH_SATURATION_DEFAULT) / 100;
      ss->brightness = (0xffff * SWITCH_BRIGHTNESS_DEFAULT) / 100;
      ss->opacity = (OPAQUE * SWITCH_OPACITY_DEFAULT) / 100;

      ss->bringToFront = SWITCH_BRINGTOFRONT_DEFAULT;
      ss->showWindowList = SWITCH_SHOW_WINDOW_LIST_DEFAULT;
      ss->autoRotate = SWITCH_AUTO_ROTATE_DEFAULT;
      ss->autoRotate = SWITCH_TEMP_UNMINIMIZE_DEFAULT;
      ss->allWindows = FALSE;
      ss->head = 0;
      ss->tempUnMinimize = FALSE;
      ss->switchMode = ApplicationSwitcher;
      ss->iconCorner = SWITCH_ICON_CORNER_DEFAULT;

      ss->insideAtom = IPCS_GetAtom(IPCS_OBJECT(s), IPCS_BOOL, "INSIDE", TRUE);

      switchScreenInitOptions(ss);

      addScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_NEXT].value.action);
      addScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_PREV].value.action);
      addScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_NEXT_ALL].value.action);
      addScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_PREV_ALL].value.action);
      addScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_RING_NEXT].value.action);
      addScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_RING_PREV].value.action);
      addScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_RING_NEXT_ALL].value.action);
      addScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_RING_PREV_ALL].value.action);

      WRAP(ss, s, preparePaintScreen, switchPreparePaintScreen);
      WRAP(ss, s, donePaintScreen, switchDonePaintScreen);
      WRAP(ss, s, paintScreen, switchPaintScreen);
      WRAP(ss, s, paintWindow, switchPaintWindow);
      WRAP(ss, s, damageWindowRect, switchDamageWindowRect);

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

      return TRUE;
}

static void switchFiniScreen(CompPlugin * p, CompScreen * s)
{
      SWITCH_SCREEN(s);
      SWITCH_DISPLAY(s->display);

      UNWRAP(ss, s, preparePaintScreen);
      UNWRAP(ss, s, donePaintScreen);
      UNWRAP(ss, s, paintScreen);
      UNWRAP(ss, s, paintWindow);
      UNWRAP(ss, s, damageWindowRect);

      removeScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_NEXT].value.action);
      removeScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_PREV].value.action);
      removeScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_NEXT_ALL].value.action);
      removeScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_PREV_ALL].value.action);
      removeScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_RING_NEXT].value.action);
      removeScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_RING_PREV].value.action);
      removeScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_RING_NEXT_ALL].value.action);
      removeScreenAction(s, &sd->opt[SWITCH_DISPLAY_OPTION_RING_PREV_ALL].value.action);

      if (ss->popupWindow)
            XDestroyWindow(s->display->display, ss->popupWindow);

      if (ss->windowsSize)
            free(ss->windows);

      free(ss);
}

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

      return TRUE;
}

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

CompPluginDep setDeps[] = {
      {CompPluginRuleAfter, "cube"},
      {CompPluginRuleAfter, "decoration"},
};

CompPluginVTable switchVTable = {
      "switcher",
      N_("Application Window Switcher"),
      N_("Application Window Switcher"),
      switchInit,
      switchFini,
      switchInitDisplay,
      switchFiniDisplay,
      switchInitScreen,
      switchFiniScreen,
      0,
      0,
      switchGetDisplayOptions,
      switchSetDisplayOption,
      switchGetScreenOptions,
      switchSetScreenOption,
      setDeps,
      sizeof(setDeps) / sizeof(setDeps[0]),
      0,
      0,
      BERYL_ABI_INFO,
      "beryl-plugins",
      "wm",
      0,
      0,
      True,
};

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

Generated by  Doxygen 1.6.0   Back to index