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();