diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt index cd77323d40..cdd26577b3 100644 --- a/effects/CMakeLists.txt +++ b/effects/CMakeLists.txt @@ -112,6 +112,7 @@ endif() # Common effects include( dialogparent/CMakeLists.txt ) +include( kscreen/CMakeLists.txt ) include( presentwindows/CMakeLists.txt ) include( screenedge/CMakeLists.txt ) include( slidingpopups/CMakeLists.txt ) diff --git a/effects/kscreen/CMakeLists.txt b/effects/kscreen/CMakeLists.txt new file mode 100644 index 0000000000..9f2aec0a02 --- /dev/null +++ b/effects/kscreen/CMakeLists.txt @@ -0,0 +1,14 @@ +####################################### +# Effect + +# Source files +set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources} + kscreen/kscreen.cpp +) + +kde4_add_kcfg_files(kwin4_effect_builtins_sources kscreen/kscreenconfig.kcfgc) + +# .desktop files +install( FILES + kscreen/kscreen.desktop + DESTINATION ${SERVICES_INSTALL_DIR}/kwin ) diff --git a/effects/kscreen/kscreen.cpp b/effects/kscreen/kscreen.cpp new file mode 100644 index 0000000000..c3cf9e2f88 --- /dev/null +++ b/effects/kscreen/kscreen.cpp @@ -0,0 +1,191 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2013 Martin Gräßlin + +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. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +// own +#include "kscreen.h" +// KConfigSkeleton +#include "kscreenconfig.h" + +/** + * How this effect works: + * + * Effect announces that it is around through property _KDE_KWIN_KSCREEN_SUPPORT on the root window. + * + * KScreen watches for this property and when it wants to adjust screens, KScreen goes + * through the following protocol: + * 1. KScreen sets the property value to 1 + * 2. Effect starts to fade out all windows + * 3. When faded out the effect sets property value to 2 + * 4. KScreen adjusts the screens + * 5. KScreen sets property value to 3 + * 6. Effect starts to fade in all windows again + * 7. Effect sets back property value to 0 + * + * The property has type 32 bits cardinal. To test it use: + * xprop -root -f _KDE_KWIN_KSCREEN_SUPPORT 32c -set _KDE_KWIN_KSCREEN_SUPPORT 1 + * + * The states are: + * 0: normal + * 1: fading out + * 2: faded out + * 3: fading in + **/ + +namespace KWin +{ + +KWIN_EFFECT(kscreen, KscreenEffect) + +KscreenEffect::KscreenEffect() + : Effect() + , m_state(StateNormal) + , m_atom(effects->announceSupportProperty("_KDE_KWIN_KSCREEN_SUPPORT", this)) +{ + connect(effects, SIGNAL(propertyNotify(KWin::EffectWindow*,long)), SLOT(propertyNotify(KWin::EffectWindow*,long))); + reconfigure(ReconfigureAll); +} + +KscreenEffect::~KscreenEffect() +{ +} + +void KscreenEffect::reconfigure(ReconfigureFlags flags) +{ + Q_UNUSED(flags) + + KscreenConfig::self()->readConfig(); + m_timeLine.setDuration(animationTime(250)); +} + +void KscreenEffect::prePaintScreen(ScreenPrePaintData &data, int time) +{ + if (m_state == StateFadingIn || m_state == StateFadingOut) { + m_timeLine.setCurrentTime(m_timeLine.currentTime() + time); + if (m_timeLine.currentValue() >= 1.0) { + switchState(); + } + } + effects->prePaintScreen(data, time); +} + +void KscreenEffect::postPaintScreen() +{ + if (m_state == StateFadingIn || m_state == StateFadingOut) { + effects->addRepaintFull(); + } +} + +void KscreenEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) +{ + if (m_state != StateNormal) { + data.setTranslucent(); + } + effects->prePaintWindow(w, data, time); +} + +void KscreenEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) +{ + switch (m_state) { + case StateFadingOut: + data.multiplyOpacity(1.0 - m_timeLine.currentValue()); + break; + case StateFadedOut: + data.multiplyOpacity(0.0); + break; + case StateFadingIn: + data.multiplyOpacity(m_timeLine.currentValue()); + break; + default: + // no adjustment + break; + } + effects->paintWindow(w, mask, region, data); +} + +void KscreenEffect::propertyNotify(EffectWindow *window, long int atom) +{ + if (window || atom != m_atom) { + return; + } + QByteArray byteData = effects->readRootProperty(m_atom, XCB_ATOM_CARDINAL, 32); + long *data = reinterpret_cast(byteData.data()); + if (!data[0]) { + // Property was deleted + if (m_state != StateNormal) { + m_state = StateNormal; + effects->addRepaintFull(); + } + return; + } + if (data[0] == 0) { + // normal state - KWin should have switched to it + if (m_state != StateNormal) { + m_state = StateNormal; + effects->addRepaintFull(); + } + return; + } + if (data[0] == 2) { + // faded out state - KWin should have switched to it + if (m_state != StateFadedOut) { + m_state = StateFadedOut; + effects->addRepaintFull(); + } + return; + } + if (data[0] == 1) { + // kscreen wants KWin to fade out all windows + m_state = StateFadingOut; + m_timeLine.setCurrentTime(0); + effects->addRepaintFull(); + return; + } + if (data[0] == 3) { + // kscreen wants KWin to fade in again + m_state = StateFadingIn; + m_timeLine.setCurrentTime(0); + effects->addRepaintFull(); + return; + } + kDebug(1212) << "Incorrect Property state, immediate stop: " << data[0]; + m_state = StateNormal; + effects->addRepaintFull(); +} + +void KscreenEffect::switchState() +{ + long value = -1l; + if (m_state == StateFadingOut) { + m_state = StateFadedOut; + value = 2l; + } else if (m_state == StateFadingIn) { + m_state = StateNormal; + value = 0l; + } + if (value != -1l) { + xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, rootWindow(), m_atom, XCB_ATOM_CARDINAL, 32, 1, &value); + } +} + +bool KscreenEffect::isActive() const +{ + return m_state != StateNormal; +} + +} // namespace KWin diff --git a/effects/kscreen/kscreen.desktop b/effects/kscreen/kscreen.desktop new file mode 100644 index 0000000000..1be24af355 --- /dev/null +++ b/effects/kscreen/kscreen.desktop @@ -0,0 +1,19 @@ +[Desktop Entry] +Name=Kscreen +Icon=preferences-system-windows-effect-kscreen +Comment=Helper Effect for KScreen + +Type=Service +X-KDE-ServiceTypes=KWin/Effect +X-KDE-PluginInfo-Author=Martin Gräßlin +X-KDE-PluginInfo-Email=mgraesslin@kde.org +X-KDE-PluginInfo-Name=kwin4_effect_kscreen +X-KDE-PluginInfo-Version=0.1.0 +X-KDE-PluginInfo-Category=Appearance +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true +X-KDE-Library=kwin4_effect_builtins +X-KDE-Ordering=99 +X-KWin-Requires-OpenGL=false +X-KWin-Requires-Shaders=false diff --git a/effects/kscreen/kscreen.h b/effects/kscreen/kscreen.h new file mode 100644 index 0000000000..278deeda09 --- /dev/null +++ b/effects/kscreen/kscreen.h @@ -0,0 +1,64 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2013 Martin Gräßlin + +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. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef KWIN_KSCREEN_H +#define KWIN_KSCREEN_H + +#include +// Qt +#include + +namespace KWin +{ + +class KscreenEffect : public Effect +{ + Q_OBJECT + +public: + KscreenEffect(); + virtual ~KscreenEffect(); + + virtual void prePaintScreen(ScreenPrePaintData &data, int time); + virtual void postPaintScreen(); + virtual void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time); + virtual void paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data); + + void reconfigure(ReconfigureFlags flags); + virtual bool isActive() const; + +private Q_SLOTS: + void propertyNotify(KWin::EffectWindow *window, long atom); + +private: + void switchState(); + enum FadeOutState { + StateNormal, + StateFadingOut, + StateFadedOut, + StateFadingIn + }; + QTimeLine m_timeLine; + FadeOutState m_state; + xcb_atom_t m_atom; +}; + + +} // namespace KWin +#endif // KWIN_KSCREEN_H diff --git a/effects/kscreen/kscreen.kcfg b/effects/kscreen/kscreen.kcfg new file mode 100644 index 0000000000..41232357aa --- /dev/null +++ b/effects/kscreen/kscreen.kcfg @@ -0,0 +1,12 @@ + + + + + + 0 + + + diff --git a/effects/kscreen/kscreenconfig.kcfgc b/effects/kscreen/kscreenconfig.kcfgc new file mode 100644 index 0000000000..c2b8bbbe61 --- /dev/null +++ b/effects/kscreen/kscreenconfig.kcfgc @@ -0,0 +1,5 @@ +File=kscreen.kcfg +ClassName=KscreenConfig +NameSpace=KWin +Singleton=true +Mutators=true