diff --git a/effects.cpp b/effects.cpp index 8e73780066..ece7950520 100644 --- a/effects.cpp +++ b/effects.cpp @@ -270,12 +270,12 @@ void EffectsHandlerImpl::postPaintWindow(EffectWindow* w) // no special final code } -bool EffectsHandlerImpl::provides(Effect::Feature ef) +Effect *EffectsHandlerImpl::provides(Effect::Feature ef) { for (int i = 0; i < loaded_effects.size(); ++i) if (loaded_effects.at(i).second->provides(ef)) - return true; - return false; + return loaded_effects.at(i).second; + return NULL; } void EffectsHandlerImpl::drawWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) diff --git a/effects.h b/effects.h index 994a89c3b3..19aefa2553 100644 --- a/effects.h +++ b/effects.h @@ -57,7 +57,7 @@ public: virtual void postPaintWindow(EffectWindow* w); virtual void paintEffectFrame(EffectFrame* frame, QRegion region, double opacity, double frameOpacity); - bool provides(Effect::Feature ef); + Effect *provides(Effect::Feature ef); virtual void drawWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data); diff --git a/effects/invert/invert.cpp b/effects/invert/invert.cpp index e87851605a..3ac78a7dc0 100644 --- a/effects/invert/invert.cpp +++ b/effects/invert/invert.cpp @@ -48,7 +48,7 @@ InvertEffect::InvertEffect() KAction* a = (KAction*)actionCollection->addAction("Invert"); a->setText(i18n("Toggle Invert Effect")); a->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::META + Qt::Key_I)); - connect(a, SIGNAL(triggered(bool)), this, SLOT(toggle())); + connect(a, SIGNAL(triggered(bool)), this, SLOT(toggleScreenInversion())); KAction* b = (KAction*)actionCollection->addAction("InvertWindow"); b->setText(i18n("Toggle Invert Effect on Window")); @@ -143,7 +143,7 @@ void InvertEffect::slotWindowClosed(EffectWindow* w) m_windows.removeOne(w); } -void InvertEffect::toggle() +void InvertEffect::toggleScreenInversion() { m_allWindows = !m_allWindows; effects->addRepaintFull(); @@ -163,6 +163,11 @@ bool InvertEffect::isActive() const return m_valid && (m_allWindows || !m_windows.isEmpty()); } +bool InvertEffect::provides(Feature f) +{ + return f == ScreenInversion; +} + } // namespace #include "invert.moc" diff --git a/effects/invert/invert.h b/effects/invert/invert.h index d02a5707fa..908eef4aff 100644 --- a/effects/invert/invert.h +++ b/effects/invert/invert.h @@ -45,11 +45,12 @@ public: virtual void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time); virtual void paintEffectFrame(KWin::EffectFrame* frame, QRegion region, double opacity, double frameOpacity); virtual bool isActive() const; + virtual bool provides(Feature); static bool supported(); public slots: - void toggle(); + void toggleScreenInversion(); void toggleWindow(); void slotWindowClosed(KWin::EffectWindow *w); diff --git a/kwinbindings.cpp b/kwinbindings.cpp index 3284cf0700..1f0d7ceda0 100644 --- a/kwinbindings.cpp +++ b/kwinbindings.cpp @@ -191,6 +191,7 @@ a->setText(i18n("Miscellaneous")); DEF(I18N_NOOP("Kill Window"), Qt::CTRL + Qt::ALT + Qt::Key_Escape, slotKillWindow()); DEF(I18N_NOOP("Block Global Shortcuts"), 0, slotDisableGlobalShortcuts()); DEF(I18N_NOOP("Suspend Compositing"), Qt::SHIFT + Qt::ALT + Qt::Key_F12, slotToggleCompositing()); +DEF(I18N_NOOP("Invert Screen Colors"), 0, slotInvertScreen()); #undef DEF #undef DEF2 diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h index 1a6c7fce1e..906aed3630 100644 --- a/libkwineffects/kwineffects.h +++ b/libkwineffects/kwineffects.h @@ -320,8 +320,7 @@ public: }; enum Feature { - Nothing = 0, Resize, GeometryTip, - Outline + Nothing = 0, Resize, GeometryTip, Outline, ScreenInversion }; /** @@ -415,7 +414,7 @@ public: /** * Called on Transparent resizes. - * return true if your effect substitutes the XOR rubberband + * return true if your effect substitutes questioned feature */ virtual bool provides(Feature); diff --git a/useractions.cpp b/useractions.cpp index 1327d872ec..27198f6651 100644 --- a/useractions.cpp +++ b/useractions.cpp @@ -44,6 +44,10 @@ along with this program. If not, see . #include #endif +#include +#ifndef KWIN_NO_XF86VM +#include +#endif #include #include #include @@ -1615,6 +1619,80 @@ void Workspace::slotWindowResize() performWindowOperation(active_client, Options::UnrestrictedResizeOp); } +void Workspace::slotInvertScreen() +{ + bool succeeded = false; + + //BEGIN Xrandr inversion - does atm NOT work with the nvidia blob + XRRScreenResources *res = XRRGetScreenResources(display(), active_client ? active_client->window() : rootWindow()); + if (res) { + for (int j = 0; j < res->ncrtc; ++j) { + XRRCrtcGamma *gamma = XRRGetCrtcGamma(display(), res->crtcs[j]); + if (gamma && gamma->size) { + kDebug(1212) << "inverting screen using XRRSetCrtcGamma"; + const int half = gamma->size / 2 + 1; + unsigned short swap; + for (int i = 0; i < half; ++i) { +#define INVERT(_C_) swap = gamma->_C_[i]; gamma->_C_[i] = gamma->_C_[gamma->size - 1 - i]; gamma->_C_[gamma->size - 1 - i] = swap + INVERT(red); + INVERT(green); + INVERT(blue); +#undef INVERT + } + XRRSetCrtcGamma(display(), res->crtcs[j], gamma); + XRRFreeGamma(gamma); + succeeded = true; + } + } + XRRFreeScreenResources(res); + } + if (succeeded) + return; + + //BEGIN XF86VidMode inversion - only works if optionally libXxf86vm is linked +#ifndef KWIN_NO_XF86VM + int size = 0; + // TODO: this doesn't work with screen numbers in twinview - probably relevant only for multihead? + const int scrn = 0; // active_screen + if (XF86VidModeGetGammaRampSize(display(), scrn, &size)) { + unsigned short *red, *green, *blue; + red = new unsigned short[size]; + green = new unsigned short[size]; + blue = new unsigned short[size]; + if (XF86VidModeGetGammaRamp(display(), scrn, size, red, green, blue)) { + kDebug(1212) << "inverting screen using XF86VidModeSetGammaRamp"; + const int half = size / 2 + 1; + unsigned short swap; + for (int i = 0; i < half; ++i) { + swap = red[i]; red[i] = red[size - 1 - i]; red[size - 1 - i] = swap; + swap = green[i]; green[i] = green[size - 1 - i]; green[size - 1 - i] = swap; + swap = blue[i]; blue[i] = blue[size - 1 - i]; blue[size - 1 - i] = swap; + } + XF86VidModeSetGammaRamp(display(), scrn, size, red, green, blue); + succeeded = true; + } + delete [] red; + delete [] green; + delete [] blue; + } + + if (succeeded) + return; +#endif + + //BEGIN effect plugin inversion - atm only works with OpenGL and has an overhead to it + if (effects) { + if (Effect *inverter = static_cast(effects)->provides(Effect::ScreenInversion)) { + kDebug(1212) << "inverting screen using Effect plugin"; + QMetaObject::invokeMethod(inverter, "toggleScreenInversion", Qt::DirectConnection); + } + } + + if (!succeeded) + kDebug(1212) << "sorry - neither Xrandr, nor XF86VidModeSetGammaRamp worked and there's no inversion supplying effect plugin either"; + +} + #undef USABLE_ACTIVE_CLIENT void Client::setShortcut(const QString& _cut) diff --git a/workspace.h b/workspace.h index e271f8fafa..3be2bc523a 100644 --- a/workspace.h +++ b/workspace.h @@ -622,6 +622,7 @@ public slots: void slotSetupWindowShortcut(); void setupWindowShortcutDone(bool); void slotToggleCompositing(); + void slotInvertScreen(); void updateClientArea(); void suspendCompositing();