From d6a5f717f2f85d57a8b5c3e6d702a49e71b1b070 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 15 Apr 2009 19:31:20 +0000 Subject: [PATCH] Add new SlideBack effect svn path=/trunk/KDE/kdebase/workspace/; revision=954446 --- effects/CMakeLists.txt | 1 + effects/slideback/CMakeLists.txt | 12 ++ effects/slideback/slideback.cpp | 311 ++++++++++++++++++++++++++++ effects/slideback/slideback.desktop | 17 ++ effects/slideback/slideback.h | 72 +++++++ 5 files changed, 413 insertions(+) create mode 100644 effects/slideback/CMakeLists.txt create mode 100644 effects/slideback/slideback.cpp create mode 100644 effects/slideback/slideback.desktop create mode 100644 effects/slideback/slideback.h diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt index 7a9bef0dba..87469df650 100644 --- a/effects/CMakeLists.txt +++ b/effects/CMakeLists.txt @@ -69,6 +69,7 @@ include( shadow/CMakeLists.txt ) include( showfps/CMakeLists.txt ) include( showpaint/CMakeLists.txt ) include( slide/CMakeLists.txt ) +include( slideback/CMakeLists.txt ) include( taskbarthumbnail/CMakeLists.txt ) include( thumbnailaside/CMakeLists.txt ) include( zoom/CMakeLists.txt ) diff --git a/effects/slideback/CMakeLists.txt b/effects/slideback/CMakeLists.txt new file mode 100644 index 0000000000..f95f9d6915 --- /dev/null +++ b/effects/slideback/CMakeLists.txt @@ -0,0 +1,12 @@ +####################################### +# Effect + +# Source files +set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources} + slideback/slideback.cpp + ) + +# .desktop files +install( FILES + slideback/slideback.desktop + DESTINATION ${SERVICES_INSTALL_DIR}/kwin ) diff --git a/effects/slideback/slideback.cpp b/effects/slideback/slideback.cpp new file mode 100644 index 0000000000..cd5f7f36ab --- /dev/null +++ b/effects/slideback/slideback.cpp @@ -0,0 +1,311 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2009 Michael Zanetti + +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 "slideback.h" + +#include +#include + +namespace KWin +{ + +KWIN_EFFECT( slideback, SlideBackEffect ) + +SlideBackEffect::SlideBackEffect() + { + // updateStackingOrder(); + } + +void SlideBackEffect::windowActivated( EffectWindow* w ) + { + if( w == NULL ) + { + return; + } + + if( disabled || effects->activeFullScreenEffect() ) // TabBox or PresentWindows/Cube in progress + { + updateStackingOrder(); + disabled = false; + return; + } + + if( !isWindowUsable( w ) || !isWindowOnTop( w ) ) // Focus changed but stacking still the same + { + updateStackingOrder(); + return; + } + // Determine all windows on top of the activated one + bool currentFound = false; + foreach( EffectWindow *tmp, oldStackingOrder ) + { + if( !currentFound ) + { + if( tmp == w ) + { + currentFound = true; + } + } + else + { + if( isWindowUsable( tmp ) && tmp->isOnDesktop( w->desktop() ) ) + { + // Do we have to move it? + if( tmp->geometry().intersects( w->geometry() ) ) + { + effects->setElevatedWindow( tmp, true ); + elevatedList.append( tmp ); + + // Determine the shortest way: + int leftSlide = w->geometry().left() - tmp->geometry().right() - 20; + int rightSlide = w->geometry().right() - tmp->geometry().left() + 20; + int upSlide = w->geometry().top() - tmp->geometry().bottom() - 20; + int downSlide = w->geometry().bottom() - tmp->geometry().top() + 20; + + int horizSlide = leftSlide; + if( abs( horizSlide ) > abs( rightSlide ) ) + { + horizSlide = rightSlide; + } + int vertSlide = upSlide; + if( abs( vertSlide ) > abs( downSlide ) ) + { + vertSlide = downSlide; + } + + QRect slideRect = tmp->geometry(); + if( abs( horizSlide ) < abs( vertSlide ) ) + { + slideRect.moveLeft( slideRect.x() + horizSlide ); + } + else + { + slideRect.moveTop( slideRect.y() + vertSlide ); + } + + motionManager.manage( tmp ); + motionManager.moveWindow( tmp, slideRect ); + destinationList.insert( tmp, slideRect ); + coveringWindows.append( tmp ); + } + else + { + //Does it intersect with a moved (elevated) window and do we have to elevate it too? + foreach( EffectWindow *elevatedWindow, elevatedList ) + { + if( tmp->geometry().intersects( elevatedWindow->geometry() ) ) + { + effects->setElevatedWindow( tmp, true ); + elevatedList.append( tmp ); + break; + } + } + + } + } + if( tmp->isDock() ) + { + effects->setElevatedWindow( tmp, true ); + elevatedList.append( tmp ); + } + } + } + // If a window is minimized it could happen that the panels stay elevated without any windows sliding. + // clear all elevation settings + if( !motionManager.managingWindows() ) + { + foreach( EffectWindow* tmp, elevatedList ) + { + effects->setElevatedWindow( tmp, false ); + } + } + updateStackingOrder(); + } + +void SlideBackEffect::updateStackingOrder() + { + usableOldStackingOrder = usableWindows( effects->stackingOrder() ); + oldStackingOrder = effects->stackingOrder(); + } + +void SlideBackEffect::prePaintScreen( ScreenPrePaintData &data, int time ) + { + if( motionManager.managingWindows() ) + { + motionManager.calculate( time ); + data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; + } + effects->prePaintScreen( data, time ); + } + +void SlideBackEffect::postPaintScreen() + { + if( motionManager.areWindowsMoving() ) + { + effects->addRepaintFull(); + } + effects->postPaintScreen(); + } + +void SlideBackEffect::prePaintWindow( EffectWindow *w, WindowPrePaintData &data, int time ) + { + if( motionManager.areWindowsMoving() ) + { + if( motionManager.isManaging( w ) ) + { + data.setTransformed(); + } + } + + effects->prePaintWindow( w, data, time ); + } + +void SlideBackEffect::paintWindow( EffectWindow *w, int mask, QRegion region, WindowPaintData &data ) + { + if( !motionManager.managingWindows() && stackingOrderChanged() && ( w == newTopWindow() ) ) + { + /* This can happen because of two reasons: + - a window has received the focus earlier without beeing raised and is raised now. -> call windowActivated() now + - paintWindow() is called with a new stackingOrder before activateWindow(). Bug? -> don't draw the overlapping content;*/ + foreach( EffectWindow *tmp, oldStackingOrder ) + { + if( oldStackingOrder.lastIndexOf( tmp ) > oldStackingOrder.lastIndexOf( w ) && isWindowUsable( tmp ) ) + { + region = region.subtracted( tmp->geometry() ); + } + } + // Add a full repaint to make sure the not painted area is repainted soon + effects->addRepaintFull(); + // Finally call windowActivated in case a already active window is raised. + if( !disabled ) + { + windowActivated( w ); + } + } + if( motionManager.areWindowsMoving() ) + { + if( motionManager.isManaging( w ) ) + { + motionManager.apply( w, data ); + } + } + effects->paintWindow( w, mask, region, data ); + } + +void SlideBackEffect::postPaintWindow( EffectWindow* w ) + { + if( motionManager.isManaging( w ) ) + { + if( destinationList.contains( w ) ) + { + // has window reched its destination? + if(( abs( motionManager.transformedGeometry( w ).x() - destinationList[w].x() ) < 1 ) && + ( abs( motionManager.transformedGeometry( w ).y() - destinationList[w].y() ) < 1 ) ) + { + // Move the window back where it belongs + motionManager.moveWindow( w, w->geometry() ); + destinationList.remove( w ); + } + } + else + { + // is window back at its original position? + if(( abs( motionManager.transformedGeometry( w ).x() - w->geometry().x() ) < 1 ) && + ( abs( motionManager.transformedGeometry( w ).y() - w->geometry().y() ) < 1 ) ) + { + motionManager.unmanage( w ); + } + } + if( coveringWindows.contains( w ) ) + { + // It could happen that there is no aciveWindow() here if the user clicks the close-button on an inactive window. + // Just skip... the window will be removed in windowDeleted() later + if( effects->activeWindow() && !motionManager.transformedGeometry( w ).intersects( effects->activeWindow()->geometry() ) ) + { + coveringWindows.removeAll( w ); + if( coveringWindows.isEmpty() ) + { + // Restore correct stacking order + foreach( EffectWindow *tmp, elevatedList ) + { + effects->setElevatedWindow( tmp, false ); + elevatedList.clear(); + } + } + } + } + } + effects->postPaintWindow( w ); + } + +void SlideBackEffect::windowDeleted( EffectWindow* w ) + { + usableOldStackingOrder.removeAll( w ); + oldStackingOrder.removeAll( w ); + coveringWindows.removeAll( w ); + elevatedList.removeAll( w ); + } + +void SlideBackEffect::windowAdded( KWin::EffectWindow* w ) + { + updateStackingOrder(); + } + + +void SlideBackEffect::tabBoxClosed() + { + disabled = true; + } + +bool SlideBackEffect::isWindowOnTop( EffectWindow* w ) + { + return usableWindows( effects->stackingOrder() ).last() == w ? true : false; + } + +bool SlideBackEffect::isWindowUsable( EffectWindow* w ) + { + return w && ( w->isNormalWindow() || w->isDialog() ) && !w->isDeleted() && !w->isMinimized(); + } + +EffectWindowList SlideBackEffect::usableWindows( const EffectWindowList & allWindows ) + { + EffectWindowList retList; + foreach( EffectWindow *tmp, allWindows ) + { + if( isWindowUsable( tmp ) ) + { + retList.append( tmp ); + } + } + return retList; + } + +bool SlideBackEffect::stackingOrderChanged() + { + return !( usableOldStackingOrder == usableWindows( effects->stackingOrder() ) ); + } + +EffectWindow* SlideBackEffect::newTopWindow() + { + EffectWindowList stacking = usableWindows( effects->stackingOrder() ); + return stacking.isEmpty() ? NULL : stacking.last(); + } + +} //Namespace diff --git a/effects/slideback/slideback.desktop b/effects/slideback/slideback.desktop new file mode 100644 index 0000000000..936ccc1c72 --- /dev/null +++ b/effects/slideback/slideback.desktop @@ -0,0 +1,17 @@ +[Desktop Entry] +Name=Slide Back + +Type=Service +Comment=Slide back windows losing focus +Icon=preferences-system-windows-effect-slideback +X-KDE-ServiceTypes=KWin/Effect +X-KDE-PluginInfo-Author=Michael Zanetti +X-KDE-PluginInfo-Email=michael_zanetti@gmx.net +X-KDE-PluginInfo-Name=kwin4_effect_slideback +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Category=Focus +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=false +X-KDE-Library=kwin4_effect_builtins +X-KDE-Ordering=50 diff --git a/effects/slideback/slideback.h b/effects/slideback/slideback.h new file mode 100644 index 0000000000..378053069b --- /dev/null +++ b/effects/slideback/slideback.h @@ -0,0 +1,72 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2009 Michael Zanetti + +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 SlideBackEffect + : public Effect + { + public: + SlideBackEffect(); + + virtual void windowActivated( EffectWindow* c ); + + 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 ); + + virtual void prePaintScreen( ScreenPrePaintData &data, int time ); + virtual void postPaintScreen(); + + virtual void windowDeleted( EffectWindow* w ); + virtual void windowAdded( EffectWindow* w ); + + virtual void tabBoxClosed(); + + private: + + WindowMotionManager motionManager; + EffectWindowList usableOldStackingOrder; + EffectWindowList oldStackingOrder; + EffectWindowList coveringWindows; + EffectWindowList elevatedList; + QHash destinationList; + bool disabled; + + void updateStackingOrder(); + bool isWindowOnTop( EffectWindow *w ); + bool isWindowUsable( EffectWindow *w ); + bool stackingOrderChanged(); + EffectWindowList usableWindows( const EffectWindowList &allWindows ); + EffectWindow *newTopWindow(); + + }; + +} // namespace + +#endif