/* * * Compiz shift switcher plugin * * shift.cpp * * Copyright : (C) 2007 by Dennis Kasprzyk * E-mail : onestone@opencompositing.org * * * Based on ring.c: * Copyright : (C) 2007 by Danny Baumann * E-mail : maniac@opencompositing.org * * Based on scale.c and switcher.c: * Copyright : (C) 2007 David Reveman * E-mail : davidr@novell.com * * Rounded corner drawing taken from wall.c: * Copyright : (C) 2007 Robert Carr * E-mail : racarr@beryl-project.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include "shift.h" COMPIZ_PLUGIN_20090315 (shift, ShiftPluginVTable); bool textAvailable = false; void setFunctions (bool enabled) { SHIFT_SCREEN (screen); screen->handleEventSetEnabled (ss, enabled); ss->cScreen->preparePaintSetEnabled (ss, enabled); ss->cScreen->paintSetEnabled (ss, enabled); ss->gScreen->glPaintOutputSetEnabled (ss, enabled); ss->cScreen->donePaintSetEnabled (ss, enabled); foreach (CompWindow *w, screen->windows ()) { SHIFT_WINDOW (w); sw->gWindow->glPaintSetEnabled (sw, enabled); sw->cWindow->damageRectSetEnabled (sw, enabled); } } void ShiftScreen::activateEvent (bool activating) { CompOption::Vector o; o.resize (2); o[0] = CompOption ("root", CompOption::TypeInt); o[0].value ().set ((int) screen->root ()); o[1] = CompOption ("active", CompOption::TypeBool); o[1].value ().set (activating); screen->handleCompizEvent ("shift", "activate", o); } bool ShiftWindow::isShiftable () { SHIFT_SCREEN (screen); if (window->overrideRedirect ()) return false; if (window->wmType () & (CompWindowTypeDockMask | CompWindowTypeDesktopMask)) return false; if (!window->mapNum () || !window->isViewable ()) { if (ss->optionGetMinimized ()) { if (!window->minimized () && !window->inShowDesktopMode () && !window->shaded ()) return false; } else return false; } if (ss->mType == ShiftTypeNormal) { if (!window->mapNum () || !window->isViewable ()) { if (window->serverGeometry ().x () + window->serverGeometry ().width () <= 0 || window->serverGeometry ().y () + window->serverGeometry ().height () <= 0 || window->serverGeometry ().x () >= screen->width () || window->serverGeometry ().y () >= screen->height ()) return false; } else { if (!window->focus ()) return false; } } else if (ss->mType == ShiftTypeGroup && ss->mClientLeader != window->clientLeader () && ss->mClientLeader != window->id ()) { return false; } if (window->state () & CompWindowStateSkipTaskbarMask) return false; if (ss->mCurrentMatch && !ss->mCurrentMatch->evaluate (window)) return false; return true; } void ShiftScreen::freeWindowTitle () { } void ShiftScreen::renderWindowTitle () { CompText::Attrib tA; CompRect oe; freeWindowTitle (); if (!textAvailable) return; if (!optionGetWindowTitle ()) return; if (optionGetMultioutputMode () == ShiftOptions::MultioutputModeOneBigSwitcher) { oe.setGeometry (0, 0, screen->width (), screen->height ()); } else oe = screen->getCurrentOutputExtents (); /* 75% of the output device as maximum width */ tA.maxWidth = oe.width () * 3 / 4; tA.maxHeight = 100; tA.family = "Sans"; tA.size = optionGetTitleFontSize (); tA.color[0] = optionGetTitleFontColorRed (); tA.color[1] = optionGetTitleFontColorGreen (); tA.color[2] = optionGetTitleFontColorBlue (); tA.color[3] = optionGetTitleFontColorAlpha (); tA.flags = CompText::WithBackground | CompText::Ellipsized; if (optionGetTitleFontBold ()) tA.flags |= CompText::StyleBold; tA.bgHMargin = 15; tA.bgVMargin = 15; tA.bgColor[0] = optionGetTitleBackColorRed (); tA.bgColor[1] = optionGetTitleBackColorGreen (); tA.bgColor[2] = optionGetTitleBackColorBlue (); tA.bgColor[3] = optionGetTitleBackColorAlpha (); text.renderWindowTitle (mSelectedWindow ? mSelectedWindow : None, mType == ShiftTypeAll, tA); } void ShiftScreen::drawWindowTitle () { float width, height, border = 10.0f; CompRect oe; width = text.getWidth (); height = text.getHeight (); if (optionGetMultioutputMode () == MultioutputModeOneBigSwitcher) { oe.setGeometry (0, 0, screen->width (), screen->height ()); } else { oe = (CompRect) screen->outputDevs ()[mUsedOutput]; } float x = oe.centerX () - width / 2; float y; /* assign y (for the lower corner!) according to the setting */ switch (optionGetTitleTextPlacement ()) { case TitleTextPlacementCenteredOnScreen: y = oe.centerY () + height / 2; break; case TitleTextPlacementAbove: case TitleTextPlacementBelow: { CompRect workArea = screen->currentOutputDev ().workArea (); if (optionGetTitleTextPlacement () == TitleTextPlacementAbove) y = oe.y1 () + workArea.y1 () + 2 * border + height; else y = oe.y1 () + workArea.y2 () - 2 * border; } break; default: return; } text.draw (floor (x), floor (y), 1.0f); } bool ShiftWindow::glPaint (const GLWindowPaintAttrib &attrib, const GLMatrix &transform, const CompRegion ®ion, unsigned int mask) { bool status; SHIFT_SCREEN (screen); if (ss->mState != ShiftStateNone && !ss->mPaintingAbove && !(window->wmType () & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))) { GLWindowPaintAttrib sAttrib = attrib; bool scaled = false; if (window->mapNum ()) { if (gWindow->textures ().empty ()) gWindow->bind (); } if (mActive) scaled = (ss->mActiveSlot != NULL); if (mOpacity > 0.01 && (ss->mActiveSlot == NULL)) { sAttrib.brightness = sAttrib.brightness * mBrightness; sAttrib.opacity = sAttrib.opacity * mOpacity; } else mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK; if (mActive && ((unsigned int) ss->mOutput->id () == (unsigned int) ss->mUsedOutput || (unsigned int) ss->mOutput->id () == (unsigned int) ~0)) mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK; status = gWindow->glPaint (sAttrib, transform, region, mask); if (scaled && !gWindow->textures ().empty ()) { GLFragment::Attrib fragment (attrib); GLMatrix wTransform = transform; ShiftSlot *slot = ss->mActiveSlot->slot; float sx = ss->mAnim * slot->tx; float sy = ss->mAnim * slot->ty; float sz = ss->mAnim * slot->z; float srot = (ss->mAnim * slot->rotation); float anim = MIN (1.0, MAX (0.0, ss->mAnim)); float sscale; float sopacity; if (slot->primary) sscale = (ss->mAnim * slot->scale) + (1 - ss->mAnim); else sscale = ss->mAnim * slot->scale; if (slot->primary && !ss->mReflectActive) sopacity = (ss->mAnim * slot->opacity) + (1 - ss->mAnim); else sopacity = anim * anim * slot->opacity; if (sopacity <= 0.05) return status; /*if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) return false;*/ fragment.setOpacity ((float)fragment.getOpacity () * sopacity); fragment.setBrightness ((float)fragment.getBrightness () * ss->mReflectBrightness); if (window->alpha () || fragment.getOpacity () != OPAQUE) mask |= PAINT_WINDOW_TRANSLUCENT_MASK; wTransform.translate (sx, sy, sz); wTransform.translate (window->x () + (window->width () * sscale / 2), window->y () + (window->height () * sscale / 2.0), 0.0f); wTransform.scale (ss->mOutput->width (), -ss->mOutput->height (), 1.0f); wTransform.rotate (srot, 0.0, 1.0, 0.0); wTransform.scale (1.0f / ss->mOutput->width (), -1.0f / ss->mOutput->height (), 1.0f); wTransform.scale (sscale, sscale, 1.0f); wTransform.translate (-window->x () - (window->width () / 2), -window->y () - (window->height () / 2), 0.0f); glPushMatrix (); glLoadMatrixf (wTransform.getMatrix ()); gWindow->glDraw (wTransform, fragment, region, mask | PAINT_WINDOW_TRANSFORMED_MASK); glPopMatrix (); } if (scaled && ((ss->optionGetOverlayIcon () != ShiftOptions::OverlayIconNone) || gWindow->textures ().empty ())) { GLTexture *icon; icon = gWindow->getIcon (96, 96); if (!icon) icon = ss->gScreen->defaultIcon (); if (icon && (icon->name ())) { CompRegion iconReg; float scale; float x, y; int width, height; int scaledWinWidth, scaledWinHeight; int iconOverlay = ss->optionGetOverlayIcon (); ShiftSlot *slot = ss->mActiveSlot->slot; GLTexture::MatrixList matl; float sx = ss->mAnim * slot->tx; float sy = ss->mAnim * slot->ty; float sz = ss->mAnim * slot->z; float srot = (ss->mAnim * slot->rotation); float sopacity = ss->mAnim * slot->opacity; float sscale; if (slot->primary) sscale = (ss->mAnim * slot->scale) + (1 - ss->mAnim); else sscale = ss->mAnim * ss->mAnim * slot->scale; scaledWinWidth = window->width () * sscale; scaledWinHeight = window->height () * sscale; if (gWindow->textures ().empty ()) iconOverlay = ShiftOptions::OverlayIconBig; switch (iconOverlay) { case ShiftOptions::OverlayIconNone: case ShiftOptions::OverlayIconEmblem: scale = 1.0f; break; case ShiftOptions::OverlayIconBig: default: /* only change opacity if not painting an icon for a minimized window */ if (!gWindow->textures ().empty ()) sAttrib.opacity /= 3; scale = MIN (((float) scaledWinWidth / icon->width ()), ((float) scaledWinHeight / icon->height ())); break; } width = icon->width () * scale; height = icon->height () * scale; switch (iconOverlay) { case ShiftOptions::OverlayIconNone: case ShiftOptions::OverlayIconEmblem: x = scaledWinWidth - width; y = scaledWinHeight - height; break; case ShiftOptions::OverlayIconBig: default: x = scaledWinWidth / 2 - width / 2; y = scaledWinHeight / 2 - height / 2; break; } mask |= PAINT_WINDOW_BLEND_MASK; /* if we paint the icon for a minimized window, we need to force the usage of a good texture filter */ if (gWindow->textures ().empty ()) mask |= PAINT_WINDOW_TRANSFORMED_MASK; iconReg = CompRegion (0, 0, icon->width (), icon->height ()); gWindow->geometry ().reset (); matl.push_back (icon->matrix ()); gWindow->glAddGeometry (matl, iconReg, iconReg); if (gWindow->geometry ().vCount) { GLFragment::Attrib fragment (sAttrib); GLMatrix wTransform (transform); if (gWindow->textures ().empty ()) sAttrib.opacity = gWindow->paintAttrib ().opacity; fragment = GLFragment::Attrib (sAttrib); fragment.setOpacity ((float)fragment.getOpacity () * sopacity); fragment.setBrightness ((float)fragment.getBrightness () * ss->mReflectBrightness); wTransform.translate (sx, sy, sz); wTransform.translate (window->x () + (window->width () * sscale / 2), window->y () + (window->height () * sscale / 2.0), 0.0f); wTransform.scale (ss->mOutput->width (), -ss->mOutput->height (), 1.0f); wTransform.rotate (srot, 0.0, 1.0, 0.0); wTransform.scale (1.0f / ss->mOutput->width (), -1.0f / ss->mOutput->height (), 1.0f); wTransform.translate (x - (window->width () * sscale / 2), y - (window->height () * sscale / 2.0), 0.0f); wTransform.scale (scale, scale, 1.0f); glPushMatrix (); glLoadMatrixf (wTransform.getMatrix ()); gWindow->glDrawTexture (icon, fragment, mask); glPopMatrix (); } } } } else { GLWindowPaintAttrib sAttrib = attrib; if (ss->mPaintingAbove) { sAttrib.opacity = sAttrib.opacity * (1.0 - ss->mAnim); if (ss->mAnim > 0.99) mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK; } status = gWindow->glPaint (sAttrib, transform, region, mask); } return status; } static int compareWindows (const void *elem1, const void *elem2) { CompWindow *w1 = *((CompWindow **) elem1); CompWindow *w2 = *((CompWindow **) elem2); CompWindow *w = w1; if (w1 == w2) return 0; if (!w1->shaded () && !w1->isViewable () && (w2->shaded () || w2->isViewable ())) { return 1; } if (!w2->shaded () && !w2->isViewable () && (w1->shaded () || w1->isViewable ())) { return -1; } while (w) { if (w == w2) return 1; w = w->next; } return -1; } static int compareShiftWindowDistance (const void *elem1, const void *elem2) { float a1 = ((ShiftDrawSlot *) elem1)->distance; float a2 = ((ShiftDrawSlot *) elem2)->distance; float ab = fabs (a1 - a2); if (ab > 0.3 && a1 > a2) return -1; else if (ab > 0.3 && a1 < a2) return 1; else return compareWindows (&((ShiftDrawSlot *) elem2)->w, &((ShiftDrawSlot *) elem1)->w); } bool ShiftScreen::layoutThumbsCover () { CompWindow *w; int index; int ww, wh; float xScale, yScale; float distance; int i; CompRect oe; if (optionGetMultioutputMode () == ShiftScreen::MultioutputModeOneBigSwitcher) { oe.setGeometry (0, 0, screen->width (), screen->height ()); } else { oe = screen->outputDevs ()[mUsedOutput]; } /* the center of the ellipse is in the middle of the used output device */ int centerX = oe.centerX (); int centerY = oe.centerY (); int maxThumbWidth = oe.width () * optionGetSize () / 100; int maxThumbHeight = oe.height () * optionGetSize () / 100; for (index = 0; index < mNWindows; index++) { w = mWindows[index]; SHIFT_WINDOW (w); ww = w->width () + w->input ().left + w->input ().right; wh = w->height () + w->input ().top + w->input ().bottom; if (ww > maxThumbWidth) xScale = (float)(maxThumbWidth) / (float)ww; else xScale = 1.0f; if (wh > maxThumbHeight) yScale = (float)(maxThumbHeight) / (float)wh; else yScale = 1.0f; float val1 = floor((float) MIN (mNWindows, optionGetCoverMaxVisibleWindows ()) / 2.0); float pos; float space = (maxThumbWidth / 2); space *= cos (sin (PI / 4) * PI / 3); space *= 2; //space += (space / sin (PI / 4)) - space; for (i = 0; i < 2; i++) { if (mInvert ^ (i == 0)) { distance = mMvTarget - index; distance += optionGetCoverOffset (); } else { distance = mMvTarget - index + mNWindows; distance += optionGetCoverOffset (); if (distance > mNWindows) distance -= mNWindows * 2; } pos = MIN (1.0, MAX (-1.0, distance)); sw->mSlots[i].opacity = 1.0 - MIN (1.0, MAX (0.0, fabs(distance) - val1)); sw->mSlots[i].scale = MIN (xScale, yScale); sw->mSlots[i].y = centerY + (maxThumbHeight / 2.0) - (((w->height () / 2.0) + w->input ().bottom) * sw->mSlots[i].scale); if (fabs(distance) < 1.0) { sw->mSlots[i].x = centerX + (sin(pos * PI * 0.5) * space * optionGetCoverExtraSpace ()); sw->mSlots[i].z = fabs (distance); sw->mSlots[i].z *= -(maxThumbWidth / (2.0 * oe.width ())); sw->mSlots[i].rotation = sin(pos * PI * 0.5) * -optionGetCoverAngle (); } else { float rad = (space / oe.width ()) / sin(PI / 6.0); float ang = (PI / MAX(72.0, mNWindows * 2)) * (distance - pos) + (pos * (PI / 6.0)); sw->mSlots[i].x = centerX; sw->mSlots[i].x += sin(ang) * rad * oe.width () * optionGetCoverExtraSpace (); sw->mSlots[i].rotation = optionGetCoverAngle () + 30; sw->mSlots[i].rotation -= fabs(ang) * 180.0 / PI; sw->mSlots[i].rotation *= -pos; sw->mSlots[i].z = -(maxThumbWidth / (2.0 * oe.width ())); sw->mSlots[i].z += -(cos(PI / 6.0) * rad); sw->mSlots[i].z += (cos(ang) * rad); } mDrawSlots[index * 2 + i].w = w; mDrawSlots[index * 2 + i].slot = &sw->mSlots[i]; mDrawSlots[index * 2 + i].distance = fabs(distance); } if (mDrawSlots[index * 2].distance > mDrawSlots[index * 2 + 1].distance) { mDrawSlots[index * 2].slot->primary = false; mDrawSlots[index * 2 + 1].slot->primary = true; } else { mDrawSlots[index * 2].slot->primary = true; mDrawSlots[index * 2 + 1].slot->primary = false; } } mNSlots = mNWindows * 2; qsort (mDrawSlots, mNSlots, sizeof (ShiftDrawSlot), compareShiftWindowDistance); return true; } bool ShiftScreen::layoutThumbsFlip () { CompWindow *w; int index; int ww, wh; float xScale, yScale; float distance; int i; float angle; int slotNum; CompRect oe; if (optionGetMultioutputMode () == ShiftOptions::MultioutputModeOneBigSwitcher) { oe.setGeometry (0, 0, screen->width (), screen->height ()); } else { oe = screen->outputDevs ()[mUsedOutput]; } /* the center of the ellipse is in the middle of the used output device */ int centerX = oe.centerX (); int centerY = oe.centerY (); int maxThumbWidth = oe.width () * optionGetSize () / 100; int maxThumbHeight = oe.height () * optionGetSize () / 100; slotNum = 0; for (index = 0; index < mNWindows; index++) { w = mWindows[index]; SHIFT_WINDOW (w); ww = w->width () + w->input ().left + w->input ().right; wh = w->height () + w->input ().top + w->input ().bottom; if (ww > maxThumbWidth) xScale = (float)(maxThumbWidth) / (float)ww; else xScale = 1.0f; if (wh > maxThumbHeight) yScale = (float)(maxThumbHeight) / (float)wh; else yScale = 1.0f; angle = optionGetFlipRotation () * PI / 180.0; for (i = 0; i < 2; i++) { if (mInvert ^ (i == 0)) distance = mMvTarget - index; else { distance = mMvTarget - index + mNWindows; if (distance > 1.0) distance -= mNWindows * 2; } if (distance > 0.0) sw->mSlots[i].opacity = MAX (0.0, 1.0 - (distance * 1.0)); else { if (distance < -(mNWindows - 1)) sw->mSlots[i].opacity = MAX (0.0, mNWindows + distance); else sw->mSlots[i].opacity = 1.0; } if (distance > 0.0 && w->id () != mSelectedWindow) sw->mSlots[i].primary = false; else sw->mSlots[i].primary = true; sw->mSlots[i].scale = MIN (xScale, yScale); sw->mSlots[i].y = centerY + (maxThumbHeight / 2.0) - (((w->height () / 2.0) + w->input ().bottom) * sw->mSlots[i].scale); sw->mSlots[i].x = sin(angle) * distance * (maxThumbWidth / 2); if (distance > 0 && false) sw->mSlots[i].x *= 1.5; sw->mSlots[i].x += centerX; sw->mSlots[i].z = cos(angle) * distance; if (distance > 0) sw->mSlots[i].z *= 1.5; sw->mSlots[i].z *= (maxThumbWidth / (2.0 * oe.width ())); sw->mSlots[i].rotation = optionGetFlipRotation (); if (sw->mSlots[i].opacity > 0.0) { mDrawSlots[slotNum].w = w; mDrawSlots[slotNum].slot = &sw->mSlots[i]; mDrawSlots[slotNum].distance = -distance; slotNum++; } } } mNSlots = slotNum; qsort (mDrawSlots, mNSlots, sizeof (ShiftDrawSlot), compareShiftWindowDistance); return true; } bool ShiftScreen::layoutThumbs () { bool result = false; if (mState == ShiftStateNone) return false; switch (optionGetMode ()) { case ShiftScreen::ModeCover: result = layoutThumbsCover (); break; case ShiftScreen::ModeFlip: result = layoutThumbsFlip (); break; } if (mState == ShiftStateIn) return false; return result; } void ShiftScreen::addWindowToList (CompWindow *w) { if (mWindowsSize <= mNWindows) { mWindows = (CompWindow **) realloc (mWindows, sizeof (CompWindow *) * (mNWindows + 32)); if (!mWindows) return; mWindowsSize = mNWindows + 32; } if (mSlotsSize <= mNWindows * 2) { mDrawSlots = (ShiftDrawSlot *) realloc (mDrawSlots, sizeof (ShiftDrawSlot) * ((mNWindows * 2) + 64)); if (!mDrawSlots) { free (mDrawSlots); return; } mSlotsSize = (mNWindows * 2) + 64; } mWindows[mNWindows++] = w; } bool ShiftScreen::updateWindowList () { int i, idx; CompWindow **wins; qsort (mWindows, mNWindows, sizeof (CompWindow *), compareWindows); mMvTarget = 0; mMvAdjust = 0; mMvVelocity = 0; for (i = 0; i < mNWindows; i++) { if (mWindows[i]->id () == mSelectedWindow) break; mMvTarget++; } if (mMvTarget == mNWindows) mMvTarget = 0; /* create spetial window order to create a good animation A,B,C,D,E --> A,B,D,E,C to get B,D,E,C,(A),B,D,E,C as initial state */ if (optionGetMode () == ShiftScreen::ModeCover) { wins = (CompWindow **) malloc(mNWindows * sizeof (CompWindow *)); if (!wins) return false; memcpy(wins, mWindows, mNWindows * sizeof (CompWindow *)); for (i = 0; i < mNWindows; i++) { idx = ceil (i * 0.5); idx *= (i & 1) ? 1 : -1; if (idx < 0) idx += mNWindows; mWindows[idx] = wins[i]; } free (wins); } return layoutThumbs (); } bool ShiftScreen::createWindowList () { mNWindows = 0; foreach (CompWindow *w, screen->windows ()) { SHIFT_WINDOW (w); if (sw->isShiftable ()) { addWindowToList (w); sw->mActive = true; } } return updateWindowList (); } void ShiftScreen::switchToWindow (bool toNext) { CompWindow *w; int cur; if (!mGrabIndex) return; for (cur = 0; cur < mNWindows; cur++) { if (mWindows[cur]->id () == mSelectedWindow) break; } if (cur == mNWindows) return; if (toNext) w = mWindows[(cur + 1) % mNWindows]; else w = mWindows[(cur + mNWindows - 1) % mNWindows]; if (w) { Window old = mSelectedWindow; mSelectedWindow = w->id (); if (old != w->id ()) { if (toNext) mMvAdjust += 1; else mMvAdjust -= 1; mMoveAdjust = true; cScreen->damageScreen (); renderWindowTitle (); } } } int ShiftScreen::countWindows () { int count = 0; foreach (CompWindow *w, screen->windows ()) { if (ShiftWindow::get (w)->isShiftable ()) count++; } return count; } int ShiftScreen::adjustShiftMovement (float chunk) { float dx, adjust, amount; float change; dx = mMvAdjust; adjust = dx * 0.15f; amount = fabs(dx) * 1.5f; if (amount < 0.2f) amount = 0.2f; else if (amount > 2.0f) amount = 2.0f; mMvVelocity = (amount * mMvVelocity + adjust) / (amount + 1.0f); if (fabs (dx) < 0.002f && fabs (mMvVelocity) < 0.004f) { mMvVelocity = 0.0f; mMvTarget = mMvTarget + mMvAdjust; mMvAdjust = 0; layoutThumbs (); return false; } change = mMvVelocity * chunk; if (!change) { if (mMvVelocity) change = (mMvAdjust > 0) ? 0.01 : -0.01; } mMvAdjust -= change; mMvTarget += change; while (mMvTarget >= mNWindows) { mMvTarget -= mNWindows; mInvert = !mInvert; } while (mMvTarget < 0) { mMvTarget += mNWindows; mInvert = !mInvert; } if (!layoutThumbs ()) return false; return true; } bool ShiftWindow::adjustShiftAttribs (float chunk) { float dp, db, adjust, amount; float opacity, brightness; SHIFT_SCREEN (screen); if ((mActive && ss->mState != ShiftStateIn && ss->mState != ShiftStateNone) || (ss->optionGetHideAll () && !(window->type () & CompWindowTypeDesktopMask) && (ss->mState == ShiftStateOut || ss->mState == ShiftStateSwitching || ss->mState == ShiftStateFinish))) opacity = 0.0; else opacity = 1.0; if (ss->mState == ShiftStateIn || ss->mState == ShiftStateNone) brightness = 1.0; else brightness = ss->optionGetBackgroundIntensity (); dp = opacity - mOpacity; adjust = dp * 0.1f; amount = fabs (dp) * 7.0f; if (amount < 0.01f) amount = 0.01f; else if (amount > 0.15f) amount = 0.15f; mOpacityVelocity = (amount * mOpacityVelocity + adjust) / (amount + 1.0f); db = brightness - mBrightness; adjust = db * 0.1f; amount = fabs (db) * 7.0f; if (amount < 0.01f) amount = 0.01f; else if (amount > 0.15f) amount = 0.15f; mBrightnessVelocity = (amount * mBrightnessVelocity + adjust) / (amount + 1.0f); /* FIXME: There is a possible floating point overflow here, * can be worked-around but not particularly nice */ if ((fabs (dp) < 0.1f && fabs (mOpacityVelocity) < 0.2f && fabs (db) < 0.1f && fabs (mBrightnessVelocity) < 0.2f) || (fabs(db) != fabs (db) || fabs (mOpacityVelocity) != fabs (mOpacityVelocity) || fabs (dp) != fabs (dp) || fabs (mBrightnessVelocity) != fabs (mBrightnessVelocity))) { mBrightness = brightness; mOpacity = opacity; return false; } mBrightness += mBrightnessVelocity * chunk; mOpacity += mOpacityVelocity * chunk; return true; } bool ShiftScreen::adjustShiftAnimationAttribs (float chunk) { float dr, adjust, amount; float anim; if (mState != ShiftStateIn && mState != ShiftStateNone) anim = 1.0; else anim = 0.0; dr = anim - mAnim; adjust = dr * 0.1f; amount = fabs (dr) * 7.0f; if (amount < 0.002f) amount = 0.002f; else if (amount > 0.15f) amount = 0.15f; mAnimVelocity = (amount * mAnimVelocity + adjust) / (amount + 1.0f); if (fabs (dr) < 0.002f && fabs (mAnimVelocity) < 0.004f) { mAnim = anim; return false; } mAnim += mAnimVelocity * chunk; return true; } bool ShiftScreen::glPaintOutput (const GLScreenPaintAttrib &attrib, const GLMatrix &transform, const CompRegion ®ion, CompOutput *output, unsigned int mask) { bool status; if (mState != ShiftStateNone) mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK; mPaintingAbove = false; mOutput = output; status = gScreen->glPaintOutput (attrib, transform, region, output, mask); if (mState != ShiftStateNone && ((unsigned int) output->id () == (unsigned int) mUsedOutput || ((unsigned int) output->id () == (unsigned int) ~0))) { CompWindow *w; GLMatrix sTransform (transform); int i; int oy1 = screen->outputDevs ()[mUsedOutput].region ()->extents.y1; int oy2 = screen->outputDevs ()[mUsedOutput].region ()->extents.y2; int maxThumbHeight = (oy2 - oy1) * optionGetSize () / 100; int oldFilter = gScreen->textureFilter (); if (optionGetMultioutputMode () == ShiftOptions::MultioutputModeOneBigSwitcher) { oy1 = 0; oy2 = screen->height (); } sTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA); GLdouble clip[4] = { 0.0, -1.0, 0.0, 0.0}; clip[3] = ((oy1 + (oy2 - oy1) / 2)) + (maxThumbHeight / 2.0); /* Reflection drawing */ if (optionGetReflection ()) { GLMatrix rTransform = sTransform; unsigned short color[4]; int cull, cullInv; glGetIntegerv (GL_CULL_FACE_MODE, &cull); cullInv = (cull == GL_BACK)? GL_FRONT : GL_BACK; rTransform.translate (0.0, oy1 + oy2 + maxThumbHeight, 0.0); rTransform.scale (1.0, -1.0, 1.0); glPushMatrix (); glLoadMatrixf (rTransform.getMatrix ()); glCullFace (cullInv); if (optionGetMipmaps ()) gScreen->setTextureFilter (GL_LINEAR_MIPMAP_LINEAR); if (mAnim == 1.0) { glClipPlane (GL_CLIP_PLANE0, clip); glEnable (GL_CLIP_PLANE0); } mReflectActive = true; mReflectBrightness = optionGetIntensity (); for (i = 0; i < mNSlots; i++) { w = mDrawSlots[i].w; SHIFT_WINDOW (w); mActiveSlot = &mDrawSlots[i]; { sw->gWindow->glPaint (sw->gWindow->paintAttrib (), rTransform, infiniteRegion, 0); } } glDisable (GL_CLIP_PLANE0); glCullFace (cull); glLoadIdentity(); glTranslatef (0.0, 0.0, -DEFAULT_Z_CAMERA); glEnable(GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBegin (GL_QUADS); glColor4f (0.0, 0.0, 0.0, 0.0); glVertex2f (0.5, 0.0); glVertex2f (-0.5, 0.0); glColor4f (0.0, 0.0, 0.0, MIN (1.0, 1.0 - optionGetIntensity ()) * 2.0 * mAnim); glVertex2f (-0.5, -0.5); glVertex2f (0.5, -0.5); glEnd(); if (optionGetGroundSize () > 0.0) { glBegin (GL_QUADS); color[0] = optionGetGroundColor1 ()[0]; color[1] = optionGetGroundColor1 ()[1]; color[2] = optionGetGroundColor1 ()[2]; color[3] = (float)optionGetGroundColor1 ()[3] * mAnim; glColor4usv (color); glVertex2f (-0.5, -0.5); glVertex2f (0.5, -0.5); color[0] = optionGetGroundColor2 ()[0]; color[1] = optionGetGroundColor2 ()[1]; color[2] = optionGetGroundColor2 ()[2]; color[3] = (float)optionGetGroundColor2 ()[3] * mAnim; glColor4usv (color); glVertex2f (0.5, -0.5 + optionGetGroundSize ()); glVertex2f (-0.5, -0.5 + optionGetGroundSize ()); glEnd(); } glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); glColor4f (1.0, 1.0, 1.0, 1.0); glPopMatrix (); } /* Drawing normal windows */ glPushMatrix (); glLoadMatrixf (sTransform.getMatrix ()); if (optionGetReflection () && mAnim == 1.0) { glClipPlane (GL_CLIP_PLANE0, clip); glEnable (GL_CLIP_PLANE0); } mReflectBrightness = 1.0; mReflectActive = false; for (i = 0; i < mNSlots; i++) { w = mDrawSlots[i].w; SHIFT_WINDOW (w); mActiveSlot = &mDrawSlots[i]; { sw->gWindow->glPaint (sw->gWindow->paintAttrib (), sTransform, infiniteRegion, 0); } } glDisable (GL_CLIP_PLANE0); mActiveSlot = NULL; gScreen->setTextureFilter (oldFilter); if (textAvailable && (mState != ShiftStateIn)) drawWindowTitle (); if (mState == ShiftStateIn || mState == ShiftStateOut) { bool found; mPaintingAbove = true; w = screen->findWindow (mSelectedWindow); for (; w; w = w->next) { if (w->destroyed ()) continue; if (!w->shaded ()) { if (!w->isViewable () || !CompositeWindow::get (w)->damaged ()) continue; } found = false; for (i = 0; i < mNWindows; i++) if (mWindows[i] == w) found = true; if (found) continue; SHIFT_WINDOW (w); sw->gWindow->glPaint (sw->gWindow->paintAttrib (), sTransform, infiniteRegion, 0); } mPaintingAbove = false; } glPopMatrix (); } return status; } void ShiftScreen::paint (CompOutput::ptrList &outputs, unsigned int mask) { if (mState != ShiftStateNone && outputs.size () > 0 && optionGetMultioutputMode () == ShiftOptions::MultioutputModeOneBigSwitcher) { CompOutput::ptrList newOutputs; newOutputs.push_back (&screen->fullscreenOutput ()); cScreen->paint (newOutputs, mask); return; } cScreen->paint (outputs, mask); return; } void ShiftScreen::preparePaint (int msSinceLastPaint) { if (mState != ShiftStateNone && (mMoreAdjust || mMoveAdjust)) { int steps; float amount, chunk; int i; amount = msSinceLastPaint * 0.05f * optionGetShiftSpeed (); steps = amount / (0.5f * optionGetTimestep ()); if (!steps) steps = 1; chunk = amount / (float) steps; while (steps--) { mMoveAdjust = adjustShiftMovement (chunk); if (!mMoveAdjust) break; } amount = msSinceLastPaint * 0.05f * optionGetSpeed (); steps = amount / (0.5f * optionGetTimestep ()); if (!steps) steps = 1; chunk = amount / (float) steps; while (steps--) { mMoreAdjust = adjustShiftAnimationAttribs (chunk); foreach (CompWindow *w, screen->windows ()) { SHIFT_WINDOW (w); mMoreAdjust |= sw->adjustShiftAttribs (chunk); for (i = 0; i < 2; i++) { ShiftSlot *slot = &sw->mSlots[i]; slot->tx = slot->x - w->x () - (w->width () * slot->scale) / 2; slot->ty = slot->y - w->y () - (w->height () * slot->scale) / 2; } } if (!mMoreAdjust) break; } } cScreen->preparePaint (msSinceLastPaint); } bool ShiftWindow::canStackRelativeTo () { if (window->overrideRedirect ()) return false; if (!window->shaded () && !window->pendingMaps ()) { if (!window->isViewable () || window->mapNum () == 0) return false; } return true; } void ShiftScreen::donePaint () { if (mState != ShiftStateNone) { if (mMoreAdjust) { cScreen->damageScreen (); } else { if (mState == ShiftStateIn) { mState = ShiftStateNone; activateEvent (false); foreach (CompWindow *w, screen->windows ()) { SHIFT_WINDOW (w); sw->mActive = false; } setFunctions (false); cScreen->damageScreen (); } else if (mState == ShiftStateOut) mState = ShiftStateSwitching; if (mMoveAdjust) { cScreen->damageScreen (); } else if (mState == ShiftStateFinish) { CompWindow *w; CompWindow *pw = NULL; int i; mState = ShiftStateIn; mMoreAdjust = true; cScreen->damageScreen (); if (!mCancelled && mMvTarget != 0) for (i = 0; i < mNSlots; i++) { w = mDrawSlots[i].w; SHIFT_WINDOW (w); if (mDrawSlots[i].slot->primary && sw->canStackRelativeTo ()) { if (pw) w->restackAbove (pw); pw = w; } } if (!mCancelled && mSelectedWindow) { w = screen->findWindow (mSelectedWindow); if (w) screen->sendWindowActivationRequest (mSelectedWindow); } } cScreen->damageScreen (); } } cScreen->donePaint (); } void ShiftScreen::term (bool cancel) { if (mGrabIndex) { screen->removeGrab (mGrabIndex, 0); mGrabIndex = 0; } if (mState != ShiftStateNone) { if (cancel && mMvTarget != 0) { if (mNWindows - mMvTarget > mMvTarget) mMvAdjust = -mMvTarget; else mMvAdjust = mNWindows - mMvTarget; mMoveAdjust = true; } mMoreAdjust = false; mMoveAdjust = false; mState = ShiftStateFinish; mCancelled = cancel; cScreen->damageScreen (); } } bool ShiftScreen::terminate (CompAction *action, CompAction::State state, CompOption::Vector &options) { Window xid; xid = CompOption::getIntOptionNamed (options, "root", 0); if (!(xid && screen->root () != xid)) { term ((state & CompAction::StateCancel)); if (action->state () & CompAction::StateTermButton) action->setState (action->state () & ~CompAction::StateTermButton); if (action->state () & CompAction::StateTermKey) action->setState (action->state () & ~CompAction::StateTermKey); } return false; } bool ShiftScreen::initiateScreen (CompAction *action, CompAction::State state, CompOption::Vector &options) { CompMatch match; int count; if (screen->otherGrabExist ("shift", NULL)) return false; mCurrentMatch = &(optionGetWindowMatch ()); match = CompOption::getMatchOptionNamed (options, "match", CompMatch::emptyMatch); if (match != CompMatch::emptyMatch) { mMatch = match; mMatch.update (); mCurrentMatch = &mMatch; } count = countWindows (); if (count < 1) return false; if (!mGrabIndex) mGrabIndex = screen->pushGrab (screen->invisibleCursor (), "shift"); if (mGrabIndex) { mState = ShiftStateOut; activateEvent (true); if (!createWindowList ()) return false; mSelectedWindow = mWindows[0]->id (); renderWindowTitle (); mMvTarget = 0; mMvAdjust = 0; mMvVelocity = 0; mMoreAdjust = true; cScreen->damageScreen (); } mUsedOutput = screen->currentOutputDev ().id (); setFunctions (true); return true; } bool ShiftScreen::doSwitch (CompAction *action, CompAction::State state, CompOption::Vector &options, bool nextWindow, ShiftType type) { bool ret = true; bool initial = false; if ((mState == ShiftStateNone) || (mState == ShiftStateIn)) { if (type == ShiftTypeGroup) { CompWindow *w; w = screen->findWindow (CompOption::getIntOptionNamed (options, "window", 0)); if (w) { mType = ShiftTypeGroup; mClientLeader = (w->clientLeader ()) ? w->clientLeader () : w->id (); ret = initiateScreen (action, state, options); } } else { mType = type; ret = initiateScreen (action, state, options); } if (state & CompAction::StateInitKey) action->setState (state | CompAction::StateTermKey); if (state & CompAction::StateInitButton) action->setState (state | CompAction::StateTermButton); if (state & CompAction::StateInitEdge) action->setState (state | CompAction::StateTermEdge); initial = true; } if (ret) { switchToWindow (nextWindow); if (initial && false) { mMvTarget += mMvAdjust; mMvAdjust = 0.0; } } return ret; } bool ShiftScreen::initiate (CompAction *action, CompAction::State state, CompOption::Vector &options) { bool ret = true; mType = ShiftTypeNormal; if ((mState == ShiftStateNone) || (mState == ShiftStateIn) || (mState == ShiftStateFinish)) ret = initiateScreen (action, state, options); else ret = terminate (action, state, options); if (state & CompAction::StateTermButton) action->setState (state & ~CompAction::StateTermButton); if (state & CompAction::StateTermKey) action->setState (state & ~CompAction::StateTermKey); return ret; } bool ShiftScreen::initiateAll (CompAction *action, CompAction::State state, CompOption::Vector &options) { bool ret = true; mType = ShiftTypeAll; if ((mState == ShiftStateNone) || (mState == ShiftStateIn) || (mState == ShiftStateFinish)) ret = initiateScreen (action, state, options); else ret = terminate (action, state, options); if (state & CompAction::StateTermButton) action->setState (state & ~CompAction::StateTermButton); if (state & CompAction::StateTermKey) action->setState (state & ~CompAction::StateTermKey); return ret; } void ShiftScreen::windowRemove (Window id) { CompWindow *w = screen->findWindow (id); if (w) { bool inList = false; int j, i = 0; Window selected; SHIFT_WINDOW (w); if (mState == ShiftStateNone) return; if (sw->isShiftable ()) return; selected = mSelectedWindow; while (i < mNWindows) { if (w->id () == mWindows[i]->id ()) { inList = true; if (w->id () == selected) { if (i < (mNWindows - 1)) selected = mWindows[i + 1]->id (); else selected = mWindows[0]->id (); mSelectedWindow = selected; } mNWindows--; for (j = i; j < mNWindows; j++) mWindows[j] = mWindows[j + 1]; } else { i++; } } if (!inList) return; if (mNWindows == 0) { CompOption o; CompOption::Vector opts; o = CompOption ("root", CompOption::TypeInt); o.value ().set ((int) screen->root ()); opts.push_back (o); terminate (NULL, 0, opts); return; } // Let the window list be updated to avoid crash // when a window is closed while ending shift (ShiftStateIn). if (!mGrabIndex && mState != ShiftStateIn) return; if (updateWindowList ()) { mMoreAdjust = true; mState = ShiftStateOut; cScreen->damageScreen (); } } } void ShiftScreen::handleEvent (XEvent *event) { screen->handleEvent (event); switch (event->type) { case PropertyNotify: if (event->xproperty.atom == XA_WM_NAME) { CompWindow *w; w = screen->findWindow (event->xproperty.window); if (w) { if (mGrabIndex && (w->id () == mSelectedWindow)) { renderWindowTitle (); cScreen->damageScreen (); } } } break; case UnmapNotify: windowRemove (event->xunmap.window); break; case DestroyNotify: windowRemove (event->xdestroywindow.window); break; case KeyPress: if (mState == ShiftStateSwitching) { if (event->xkey.keycode == mLeftKey) switchToWindow (false); else if (event->xkey.keycode == mRightKey) switchToWindow (true); else if (event->xkey.keycode == mUpKey) switchToWindow (false); else if (event->xkey.keycode == mDownKey) switchToWindow (true); } break; case ButtonPress: if (mState == ShiftStateSwitching || mState == ShiftStateOut) { if (event->xbutton.button == Button5) switchToWindow (false); else if (event->xbutton.button == Button4) switchToWindow (true); if (event->xbutton.button == Button1) { mButtonPressTime = event->xbutton.time; mButtonPressed = true; mStartX = event->xbutton.x_root; mStartY = event->xbutton.y_root; mStartTarget = mMvTarget + mMvAdjust; } } break; case ButtonRelease: if (mState == ShiftStateSwitching || mState == ShiftStateOut) { if (event->xbutton.button == Button1 && mButtonPressed) { int iNew; if ((int)(event->xbutton.time - mButtonPressTime) < optionGetClickDuration ()) term (false); mButtonPressTime = 0; mButtonPressed = false; if (mMvTarget - floor (mMvTarget) >= 0.5) { mMvAdjust = ceil(mMvTarget) - mMvTarget; iNew = ceil(mMvTarget); } else { mMvAdjust = floor(mMvTarget) - mMvTarget; iNew = floor(mMvTarget); } while (iNew < 0) iNew += mNWindows; iNew = iNew % mNWindows; mSelectedWindow = mWindows[iNew]->id (); renderWindowTitle (); mMoveAdjust = true; cScreen->damageScreen (); } } break; case MotionNotify: if (mState == ShiftStateSwitching || mState == ShiftStateOut) { if (mButtonPressed) { CompRect oe = screen->outputDevs ()[mUsedOutput]; float div = 0; int wx = 0; int wy = 0; int iNew; switch (optionGetMode ()) { case ShiftOptions::ModeCover: div = event->xmotion.x_root - mStartX; div /= oe.width () / optionGetMouseSpeed (); break; case ShiftOptions::ModeFlip: div = event->xmotion.y_root - mStartY; div /= oe.height () / optionGetMouseSpeed (); break; } mMvTarget = mStartTarget + div - mMvAdjust; mMoveAdjust = true; while (mMvTarget >= mNWindows) { mMvTarget -= mNWindows; mInvert = !mInvert; } while (mMvTarget < 0) { mMvTarget += mNWindows; mInvert = !mInvert; } if (mMvTarget - floor (mMvTarget) >= 0.5) iNew = ceil(mMvTarget); else iNew = floor(mMvTarget); while (iNew < 0) iNew += mNWindows; iNew = iNew % mNWindows; if (mSelectedWindow != mWindows[iNew]->id ()) { mSelectedWindow = mWindows[iNew]->id (); renderWindowTitle (); } if (event->xmotion.x_root < 50) wx = 50; if (screen->width () - event->xmotion.x_root < 50) wx = -50; if (event->xmotion.y_root < 50) wy = 50; if (screen->height () - event->xmotion.y_root < 50) wy = -50; if (wx != 0 || wy != 0) { screen->warpPointer (wx, wy); mStartX += wx; mStartY += wy; } cScreen->damageScreen (); } } break; } } bool ShiftWindow::damageRect (bool initial, const CompRect &rect) { bool status = false; SHIFT_SCREEN (screen); if (initial) { if (ss->mGrabIndex && isShiftable ()) { ss->addWindowToList (window); if (ss->updateWindowList ()) { mActive = true; ss->mMoreAdjust = true; ss->mState = ShiftStateOut; ss->cScreen->damageScreen (); } } } else if (ss->mState == ShiftStateSwitching) { if (mActive) { ss->cScreen->damageScreen (); status = true; } } status |= cWindow->damageRect (initial, rect); return status; } ShiftScreen::ShiftScreen (CompScreen *screen) : PluginClassHandler (screen), cScreen (CompositeScreen::get (screen)), gScreen (GLScreen::get (screen)), mLeftKey (XKeysymToKeycode (screen->dpy (), XStringToKeysym ("Left"))), mRightKey (XKeysymToKeycode (screen->dpy (), XStringToKeysym ("Right"))), mUpKey (XKeysymToKeycode (screen->dpy (), XStringToKeysym ("Up"))), mDownKey (XKeysymToKeycode (screen->dpy (), XStringToKeysym ("Down"))), mGrabIndex (0), mState (ShiftStateNone), mMoreAdjust (false), mMvTarget (0), mMvVelocity (0), mInvert (false), mCursor (XCreateFontCursor (screen->dpy (), XC_left_ptr)), mWindows (NULL), mNWindows (0), mWindowsSize (0), mDrawSlots (NULL), mNSlots (0), mSlotsSize (0), mActiveSlot (NULL), mSelectedWindow (0), mCurrentMatch (NULL), mUsedOutput (0), mAnim (0.0), mAnimVelocity (0.0), mButtonPressTime (0), mButtonPressed (false), mStartX (0), mStartY (0), mStartTarget (0.0f) { ScreenInterface::setHandler (screen, false); CompositeScreenInterface::setHandler (cScreen, false); GLScreenInterface::setHandler (gScreen, false); #define SHIFTINITBIND(opt, func) \ optionSet##opt##Initiate (boost::bind (&ShiftScreen::func, \ this, _1, _2, _3)); #define SHIFTTERMBIND(opt, func) \ optionSet##opt##Terminate (boost::bind (&ShiftScreen::func, \ this, _1, _2, _3)); #define SHIFTSWITCHBIND(opt, func, next, type) \ optionSet##opt##Initiate (boost::bind (&ShiftScreen::func, \ this, _1, _2, _3, \ next, type)); /* Key actions */ SHIFTINITBIND (InitiateKey, initiate); SHIFTINITBIND (InitiateAllKey, initiateAll); SHIFTSWITCHBIND (NextKey, doSwitch, true, ShiftTypeNormal); SHIFTSWITCHBIND (PrevKey, doSwitch, false, ShiftTypeNormal); SHIFTSWITCHBIND (NextAllKey, doSwitch, true, ShiftTypeAll); SHIFTSWITCHBIND (PrevAllKey, doSwitch, false, ShiftTypeAll); SHIFTSWITCHBIND (NextGroupKey, doSwitch, true, ShiftTypeGroup); SHIFTSWITCHBIND (PrevGroupKey, doSwitch, false, ShiftTypeGroup); SHIFTTERMBIND (NextKey, terminate); SHIFTTERMBIND (PrevKey, terminate); SHIFTTERMBIND (NextAllKey, terminate); SHIFTTERMBIND (PrevAllKey, terminate); SHIFTTERMBIND (NextGroupKey, terminate); SHIFTTERMBIND (PrevGroupKey, terminate); SHIFTTERMBIND (InitiateKey, terminate); SHIFTTERMBIND (InitiateAllKey, terminate); /* Button Actions */ SHIFTINITBIND (InitiateButton, initiate); SHIFTINITBIND (InitiateAllButton, initiateAll); SHIFTSWITCHBIND (NextButton, doSwitch, true, ShiftTypeNormal); SHIFTSWITCHBIND (PrevButton, doSwitch, false, ShiftTypeNormal); SHIFTSWITCHBIND (NextAllButton, doSwitch, true, ShiftTypeAll); SHIFTSWITCHBIND (PrevAllButton, doSwitch, false, ShiftTypeAll); SHIFTSWITCHBIND (NextGroupButton, doSwitch, true, ShiftTypeGroup); SHIFTSWITCHBIND (PrevGroupButton, doSwitch, false, ShiftTypeGroup); SHIFTTERMBIND (NextButton, terminate); SHIFTTERMBIND (PrevButton, terminate); SHIFTTERMBIND (NextAllButton, terminate); SHIFTTERMBIND (PrevAllButton, terminate); SHIFTTERMBIND (NextGroupButton, terminate); SHIFTTERMBIND (PrevGroupButton, terminate); SHIFTTERMBIND (InitiateButton, terminate); SHIFTTERMBIND (InitiateAllButton, terminate); /* Edge Actions */ SHIFTINITBIND (InitiateEdge, initiate); SHIFTINITBIND (InitiateAllEdge, initiateAll); SHIFTTERMBIND (InitiateEdge, terminate); SHIFTTERMBIND (InitiateAllEdge, terminate); } ShiftScreen::~ShiftScreen () { freeWindowTitle (); XFreeCursor (screen->dpy (), mCursor); if (mWindows) free (mWindows); if (mDrawSlots) free (mDrawSlots); } ShiftWindow::ShiftWindow (CompWindow *window) : PluginClassHandler (window), window (window), cWindow (CompositeWindow::get (window)), gWindow (GLWindow::get (window)), mOpacity (1.0), mBrightness (1.0), mOpacityVelocity (0.0f), mBrightnessVelocity (0.0f), mActive (false) { CompositeWindowInterface::setHandler (cWindow, false); GLWindowInterface::setHandler (gWindow, false); mSlots[0].scale = 1.0; mSlots[1].scale = 1.0; } ShiftWindow::~ShiftWindow () { } bool ShiftPluginVTable::init () { if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) || !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) || !CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI)) return false; if (!CompPlugin::checkPluginABI ("text", COMPIZ_TEXT_ABI)) { compLogMessage ("shift", CompLogLevelWarn, "No compatible text plugin"\ " loaded"); textAvailable = false; } else textAvailable = true; return true; }