/* * 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 */ #include #include #include #include #include #include #include #include #include #include #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", "0.1", 0, 0 }, { "timestep", "float", "0.1", 0, 0 }, { "window_match", "match", 0, 0, 0 }, { "mipmap", "bool", 0, 0, 0 }, { "saturation", "int", "0100", 0, 0 }, { "brightness", "int", "0100", 0, 0 }, { "opacity", "int", "0100", 0, 0 }, { "bring_to_front", "bool", 0, 0, 0 }, { "zoom", "float", "0", 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; }