You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2148 lines
48 KiB

/*
* 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;
CompWindow *selectedWindow;
CompWindow *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 48
#define MAX_ICON_SIZE 256
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)
{
Window selectedWindowId = None;
SWITCH_DISPLAY (s->display);
SWITCH_SCREEN (s);
if (ss->selectedWindow && !ss->selectedWindow->destroyed)
selectedWindowId = ss->selectedWindow->id;
XChangeProperty (s->display->display, ss->popupWindow, sd->selectWinAtom,
XA_WINDOW, 32, PropModeReplace,
(unsigned char *) &selectedWindowId, 1);
}
static Bool
isSwitchWin (CompWindow *w)
{
SWITCH_SCREEN (w->screen);
if (w->destroyed)
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->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];
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] == 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)
{
CompWindow *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;
if (!ss->zoomedWindow)
ss->zoomedWindow = ss->selectedWindow;
if (old != w)
{
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 && !old->destroyed)
addWindowDamage (old);
}
}
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, "cube", NULL))
return;
ss->selection = selection;
ss->selectedWindow = NULL;
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 = NULL;
ss->zoomedWindow = NULL;
}
if (state && ss->selectedWindow && !ss->selectedWindow->destroyed)
sendWindowActivationRequest (s, ss->selectedWindow->id);
removeScreenGrab (s, ss->grabIndex, 0);
ss->grabIndex = 0;
if (!ss->zooming)
{
ss->selectedWindow = NULL;
ss->zoomedWindow = NULL;
switchActivateEvent (s, FALSE);
}
else
{
ss->moreAdjust = 1;
}
ss->selectedWindow = NULL;
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,
CompWindow *w)
{
if (w)
{
Bool inList = FALSE;
int count, j, i = 0;
CompWindow *selected;
CompWindow *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 == selected)
{
if (i + 1 < ss->nWindows)
selected = ss->windows[i + 1];
else
selected = ss->windows[0];
}
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];
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)
{
ss->zoomedWindow = ss->selectedWindow;
addWindowDamage (ss->selectedWindow);
addWindowDamage (w);
if (old && !old->destroyed)
addWindowDamage (old);
}
}
}
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 = NULL;
SWITCH_DISPLAY (d);
switch (event->type) {
case MapNotify:
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;
case DestroyNotify:
/* We need to get the CompWindow * for event->xdestroywindow.window
here because in the (*d->handleEvent) call below, that CompWindow's
id will become 1, so findWindowAtDisplay won't be able to find the
CompWindow after that. */
w = findWindowAtDisplay (d, event->xdestroywindow.window);
break;
}
UNWRAP (sd, d, handleEvent);
(*d->handleEvent) (d, event);
WRAP (sd, d, handleEvent, switchHandleEvent);
switch (event->type) {
case UnmapNotify:
w = findWindowAtDisplay (d, event->xunmap.window);
switchWindowRemove (d, w);
break;
case DestroyNotify:
switchWindowRemove (d, w);
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 = NULL;
ss->zoomedWindow = NULL;
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 = ss->zoomedWindow;
if (zoomed && !zoomed->destroyed)
{
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;
GLenum filter;
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);
filter = w->screen->display->textureFilter;
if (ss->opt[SWITCH_SCREEN_OPTION_MIPMAP].value.b)
w->screen->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
/* 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;
w->screen->display->textureFilter = filter;
glPopMatrix ();
if (ss->opt[SWITCH_SCREEN_OPTION_ICON].value.b)
{
icon = getWindowIcon (w, MAX_ICON_SIZE, MAX_ICON_SIZE);
if (icon)
{
sAttrib.xScale = (float) ICON_SIZE / icon->width;
sAttrib.yScale = (float) ICON_SIZE / icon->height;
/*
sAttrib.xScale =
((WIDTH - (SPACE << 1)) / 2.5f) / icon->width;
sAttrib.yScale =
((HEIGHT - (SPACE << 1)) / 2.5f) / icon->height;
*/
if (sAttrib.xScale < sAttrib.yScale)
sAttrib.yScale = sAttrib.xScale;
else
sAttrib.xScale = sAttrib.yScale;
wx = x + WIDTH - icon->width * sAttrib.xScale - SPACE;
wy = y + HEIGHT - icon->height * sAttrib.yScale - SPACE;
}
}
}
else
{
width = WIDTH - (WIDTH >> 2);
height = HEIGHT - (HEIGHT >> 2);
icon = getWindowIcon (w, MAX_ICON_SIZE, MAX_ICON_SIZE);
if (!icon)
icon = w->screen->defaultIcon;
if (icon)
{
float iw, ih;
iw = width - SPACE;
ih = height - SPACE;
sAttrib.xScale = (iw / icon->width);
sAttrib.yScale = (ih / icon->height);
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)
{
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;
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 ();
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 == 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 == 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 = NULL;
ss->zoomedWindow = NULL;
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;
}