From 99e23ca6f75a677a4035efa5831fbf481c170e48 Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Thu, 23 Jul 2009 19:06:50 +0000 Subject: [PATCH] a new effect: windows with the atom _KDE_SLIDE set on them (composed by a number identifying north/south/west/east and a screen coord) will appear with a slide animation. used for popups that come out of panels svn path=/trunk/KDE/kdebase/workspace/; revision=1001604 --- effects/CMakeLists.txt | 1 + effects/slidingpopups/CMakeLists.txt | 12 ++ effects/slidingpopups/slidingpopups.cpp | 179 ++++++++++++++++++++ effects/slidingpopups/slidingpopups.desktop | 18 ++ effects/slidingpopups/slidingpopups.h | 67 ++++++++ 5 files changed, 277 insertions(+) create mode 100644 effects/slidingpopups/CMakeLists.txt create mode 100644 effects/slidingpopups/slidingpopups.cpp create mode 100644 effects/slidingpopups/slidingpopups.desktop create mode 100644 effects/slidingpopups/slidingpopups.h diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt index b12ca6c988..0c4bf08872 100644 --- a/effects/CMakeLists.txt +++ b/effects/CMakeLists.txt @@ -71,6 +71,7 @@ include( showfps/CMakeLists.txt ) include( showpaint/CMakeLists.txt ) include( slide/CMakeLists.txt ) include( slideback/CMakeLists.txt ) +include( slidingpopups/CMakeLists.txt ) include( taskbarthumbnail/CMakeLists.txt ) include( thumbnailaside/CMakeLists.txt ) include( zoom/CMakeLists.txt ) diff --git a/effects/slidingpopups/CMakeLists.txt b/effects/slidingpopups/CMakeLists.txt new file mode 100644 index 0000000000..fec1a1b14b --- /dev/null +++ b/effects/slidingpopups/CMakeLists.txt @@ -0,0 +1,12 @@ +####################################### +# Effect + +# Source files +set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources} + slidingpopups/slidingpopups.cpp + ) + +# .desktop files +install( FILES + slidingpopups/slidingpopups.desktop + DESTINATION ${SERVICES_INSTALL_DIR}/kwin ) diff --git a/effects/slidingpopups/slidingpopups.cpp b/effects/slidingpopups/slidingpopups.cpp new file mode 100644 index 0000000000..41276c7878 --- /dev/null +++ b/effects/slidingpopups/slidingpopups.cpp @@ -0,0 +1,179 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2009 Marco Martin notmart@gmail.com + +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 . +*********************************************************************/ + +#include "slidingpopups.h" + +#include + +namespace KWin +{ + +KWIN_EFFECT( slidingpopups, SlidingPopupsEffect ) + +SlidingPopupsEffect::SlidingPopupsEffect() + { + mAtom = XInternAtom( display(), "_KDE_SLIDE", False ); + effects->registerPropertyType( mAtom, true ); + // TODO hackish way to announce support, make better after 4.0 + unsigned char dummy = 0; + XChangeProperty( display(), rootWindow(), mAtom, mAtom, 8, PropModeReplace, &dummy, 1 ); + } + +SlidingPopupsEffect::~SlidingPopupsEffect() + { + XDeleteProperty( display(), rootWindow(), mAtom ); + effects->registerPropertyType( mAtom, false ); + } + +void SlidingPopupsEffect::prePaintScreen( ScreenPrePaintData& data, int time ) + { + if( !mAppearingWindows.isEmpty() || !mDisappearingWindows.isEmpty() ) + data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; + effects->prePaintScreen( data, time ); + } + +void SlidingPopupsEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time ) + { + if( mAppearingWindows.contains( w ) ) + { + mAppearingWindows[ w ].addTime( time ); + if( mAppearingWindows[ w ].value() < 1 ) + data.setTransformed(); + else + mAppearingWindows.remove( w ); + } + else if( mDisappearingWindows.contains( w ) ) + { + mDisappearingWindows[ w ].addTime( time ); + if( mDisappearingWindows[ w ].value() < 1 ) + data.setTransformed(); + else + { + mDisappearingWindows.remove( w ); + w->unrefWindow(); + } + } + effects->prePaintWindow( w, data, time ); + } + +void SlidingPopupsEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) + { + bool animating = false; + bool appearing = false; + QRegion clippedRegion = region; + + if( mAppearingWindows.contains( w ) ) + { + appearing = true; + animating = true; + } + else if( mDisappearingWindows.contains( w ) ) + { + appearing = false; + animating = true; + } + + + if( animating ) + { + const qreal progress = appearing?(1 - mAppearingWindows[ w ].value()):mDisappearingWindows[ w ].value(); + const int start = mWindowsData[ w ].start; + + switch (mWindowsData[ w ].from) + { + case West: + data.xTranslate += (start - w->width()) * progress; + clippedRegion = clippedRegion.subtracted(QRegion(start - w->width(), w->y(), w->width(), w->height())); + break; + case North: + data.yTranslate += (start - w->height()) * progress; + clippedRegion = clippedRegion.subtracted(QRegion(w->x(), start - w->height(), w->width(), w->height())); + break; + case East: + data.xTranslate += (start - w->x()) * progress; + clippedRegion = clippedRegion.subtracted(QRegion(w->x()+w->width(), w->y(), w->width(), w->height())); + break; + case South: + default: + data.yTranslate += (start - w->y()) * progress; + clippedRegion = clippedRegion.subtracted(QRegion(w->x(), start, w->width(), w->height())); + } + } + + effects->paintWindow( w, mask, clippedRegion, data ); + } + +void SlidingPopupsEffect::postPaintWindow( EffectWindow* w ) + { + if( mAppearingWindows.contains( w ) || mDisappearingWindows.contains( w ) ) + w->addRepaintFull(); // trigger next animation repaint + effects->postPaintWindow( w ); + } + +void SlidingPopupsEffect::windowAdded( EffectWindow* w ) + { + propertyNotify( w, mAtom ); + if( w->isOnCurrentDesktop() && mWindowsData.contains( w ) ) + { + mAppearingWindows[ w ].setDuration( animationTime( 250 )); + mAppearingWindows[ w ].setProgress( 0.0 ); + mAppearingWindows[ w ].setCurveShape( TimeLine::EaseOutCurve ); + + w->addRepaintFull(); + } + } + +void SlidingPopupsEffect::windowClosed( EffectWindow* w ) + { + propertyNotify( w, mAtom ); + if( w->isOnCurrentDesktop() && !w->isMinimized() && mWindowsData.contains( w ) ) + { + w->refWindow(); + mAppearingWindows.remove( w ); + mDisappearingWindows[ w ].setDuration( animationTime( 250 )); + mDisappearingWindows[ w ].setProgress( 0.0 ); + mDisappearingWindows[ w ].setCurveShape( TimeLine::EaseOutCurve ); + + w->addRepaintFull(); + } + } + +void SlidingPopupsEffect::windowDeleted( EffectWindow* w ) + { + mAppearingWindows.remove( w ); + mDisappearingWindows.remove( w ); + mWindowsData.remove( w ); + } + +void SlidingPopupsEffect::propertyNotify( EffectWindow* w, long a ) + { + if( a != mAtom ) + return; + + QByteArray data = w->readProperty( mAtom, mAtom, 32 ); + if( data.length() < 1 ) + return; + long* d = reinterpret_cast< long* >( data.data()); + Data animData; + animData.start = d[ 0 ]; + animData.from = (Position)d[ 1 ]; + mWindowsData[ w ] = animData; + } +} // namespace diff --git a/effects/slidingpopups/slidingpopups.desktop b/effects/slidingpopups/slidingpopups.desktop new file mode 100644 index 0000000000..06620050e7 --- /dev/null +++ b/effects/slidingpopups/slidingpopups.desktop @@ -0,0 +1,18 @@ +[Desktop Entry] +Name=Sliding popups + +Type=Service +Comment=Sliding animation for Plasma popups + +Icon=preferences-system-windows-effect-slidingpopups +X-KDE-ServiceTypes=KWin/Effect +X-KDE-PluginInfo-Author=Marco Martin +X-KDE-PluginInfo-Email=notmart@gmail.com +X-KDE-PluginInfo-Name=kwin4_effect_slidingpopups +X-KDE-PluginInfo-Version=0.1 +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=50 diff --git a/effects/slidingpopups/slidingpopups.h b/effects/slidingpopups/slidingpopups.h new file mode 100644 index 0000000000..d75cc3e650 --- /dev/null +++ b/effects/slidingpopups/slidingpopups.h @@ -0,0 +1,67 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2009 Marco Martin notmart@gmail.com + +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_SLIDEBACK_H +#define KWIN_SLIDEBACK_H + +// Include with base class for effects. +#include + +namespace KWin +{ + +class SlidingPopupsEffect + : public Effect + { + public: + SlidingPopupsEffect(); + ~SlidingPopupsEffect(); + virtual void prePaintScreen( ScreenPrePaintData& data, int time ); + virtual void prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time ); + virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); + virtual void postPaintWindow( EffectWindow* w ); + // TODO react also on virtual desktop changes + virtual void windowAdded( EffectWindow* c ); + virtual void windowClosed( EffectWindow* c ); + virtual void windowDeleted( EffectWindow* c ); + virtual void propertyNotify( EffectWindow* w, long a ); + private: + enum Position + { + West = 0, + North = 1, + East = 2, + South = 3 + }; + struct Data + { + int start; //point in screen coordinates where the window starts + //to animate, from decides if this point is an x or an y + Position from; + }; + long mAtom; + QHash< const EffectWindow*, TimeLine > mAppearingWindows; + QHash< const EffectWindow*, TimeLine > mDisappearingWindows; + QHash< const EffectWindow*, Data > mWindowsData; + }; + +} // namespace + +#endif