summaryrefslogtreecommitdiff
path: root/plugins/switcher.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/switcher.c')
-rw-r--r--plugins/switcher.c2134
1 files changed, 2134 insertions, 0 deletions
diff --git a/plugins/switcher.c b/plugins/switcher.c
new file mode 100644
index 0000000..116ed91
--- /dev/null
+++ b/plugins/switcher.c
@@ -0,0 +1,2134 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * 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 <compiz-core.h>
+#include <decoration.h>
+
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrender.h>
+
+#define ZOOMED_WINDOW_MASK (1 << 0)
+#define NORMAL_WINDOW_MASK (1 << 1)
+
+static CompMetadata switchMetadata;
+
+static int displayPrivateIndex;
+
+#define SWITCH_DISPLAY_OPTION_NEXT_BUTTON 0
+#define SWITCH_DISPLAY_OPTION_NEXT_KEY 1
+#define SWITCH_DISPLAY_OPTION_PREV_BUTTON 2
+#define SWITCH_DISPLAY_OPTION_PREV_KEY 3
+#define SWITCH_DISPLAY_OPTION_NEXT_ALL_BUTTON 4
+#define SWITCH_DISPLAY_OPTION_NEXT_ALL_KEY 5
+#define SWITCH_DISPLAY_OPTION_PREV_ALL_BUTTON 6
+#define SWITCH_DISPLAY_OPTION_PREV_ALL_KEY 7
+#define SWITCH_DISPLAY_OPTION_NEXT_NO_POPUP_BUTTON 8
+#define SWITCH_DISPLAY_OPTION_NEXT_NO_POPUP_KEY 9
+#define SWITCH_DISPLAY_OPTION_PREV_NO_POPUP_BUTTON 10
+#define SWITCH_DISPLAY_OPTION_PREV_NO_POPUP_KEY 11
+#define SWITCH_DISPLAY_OPTION_NEXT_PANEL_BUTTON 12
+#define SWITCH_DISPLAY_OPTION_NEXT_PANEL_KEY 13
+#define SWITCH_DISPLAY_OPTION_PREV_PANEL_BUTTON 14
+#define SWITCH_DISPLAY_OPTION_PREV_PANEL_KEY 15
+#define SWITCH_DISPLAY_OPTION_NUM 16
+
+typedef struct _SwitchDisplay {
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+
+ CompOption opt[SWITCH_DISPLAY_OPTION_NUM];
+
+ Atom selectWinAtom;
+ Atom selectFgColorAtom;
+} SwitchDisplay;
+
+#define SWITCH_SCREEN_OPTION_SPEED 0
+#define SWITCH_SCREEN_OPTION_TIMESTEP 1
+#define SWITCH_SCREEN_OPTION_WINDOW_MATCH 2
+#define SWITCH_SCREEN_OPTION_MIPMAP 3
+#define SWITCH_SCREEN_OPTION_SATURATION 4
+#define SWITCH_SCREEN_OPTION_BRIGHTNESS 5
+#define SWITCH_SCREEN_OPTION_OPACITY 6
+#define SWITCH_SCREEN_OPTION_BRINGTOFRONT 7
+#define SWITCH_SCREEN_OPTION_ZOOM 8
+#define SWITCH_SCREEN_OPTION_ICON 9
+#define SWITCH_SCREEN_OPTION_MINIMIZED 10
+#define SWITCH_SCREEN_OPTION_AUTO_ROTATE 11
+#define SWITCH_SCREEN_OPTION_NUM 12
+
+typedef enum {
+ CurrentViewport = 0,
+ AllViewports,
+ Panels
+} SwitchWindowSelection;
+
+typedef struct _SwitchScreen {
+ PreparePaintScreenProc preparePaintScreen;
+ DonePaintScreenProc donePaintScreen;
+ PaintOutputProc paintOutput;
+ PaintWindowProc paintWindow;
+ DamageWindowRectProc damageWindowRect;
+
+ CompOption opt[SWITCH_SCREEN_OPTION_NUM];
+
+ Window popupWindow;
+
+ Window selectedWindow;
+ Window zoomedWindow;
+ unsigned int lastActiveNum;
+
+ float zoom;
+
+ int grabIndex;
+
+ Bool switching;
+ Bool zooming;
+ int zoomMask;
+
+ int moreAdjust;
+
+ GLfloat mVelocity;
+ GLfloat tVelocity;
+ GLfloat sVelocity;
+
+ CompWindow **windows;
+ int windowsSize;
+ int nWindows;
+
+ int pos;
+ int move;
+
+ float translate;
+ float sTranslate;
+
+ SwitchWindowSelection selection;
+
+ unsigned int fgColor[4];
+} SwitchScreen;
+
+#define MwmHintsDecorations (1L << 1)
+
+typedef struct {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+} MwmHints;
+
+#define WIDTH 212
+#define HEIGHT 192
+#define SPACE 10
+
+#define SWITCH_ZOOM 0.1f
+
+#define BOX_WIDTH 3
+
+#define ICON_SIZE 64
+
+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)->base.privates[displayPrivateIndex].ptr)
+
+#define SWITCH_DISPLAY(d) \
+ SwitchDisplay *sd = GET_SWITCH_DISPLAY (d)
+
+#define GET_SWITCH_SCREEN(s, sd) \
+ ((SwitchScreen *) (s)->base.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 CompOption *
+switchGetScreenOptions (CompPlugin *plugin,
+ CompScreen *screen,
+ int *count)
+{
+ SWITCH_SCREEN (screen);
+
+ *count = NUM_OPTIONS (ss);
+ return ss->opt;
+}
+
+static Bool
+switchSetScreenOption (CompPlugin *plugin,
+ CompScreen *screen,
+ const 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_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;
+ default:
+ return compSetScreenOption (screen, o, value);
+ }
+
+ return FALSE;
+}
+
+static void
+setSelectedWindowHint (CompScreen *s)
+{
+ SWITCH_DISPLAY (s->display);
+ SWITCH_SCREEN (s);
+
+ XChangeProperty (s->display->display, ss->popupWindow, sd->selectWinAtom,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &ss->selectedWindow, 1);
+}
+
+static Bool
+isSwitchWin (CompWindow *w)
+{
+ SWITCH_SCREEN (w->screen);
+
+ if (!w->mapNum || w->attrib.map_state != IsViewable)
+ {
+ if (ss->opt[SWITCH_SCREEN_OPTION_MINIMIZED].value.b)
+ {
+ if (!w->minimized && !w->inShowDesktopMode && !w->shaded)
+ return FALSE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ if (!(w->inputHint || (w->protocols & CompWindowProtocolTakeFocusMask)))
+ return FALSE;
+
+ if (w->attrib.override_redirect)
+ return FALSE;
+
+ if (ss->selection == Panels)
+ {
+ if (!(w->type & (CompWindowTypeDockMask | CompWindowTypeDesktopMask)))
+ return FALSE;
+ }
+ else
+ {
+ CompMatch *match;
+
+ if (w->wmType & (CompWindowTypeDockMask | CompWindowTypeDesktopMask))
+ return FALSE;
+
+ if (w->state & CompWindowStateSkipTaskbarMask)
+ return FALSE;
+
+ match = &ss->opt[SWITCH_SCREEN_OPTION_WINDOW_MATCH].value.match;
+ if (!matchEval (match, w))
+ return FALSE;
+
+ }
+
+ if (ss->selection == CurrentViewport)
+ {
+ 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 void
+switchActivateEvent (CompScreen *s,
+ Bool activating)
+{
+ CompOption o[2];
+
+ o[0].type = CompOptionTypeInt;
+ o[0].name = "root";
+ o[0].value.i = s->root;
+
+ o[1].type = CompOptionTypeBool;
+ o[1].name = "active";
+ o[1].value.b = activating;
+
+ (*s->display->handleCompizEvent) (s->display, "switcher", "activate", o, 2);
+}
+
+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)
+{
+ int x, y;
+
+ SWITCH_SCREEN (s);
+
+ if (count > 1)
+ {
+ count -= (count + 1) & 1;
+ if (count < 3)
+ count = 3;
+ }
+
+ ss->pos = ((count >> 1) - ss->nWindows) * WIDTH;
+ ss->move = 0;
+
+ ss->selectedWindow = ss->windows[0]->id;
+
+ x = s->outputDev[s->currentOutputDev].region.extents.x1 +
+ s->outputDev[s->currentOutputDev].width / 2;
+ y = s->outputDev[s->currentOutputDev].region.extents.y1 +
+ s->outputDev[s->currentOutputDev].height / 2;
+
+ if (ss->popupWindow)
+ XMoveResizeWindow (s->display->display, ss->popupWindow,
+ x - WINDOW_WIDTH (count) / 2,
+ y - 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->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;
+
+ if (ss->selection == AllViewports &&
+ ss->opt[SWITCH_SCREEN_OPTION_AUTO_ROTATE].value.b)
+ {
+ XEvent xev;
+ int x, y;
+
+ defaultViewportForWindow (w, &x, &y);
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = s->display->display;
+ xev.xclient.format = 32;
+
+ xev.xclient.message_type = s->display->desktopViewportAtom;
+ xev.xclient.window = s->root;
+
+ xev.xclient.data.l[0] = x * s->width;
+ xev.xclient.data.l[1] = y * s->height;
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+
+ XSendEvent (s->display->display, s->root, FALSE,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+ }
+
+ ss->lastActiveNum = w->activeNum;
+ ss->selectedWindow = w->id;
+
+ if (!ss->zoomedWindow)
+ ss->zoomedWindow = ss->selectedWindow;
+
+ if (old != w->id)
+ {
+ if (toNext)
+ ss->move -= WIDTH;
+ else
+ ss->move += WIDTH;
+
+ ss->moreAdjust = 1;
+ }
+
+ if (ss->popupWindow)
+ {
+ CompWindow *popup;
+
+ popup = findWindowAtScreen (s, ss->popupWindow);
+ if (popup)
+ addWindowDamage (popup);
+
+ setSelectedWindowHint (s);
+ }
+
+ addWindowDamage (w);
+
+ if (old)
+ {
+ w = findWindowAtScreen (s, old);
+ if (w)
+ addWindowDamage (w);
+ }
+ }
+}
+
+static int
+switchCountWindows (CompScreen *s)
+{
+ CompWindow *w;
+ int count = 0;
+
+ for (w = s->windows; w && count < 5; w = w->next)
+ if (isSwitchWin (w))
+ count++;
+
+ if (count == 5 && s->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
+switchInitiate (CompScreen *s,
+ SwitchWindowSelection selection,
+ Bool showPopup)
+{
+ int count;
+
+ SWITCH_SCREEN (s);
+
+ if (otherScreenGrabExist (s, "switcher", "scale", "cube", 0))
+ return;
+
+ ss->selection = selection;
+ ss->selectedWindow = None;
+
+ count = switchCountWindows (s);
+ if (count < 1)
+ return;
+
+ if (!ss->popupWindow && showPopup)
+ {
+ Display *dpy = s->display->display;
+ XSizeHints xsh;
+ XWMHints xwmh;
+ XClassHint xch;
+ Atom state[4];
+ int nState = 0;
+ XSetWindowAttributes attr;
+ Visual *visual;
+
+ visual = findArgbVisual (dpy, s->screenNum);
+ if (!visual)
+ return;
+
+ if (count > 1)
+ {
+ count -= (count + 1) & 1;
+ if (count < 3)
+ count = 3;
+ }
+
+ xsh.flags = PSize | PWinGravity;
+ xsh.width = WINDOW_WIDTH (count);
+ xsh.height = WINDOW_HEIGHT;
+ xsh.win_gravity = StaticGravity;
+
+ xwmh.flags = InputHint;
+ xwmh.input = 0;
+
+ xch.res_name = "compiz";
+ xch.res_class = "switcher-window";
+
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap (dpy, s->root, visual,
+ AllocNone);
+
+ ss->popupWindow =
+ XCreateWindow (dpy, s->root,
+ s->width / 2 - xsh.width / 2,
+ s->height / 2 - xsh.height / 2,
+ xsh.width, xsh.height, 0,
+ 32, InputOutput, visual,
+ CWBackPixel | CWBorderPixel | CWColormap, &attr);
+
+ XSetWMProperties (dpy, ss->popupWindow, NULL, NULL,
+ programArgv, programArgc,
+ &xsh, &xwmh, &xch);
+
+ state[nState++] = s->display->winStateAboveAtom;
+ state[nState++] = s->display->winStateStickyAtom;
+ state[nState++] = s->display->winStateSkipTaskbarAtom;
+ state[nState++] = s->display->winStateSkipPagerAtom;
+
+ XChangeProperty (dpy, ss->popupWindow,
+ s->display->winStateAtom,
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *) state, nState);
+
+ XChangeProperty (dpy, ss->popupWindow,
+ s->display->winTypeAtom,
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *) &s->display->winTypeUtilAtom, 1);
+
+ setWindowProp (s->display, ss->popupWindow,
+ s->display->winDesktopAtom,
+ 0xffffffff);
+
+ setSelectedWindowHint (s);
+ }
+
+ 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->popupWindow && showPopup)
+ {
+ CompWindow *w;
+
+ w = findWindowAtScreen (s, ss->popupWindow);
+ if (w && (w->state & CompWindowStateHiddenMask))
+ {
+ w->hidden = FALSE;
+ showWindow (w);
+ }
+ else
+ {
+ XMapWindow (s->display->display, ss->popupWindow);
+ }
+ }
+
+ switchActivateEvent (s, TRUE);
+ }
+
+ 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->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 (state & CompActionStateCancel)
+ {
+ ss->selectedWindow = None;
+ ss->zoomedWindow = None;
+ }
+
+ 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;
+
+ switchActivateEvent (s, FALSE);
+ }
+ else
+ {
+ ss->moreAdjust = 1;
+ }
+
+ ss->selectedWindow = None;
+ setSelectedWindowHint (s);
+
+ ss->lastActiveNum = 0;
+
+ damageScreen (s);
+ }
+ }
+
+ if (action)
+ action->state &= ~(CompActionStateTermKey | CompActionStateTermButton);
+
+ return FALSE;
+}
+
+static Bool
+switchInitiateCommon (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption,
+ SwitchWindowSelection selection,
+ Bool showPopup,
+ Bool nextWindow)
+{
+ CompScreen *s;
+ Window xid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+
+ s = findScreenAtDisplay (d, xid);
+ if (s)
+ {
+ SWITCH_SCREEN (s);
+
+ if (!ss->switching)
+ {
+ switchInitiate (s, selection, showPopup);
+
+ if (state & CompActionStateInitKey)
+ action->state |= CompActionStateTermKey;
+
+ if (state & CompActionStateInitEdge)
+ action->state |= CompActionStateTermEdge;
+ else if (state & CompActionStateInitButton)
+ action->state |= CompActionStateTermButton;
+ }
+
+ switchToWindow (s, nextWindow);
+ }
+
+ return FALSE;
+}
+
+static Bool
+switchNext (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return switchInitiateCommon (d, action, state, option, nOption,
+ CurrentViewport, TRUE, TRUE);
+}
+
+static Bool
+switchPrev (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return switchInitiateCommon (d, action, state, option, nOption,
+ CurrentViewport, TRUE, FALSE);
+}
+
+static Bool
+switchNextAll (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return switchInitiateCommon (d, action, state, option, nOption,
+ AllViewports, TRUE, TRUE);
+}
+
+static Bool
+switchPrevAll (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return switchInitiateCommon (d, action, state, option, nOption,
+ AllViewports, TRUE, FALSE);
+}
+
+static Bool
+switchNextNoPopup (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return switchInitiateCommon (d, action, state, option, nOption,
+ CurrentViewport, FALSE, TRUE);
+}
+
+static Bool
+switchPrevNoPopup (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return switchInitiateCommon (d, action, state, option, nOption,
+ CurrentViewport, FALSE, FALSE);
+}
+
+static Bool
+switchNextPanel (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return switchInitiateCommon (d, action, state, option, nOption,
+ Panels, FALSE, TRUE);
+}
+
+static Bool
+switchPrevPanel (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return switchInitiateCommon (d, action, state, option, nOption,
+ Panels, FALSE, FALSE);
+}
+
+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
+updateForegroundColor (CompScreen *s)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *propData;
+
+ SWITCH_SCREEN (s);
+ SWITCH_DISPLAY (s->display);
+
+ if (!ss->popupWindow)
+ return;
+
+
+ result = XGetWindowProperty (s->display->display, ss->popupWindow,
+ sd->selectFgColorAtom, 0L, 4L, FALSE,
+ XA_INTEGER, &actual, &format,
+ &n, &left, &propData);
+
+ if (result == Success && propData)
+ {
+ if (n == 3 || n == 4)
+ {
+ long *data = (long *) propData;
+
+ ss->fgColor[0] = MIN (0xffff, data[0]);
+ ss->fgColor[1] = MIN (0xffff, data[1]);
+ ss->fgColor[2] = MIN (0xffff, data[2]);
+
+ if (n == 4)
+ ss->fgColor[3] = MIN (0xffff, data[3]);
+ }
+
+ XFree (propData);
+ }
+ else
+ {
+ ss->fgColor[0] = 0;
+ ss->fgColor[1] = 0;
+ ss->fgColor[2] = 0;
+ ss->fgColor[3] = 0xffff;
+ }
+}
+
+static void
+switchHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ CompWindow *w;
+ SWITCH_DISPLAY (d);
+
+ switch (event->type) {
+ w = findWindowAtDisplay (d, event->xmap.window);
+ if (w)
+ {
+ SWITCH_SCREEN (w->screen);
+
+ if (w->id == ss->popupWindow)
+ {
+ w->wmType = getWindowType (d, w->id);
+ recalcWindowType (w);
+ recalcWindowActions (w);
+ updateWindowClassHints (w);
+ }
+ }
+ break;
+ }
+
+ 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);
+ break;
+ case PropertyNotify:
+ if (event->xproperty.atom == sd->selectFgColorAtom)
+ {
+ w = findWindowAtDisplay (d, event->xproperty.window);
+ if (w)
+ {
+ SWITCH_SCREEN (w->screen);
+
+ if (event->xproperty.window == ss->popupWindow)
+ updateForegroundColor (w->screen);
+ }
+ }
+
+ 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.001f && fabs (ss->tVelocity) < 0.001f &&
+ fabs (ds) < 0.001f && fabs (ss->sVelocity) < 0.001f)
+ {
+ 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->opt[SWITCH_SCREEN_OPTION_SPEED].value.f;
+ steps = amount /
+ (0.5f * ss->opt[SWITCH_SCREEN_OPTION_TIMESTEP].value.f);
+ 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;
+ }
+
+ switchActivateEvent (s, FALSE);
+ }
+ }
+ break;
+ }
+
+ m = ss->mVelocity * chunk;
+ if (!m)
+ {
+ if (ss->mVelocity)
+ m = (ss->move > 0) ? 1 : -1;
+ }
+
+ ss->move -= m;
+ ss->pos += m;
+ 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
+switchPaintOutput (CompScreen *s,
+ const ScreenPaintAttrib *sAttrib,
+ const CompTransform *transform,
+ Region region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ Bool status;
+
+ SWITCH_SCREEN (s);
+
+ ss->zoomMask = ZOOMED_WINDOW_MASK | NORMAL_WINDOW_MASK;
+
+ if (ss->grabIndex || (ss->zooming && ss->translate > 0.001f))
+ {
+ CompTransform sTransform = *transform;
+ CompWindow *zoomed;
+ CompWindow *switcher;
+ Window zoomedAbove = None;
+ Bool saveDestroyed = FALSE;
+
+ if (ss->zooming)
+ {
+ mask &= ~PAINT_SCREEN_REGION_MASK;
+ mask |= PAINT_SCREEN_TRANSFORMED_MASK | PAINT_SCREEN_CLEAR_MASK;
+
+ matrixTranslate (&sTransform, 0.0f, 0.0f, -ss->translate);
+
+ ss->zoomMask = NORMAL_WINDOW_MASK;
+ }
+
+ switcher = findWindowAtScreen (s, ss->popupWindow);
+ if (switcher)
+ {
+ saveDestroyed = switcher->destroyed;
+ switcher->destroyed = TRUE;
+ }
+
+ if (ss->opt[SWITCH_SCREEN_OPTION_BRINGTOFRONT].value.b)
+ {
+ 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, paintOutput);
+ status = (*s->paintOutput) (s, sAttrib, &sTransform,
+ region, output, mask);
+ WRAP (ss, s, paintOutput, switchPaintOutput);
+
+ if (ss->zooming)
+ {
+ float zTranslate;
+
+ mask &= ~PAINT_SCREEN_CLEAR_MASK;
+ mask |= PAINT_SCREEN_NO_BACKGROUND_MASK;
+
+ ss->zoomMask = ZOOMED_WINDOW_MASK;
+
+ zTranslate = MIN (ss->sTranslate, ss->translate);
+ matrixTranslate (&sTransform, 0.0f, 0.0f, zTranslate);
+
+ UNWRAP (ss, s, paintOutput);
+ status = (*s->paintOutput) (s, sAttrib, &sTransform, region,
+ output, mask);
+ WRAP (ss, s, paintOutput, switchPaintOutput);
+ }
+
+ if (zoomed)
+ {
+ unhookWindowFromScreen (s, zoomed);
+ insertWindowIntoScreen (s, zoomed, zoomedAbove);
+ }
+
+ if (switcher)
+ {
+ sTransform = *transform;
+
+ switcher->destroyed = saveDestroyed;
+
+ transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
+
+ glPushMatrix ();
+ glLoadMatrixf (sTransform.m);
+
+ if (!switcher->destroyed &&
+ switcher->attrib.map_state == IsViewable &&
+ switcher->damaged)
+ {
+ (*s->paintWindow) (switcher, &switcher->paint, &sTransform,
+ &infiniteRegion, 0);
+ }
+
+ glPopMatrix ();
+ }
+ }
+ else
+ {
+ UNWRAP (ss, s, paintOutput);
+ status = (*s->paintOutput) (s, sAttrib, transform, region, output,
+ mask);
+ WRAP (ss, s, paintOutput, switchPaintOutput);
+ }
+
+ return status;
+}
+
+static void
+switchDonePaintScreen (CompScreen *s)
+{
+ SWITCH_SCREEN (s);
+
+ if ((ss->grabIndex || ss->zooming) && ss->moreAdjust)
+ {
+ if (ss->zooming)
+ {
+ 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,
+ const CompTransform *transform,
+ unsigned int mask,
+ int x,
+ int y,
+ int x1,
+ int x2)
+{
+ WindowPaintAttrib sAttrib = *attrib;
+ int wx, wy;
+ float width, height;
+ CompIcon *icon = NULL;
+
+ mask |= PAINT_WINDOW_TRANSFORMED_MASK;
+
+ if (w->mapNum)
+ {
+ if (!w->texture->pixmap && !w->bindFailed)
+ bindWindow (w);
+ }
+
+ if (w->texture->pixmap)
+ {
+ AddWindowGeometryProc oldAddWindowGeometry;
+ FragmentAttrib fragment;
+ CompTransform wTransform = *transform;
+ int ww, wh;
+
+ SWITCH_SCREEN (w->screen);
+
+ 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;
+
+ 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;
+
+ initFragmentAttrib (&fragment, &sAttrib);
+
+ if (w->alpha || fragment.opacity != OPAQUE)
+ mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+
+ matrixTranslate (&wTransform, w->attrib.x, w->attrib.y, 0.0f);
+ matrixScale (&wTransform, sAttrib.xScale, sAttrib.yScale, 1.0f);
+ matrixTranslate (&wTransform,
+ sAttrib.xTranslate / sAttrib.xScale - w->attrib.x,
+ sAttrib.yTranslate / sAttrib.yScale - w->attrib.y,
+ 0.0f);
+
+ glPushMatrix ();
+ glLoadMatrixf (wTransform.m);
+
+ /* XXX: replacing the addWindowGeometry function like this is
+ very ugly but necessary until the vertex stage has been made
+ fully pluggable. */
+ oldAddWindowGeometry = w->screen->addWindowGeometry;
+ w->screen->addWindowGeometry = addWindowGeometry;
+ (w->screen->drawWindow) (w, &wTransform, &fragment, &infiniteRegion,
+ mask);
+ w->screen->addWindowGeometry = oldAddWindowGeometry;
+
+ glPopMatrix ();
+
+ if (ss->opt[SWITCH_SCREEN_OPTION_ICON].value.b)
+ {
+ icon = getWindowIcon (w, ICON_SIZE, ICON_SIZE);
+ if (icon)
+ {
+ sAttrib.xScale = sAttrib.yScale = 1.0f;
+
+ wx = x + WIDTH - icon->width - SPACE;
+ wy = y + HEIGHT - icon->height - SPACE;
+ }
+ }
+ }
+ else
+ {
+ width = WIDTH - (WIDTH >> 2);
+ height = HEIGHT - (HEIGHT >> 2);
+
+ 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;
+
+ 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_BLEND_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 = w->indexCount = 0;
+ addWindowGeometry (w, &matrix, 1, &iconReg, &infiniteRegion);
+ if (w->vCount)
+ {
+ FragmentAttrib fragment;
+ CompTransform wTransform = *transform;
+
+ initFragmentAttrib (&fragment, &sAttrib);
+
+ matrixTranslate (&wTransform, w->attrib.x, w->attrib.y, 0.0f);
+ matrixScale (&wTransform, sAttrib.xScale, sAttrib.yScale, 1.0f);
+ matrixTranslate (&wTransform,
+ sAttrib.xTranslate / sAttrib.xScale - w->attrib.x,
+ sAttrib.yTranslate / sAttrib.yScale - w->attrib.y,
+ 0.0f);
+
+ glPushMatrix ();
+ glLoadMatrixf (wTransform.m);
+
+ (*w->screen->drawWindowTexture) (w,
+ &icon->texture, &fragment,
+ mask);
+
+ glPopMatrix ();
+ }
+ }
+}
+
+static Bool
+switchPaintWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib,
+ const CompTransform *transform,
+ Region region,
+ unsigned int mask)
+{
+ CompScreen *s = w->screen;
+ int zoomType = NORMAL_WINDOW_MASK;
+ Bool status;
+
+ SWITCH_SCREEN (s);
+
+ if (w->id == ss->popupWindow)
+ {
+ GLenum filter;
+ int x, y, x1, x2, cx, i;
+ unsigned short color[4];
+
+ if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
+ return FALSE;
+
+ UNWRAP (ss, s, paintWindow);
+ status = (*s->paintWindow) (w, attrib, transform, 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);
+
+ for (i = 0; i < ss->nWindows; i++)
+ {
+ if (x + WIDTH > x1)
+ switchPaintThumb (ss->windows[i], &w->lastPaint, transform,
+ mask, x, y, x1, x2);
+
+ x += WIDTH;
+ }
+
+ for (i = 0; i < ss->nWindows; i++)
+ {
+ if (x > x2)
+ break;
+
+ switchPaintThumb (ss->windows[i], &w->lastPaint, transform, mask,
+ x, y, x1, x2);
+
+ x += WIDTH;
+ }
+
+ glPopAttrib ();
+
+ s->display->textureFilter = filter;
+
+ cx = w->attrib.x + (w->width >> 1);
+
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+ glEnable (GL_BLEND);
+ for (i = 0; i < 4; i++)
+ color[i] = (unsigned int)ss->fgColor[i] * w->lastPaint.opacity /
+ 0xffff;
+ glColor4usv (color);
+ 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)
+ {
+ if (ss->opt[SWITCH_SCREEN_OPTION_BRINGTOFRONT].value.b &&
+ ss->selectedWindow == ss->zoomedWindow)
+ zoomType = ZOOMED_WINDOW_MASK;
+
+ if (!(ss->zoomMask & zoomType))
+ return (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) ?
+ FALSE : TRUE;
+
+ UNWRAP (ss, s, paintWindow);
+ status = (*s->paintWindow) (w, attrib, transform, region, mask);
+ WRAP (ss, s, paintWindow, switchPaintWindow);
+ }
+ else if (ss->switching)
+ {
+ WindowPaintAttrib sAttrib = *attrib;
+ GLuint value;
+
+ value = ss->opt[SWITCH_SCREEN_OPTION_SATURATION].value.i;
+ if (value != 100)
+ sAttrib.saturation = sAttrib.saturation * value / 100;
+
+ value = ss->opt[SWITCH_SCREEN_OPTION_BRIGHTNESS].value.i;
+ if (value != 100)
+ sAttrib.brightness = sAttrib.brightness * value / 100;
+
+ if (w->wmType & ~(CompWindowTypeDockMask | CompWindowTypeDesktopMask))
+ {
+ value = ss->opt[SWITCH_SCREEN_OPTION_OPACITY].value.i;
+ if (value != 100)
+ sAttrib.opacity = sAttrib.opacity * value / 100;
+ }
+
+ if (ss->opt[SWITCH_SCREEN_OPTION_BRINGTOFRONT].value.b &&
+ w->id == ss->zoomedWindow)
+ zoomType = ZOOMED_WINDOW_MASK;
+
+ if (!(ss->zoomMask & zoomType))
+ return (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) ?
+ FALSE : TRUE;
+
+ UNWRAP (ss, s, paintWindow);
+ status = (*s->paintWindow) (w, &sAttrib, transform, region, mask);
+ WRAP (ss, s, paintWindow, switchPaintWindow);
+ }
+ else
+ {
+ if (!(ss->zoomMask & zoomType))
+ return (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) ?
+ FALSE : TRUE;
+
+ UNWRAP (ss, s, paintWindow);
+ status = (*s->paintWindow) (w, attrib, transform, region, mask);
+ WRAP (ss, s, paintWindow, switchPaintWindow);
+ }
+
+ 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 CompOption *
+switchGetDisplayOptions (CompPlugin *plugin,
+ CompDisplay *display,
+ int *count)
+{
+ SWITCH_DISPLAY (display);
+
+ *count = NUM_OPTIONS (sd);
+ return sd->opt;
+}
+
+static Bool
+switchSetDisplayOption (CompPlugin *plugin,
+ CompDisplay *display,
+ const char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+
+ SWITCH_DISPLAY (display);
+
+ o = compFindOption (sd->opt, NUM_OPTIONS (sd), name, NULL);
+ if (!o)
+ return FALSE;
+
+ return compSetDisplayOption (display, o, value);
+}
+
+static const CompMetadataOptionInfo switchDisplayOptionInfo[] = {
+ { "next_button", "button", 0, switchNext, switchTerminate },
+ { "next_key", "key", 0, switchNext, switchTerminate },
+ { "prev_button", "button", 0, switchPrev, switchTerminate },
+ { "prev_key", "key", 0, switchPrev, switchTerminate },
+ { "next_all_button", "button", 0, switchNextAll, switchTerminate },
+ { "next_all_key", "key", 0, switchNextAll, switchTerminate },
+ { "prev_all_button", "button", 0, switchPrevAll, switchTerminate },
+ { "prev_all_key", "key", 0, switchPrevAll, switchTerminate },
+ { "next_no_popup_button", "button", 0, switchNextNoPopup,
+ switchTerminate },
+ { "next_no_popup_key", "key", 0, switchNextNoPopup, switchTerminate },
+ { "prev_no_popup_button", "button", 0, switchPrevNoPopup,
+ switchTerminate },
+ { "prev_no_popup_key", "key", 0, switchPrevNoPopup, switchTerminate },
+ { "next_panel_button", "button", 0, switchNextPanel, switchTerminate },
+ { "next_panel_key", "key", 0, switchNextPanel, switchTerminate },
+ { "prev_panel_button", "button", 0, switchPrevPanel, switchTerminate },
+ { "prev_panel_key", "key", 0, switchPrevPanel, switchTerminate }
+};
+
+static Bool
+switchInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ SwitchDisplay *sd;
+
+ if (!checkPluginABI ("core", CORE_ABIVERSION))
+ return FALSE;
+
+ sd = malloc (sizeof (SwitchDisplay));
+ if (!sd)
+ return FALSE;
+
+ if (!compInitDisplayOptionsFromMetadata (d,
+ &switchMetadata,
+ switchDisplayOptionInfo,
+ sd->opt,
+ SWITCH_DISPLAY_OPTION_NUM))
+ {
+ free (sd);
+ return FALSE;
+ }
+
+ sd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (sd->screenPrivateIndex < 0)
+ {
+ compFiniDisplayOptions (d, sd->opt, SWITCH_DISPLAY_OPTION_NUM);
+ free (sd);
+ return FALSE;
+ }
+
+ sd->selectWinAtom = XInternAtom (d->display,
+ DECOR_SWITCH_WINDOW_ATOM_NAME, 0);
+ sd->selectFgColorAtom =
+ XInternAtom (d->display, DECOR_SWITCH_FOREGROUND_COLOR_ATOM_NAME, 0);
+
+ WRAP (sd, d, handleEvent, switchHandleEvent);
+
+ d->base.privates[displayPrivateIndex].ptr = sd;
+
+ return TRUE;
+}
+
+static void
+switchFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ SWITCH_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, sd->screenPrivateIndex);
+
+ UNWRAP (sd, d, handleEvent);
+
+ compFiniDisplayOptions (d, sd->opt, SWITCH_DISPLAY_OPTION_NUM);
+
+ free (sd);
+}
+
+static const CompMetadataOptionInfo switchScreenOptionInfo[] = {
+ { "speed", "float", "<min>0.1</min>", 0, 0 },
+ { "timestep", "float", "<min>0.1</min>", 0, 0 },
+ { "window_match", "match", 0, 0, 0 },
+ { "mipmap", "bool", 0, 0, 0 },
+ { "saturation", "int", "<min>0</min><max>100</max>", 0, 0 },
+ { "brightness", "int", "<min>0</min><max>100</max>", 0, 0 },
+ { "opacity", "int", "<min>0</min><max>100</max>", 0, 0 },
+ { "bring_to_front", "bool", 0, 0, 0 },
+ { "zoom", "float", "<min>0</min>", 0, 0 },
+ { "icon", "bool", 0, 0, 0 },
+ { "minimized", "bool", 0, 0, 0 },
+ { "auto_rotate", "bool", 0, 0, 0 }
+};
+
+static Bool
+switchInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ SwitchScreen *ss;
+
+ SWITCH_DISPLAY (s->display);
+
+ ss = malloc (sizeof (SwitchScreen));
+ if (!ss)
+ return FALSE;
+
+ if (!compInitScreenOptionsFromMetadata (s,
+ &switchMetadata,
+ switchScreenOptionInfo,
+ ss->opt,
+ SWITCH_SCREEN_OPTION_NUM))
+ {
+ free (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->grabIndex = 0;
+
+ ss->zoom = ss->opt[SWITCH_SCREEN_OPTION_ZOOM].value.f / 30.0f;
+
+ ss->zooming = (ss->opt[SWITCH_SCREEN_OPTION_ZOOM].value.f > 0.05f);
+
+ ss->zoomMask = ~0;
+
+ ss->moreAdjust = 0;
+
+ ss->mVelocity = 0.0f;
+ ss->tVelocity = 0.0f;
+ ss->sVelocity = 0.0f;
+
+ ss->translate = 0.0f;
+ ss->sTranslate = 0.0f;
+
+ ss->selection = CurrentViewport;
+
+ ss->fgColor[0] = 0;
+ ss->fgColor[1] = 0;
+ ss->fgColor[2] = 0;
+ ss->fgColor[3] = 0xffff;
+
+ WRAP (ss, s, preparePaintScreen, switchPreparePaintScreen);
+ WRAP (ss, s, donePaintScreen, switchDonePaintScreen);
+ WRAP (ss, s, paintOutput, switchPaintOutput);
+ WRAP (ss, s, paintWindow, switchPaintWindow);
+ WRAP (ss, s, damageWindowRect, switchDamageWindowRect);
+
+ s->base.privates[sd->screenPrivateIndex].ptr = ss;
+
+ return TRUE;
+}
+
+static void
+switchFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ SWITCH_SCREEN (s);
+
+ UNWRAP (ss, s, preparePaintScreen);
+ UNWRAP (ss, s, donePaintScreen);
+ UNWRAP (ss, s, paintOutput);
+ UNWRAP (ss, s, paintWindow);
+ UNWRAP (ss, s, damageWindowRect);
+
+ if (ss->popupWindow)
+ XDestroyWindow (s->display->display, ss->popupWindow);
+
+ if (ss->windows)
+ free (ss->windows);
+
+ compFiniScreenOptions (s, ss->opt, SWITCH_SCREEN_OPTION_NUM);
+
+ free (ss);
+}
+
+static CompBool
+switchInitObject (CompPlugin *p,
+ CompObject *o)
+{
+ static InitPluginObjectProc dispTab[] = {
+ (InitPluginObjectProc) 0, /* InitCore */
+ (InitPluginObjectProc) switchInitDisplay,
+ (InitPluginObjectProc) switchInitScreen
+ };
+
+ RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
+}
+
+static void
+switchFiniObject (CompPlugin *p,
+ CompObject *o)
+{
+ static FiniPluginObjectProc dispTab[] = {
+ (FiniPluginObjectProc) 0, /* FiniCore */
+ (FiniPluginObjectProc) switchFiniDisplay,
+ (FiniPluginObjectProc) switchFiniScreen
+ };
+
+ DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
+}
+
+static CompOption *
+switchGetObjectOptions (CompPlugin *plugin,
+ CompObject *object,
+ int *count)
+{
+ static GetPluginObjectOptionsProc dispTab[] = {
+ (GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
+ (GetPluginObjectOptionsProc) switchGetDisplayOptions,
+ (GetPluginObjectOptionsProc) switchGetScreenOptions
+ };
+
+ *count = 0;
+ RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
+ (void *) count, (plugin, object, count));
+}
+
+static CompBool
+switchSetObjectOption (CompPlugin *plugin,
+ CompObject *object,
+ const char *name,
+ CompOptionValue *value)
+{
+ static SetPluginObjectOptionProc dispTab[] = {
+ (SetPluginObjectOptionProc) 0, /* SetCoreOption */
+ (SetPluginObjectOptionProc) switchSetDisplayOption,
+ (SetPluginObjectOptionProc) switchSetScreenOption
+ };
+
+ RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
+ (plugin, object, name, value));
+}
+
+static Bool
+switchInit (CompPlugin *p)
+{
+ if (!compInitPluginMetadataFromInfo (&switchMetadata,
+ p->vTable->name,
+ switchDisplayOptionInfo,
+ SWITCH_DISPLAY_OPTION_NUM,
+ switchScreenOptionInfo,
+ SWITCH_SCREEN_OPTION_NUM))
+ return FALSE;
+
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ {
+ compFiniMetadata (&switchMetadata);
+ return FALSE;
+ }
+
+ compAddMetadataFromFile (&switchMetadata, p->vTable->name);
+
+ return TRUE;
+}
+
+static void
+switchFini (CompPlugin *p)
+{
+ freeDisplayPrivateIndex (displayPrivateIndex);
+ compFiniMetadata (&switchMetadata);
+}
+
+static CompMetadata *
+switchGetMetadata (CompPlugin *plugin)
+{
+ return &switchMetadata;
+}
+
+CompPluginVTable switchVTable = {
+ "switcher",
+ switchGetMetadata,
+ switchInit,
+ switchFini,
+ switchInitObject,
+ switchFiniObject,
+ switchGetObjectOptions,
+ switchSetObjectOption
+};
+
+CompPluginVTable *
+getCompPluginInfo20070830 (void)
+{
+ return &switchVTable;
+}