diff --git a/CMakeLists.txt b/CMakeLists.txt index ad074b4aa4..1f3f29ae82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,7 @@ set(kwin_KDEINIT_SRCS effects/scalein.cpp effects/shakymove.cpp effects/shiftworkspaceup.cpp + effects/howto.cpp ) kde4_automoc(kwin ${kwin_KDEINIT_SRCS}) diff --git a/activation.cpp b/activation.cpp index 7ef1558078..f7cb36367f 100644 --- a/activation.cpp +++ b/activation.cpp @@ -29,6 +29,7 @@ License. See the file "COPYING" for the exact licensing terms. #include "atoms.h" #include "group.h" #include "rules.h" +#include "effects.h" #include namespace KWinInternal @@ -245,6 +246,8 @@ void Workspace::setActiveClient( Client* c, allowed_t ) rootInfo->setActiveWindow( active_client? active_client->window() : 0 ); updateColormap(); + if( effects ) + effects->windowActivated( active_client ); --set_active_client_recursion; } @@ -697,7 +700,7 @@ void Client::demandAttentionKNotify() } // TODO I probably shouldn't be lazy here and do it without the macro, so that people can read it -KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, const Client*, +KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, Client, const Client*, // ignore already existing splashes, toolbars, utilities, menus and topmenus, // as the app may show those before the main window !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu() diff --git a/effects.cpp b/effects.cpp index feb1440f3a..43d6e1f918 100644 --- a/effects.cpp +++ b/effects.cpp @@ -15,6 +15,7 @@ License. See the file "COPYING" for the exact licensing terms. #include "scene.h" #include "effects/fadein.h" +#include "effects/howto.h" #include "effects/maketransparent.h" #include "effects/scalein.h" #include "effects/shakymove.h" @@ -43,6 +44,10 @@ void Effect::windowDeleted( Toplevel* ) { } +void Effect::windowActivated( Toplevel* ) + { + } + void Effect::prePaintScreen( int* mask, QRegion* region, int time ) { effects->prePaintScreen( mask, region, time ); @@ -83,6 +88,7 @@ EffectsHandler::EffectsHandler( Workspace* ws ) { if( !compositing()) return; + effects.append( new HowtoEffect ); // effects.append( new MakeTransparentEffect ); // effects.append( new ShakyMoveEffect ); // effects.append( new ShiftWorkspaceUpEffect( ws )); @@ -114,6 +120,12 @@ void EffectsHandler::windowDeleted( Toplevel* c ) e->windowDeleted( c ); } +void EffectsHandler::windowActivated( Toplevel* c ) + { + foreach( Effect* e, effects ) + e->windowActivated( c ); + } + // start another painting pass void EffectsHandler::startPaint() { diff --git a/effects.h b/effects.h index fafe1ca714..7372a0e073 100644 --- a/effects.h +++ b/effects.h @@ -54,6 +54,7 @@ class Effect virtual void windowUserMovedResized( Toplevel* c, bool first, bool last ); virtual void windowAdded( Toplevel* c ); virtual void windowDeleted( Toplevel* c ); + virtual void windowActivated( Toplevel* c ); }; class EffectsHandler @@ -73,6 +74,7 @@ class EffectsHandler void windowUserMovedResized( Toplevel* c, bool first, bool last ); void windowAdded( Toplevel* c ); void windowDeleted( Toplevel* c ); + void windowActivated( Toplevel* c ); private: QVector< Effect* > effects; int current_paint_window; diff --git a/effects/howto.cpp b/effects/howto.cpp new file mode 100644 index 0000000000..ffa61ba4ee --- /dev/null +++ b/effects/howto.cpp @@ -0,0 +1,150 @@ +/***************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2006 Lubos Lunak + +You can Freely distribute this program under the GNU General Public +License. See the file "COPYING" for the exact licensing terms. +******************************************************************/ + +/* + + Files howto.cpp and howto.h implement HowtoEffect, a commented demo compositing + effect that fades out and again in a window after it has been activated. + + Please see file howto.h first. + +*/ + +// Include the class definition. +#include "howto.h" + + +// Note that currently effects need to be manually enabled in the EffectsHandler +// class constructor (in effects.cpp). + +namespace KWinInternal +{ + +// A pre-paint function that tells the compositing code how this effect will affect +// the painting. During every painting pass this function is called first, before +// the actual painting function. +// Arguments: +// w - the window that will be painted +// mask - a mask of flags controlling the painting, setting or resetting flags changes +// how the painting will be done +// region - the region of the screen that needs to be painted, support for modifying it +// is not fully implemented yet, do not use +// time - time in milliseconds since the last paint, useful for animations +void HowtoEffect::prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time ) + { + // Is this window the one that is going to be faded out and in again? + // Note that since the effects framework is still work in progress, the window() + // function is used to access internal class Toplevel. The plan is to hide away + // internal classes and have only API for effects. + if( w->window() == fade_window ) + { + // Simply add the time to the total progress. The value of progress will be used + // to determine how far in effect is. + progress += time; + // If progress is < 1000 (milliseconds), the effect is still in progress. + if( progress < 1000 ) // complete change in 1000ms + { + // Since the effect will make the window translucent, explicitly change + // the flags so that the window will be painted only as translucent. + *mask |= Scene::PAINT_WINDOW_TRANSLUCENT; + *mask &= ~Scene::PAINT_WINDOW_OPAQUE; + } + else + { + // If progress has reached 1000 (milliseconds), it means the effect is done + // and there is no window to fade anymore. + fade_window = NULL; + } + } + // Call the next effect (or the actual window painting code if this is the last effect). + // Effects are chained and they all modify something if needed and then call the next one. + effects->prePaintWindow( w, mask, region, time ); + } + +// The function that handles the actual painting. Some simple modifications are possible +// by only changing the painting data. More complicated effects would do some painting +// or transformations directly. +// Arguments: +// w - the window that will be painted +// mask - a mask of flags controlling the painting +// region - the region of the screen that needs to be painted, if mask includes the TRANSFORMED +// flag, region is infiniteRegion(), meaning that everything needs to be painted +// data - painting data that can be modified to do some simple transformations +void HowtoEffect::paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data ) + { + // Is this the window to be faded out and in again? + if( w->window() == fade_window ) + { + // This effect, after a window has been activated, fades it out to only 50% transparency + // and then fades it in again to be fully opaque (assuming it's otherwise a fully opaque + // window, otherwise the transparencies will be added). + if( progress <= 500 ) + { + // For the first 500 milliseconds (progress being 0 to 500), the window is faded out. + // progress == 0 -> opacity *= 1 + // progress == 500 -> opacity *= 0.5 + // Note that the division is floating-point division to avoid integer rounding down. + // Note that data.opacity is not set but multiplied - this allows chaining of effects, + // for example if another effect always changes opacity of some window types. + data.opacity *= 1 - 0.5 * ( progress / 500.0 ); + } + else + { + // For the second 500 milliseconds (progress being 500 to 1000), the window is + // faded in again. + // progress == 500 -> opacity *= 0.5 + // progress == 1000 -> opacity *= 1 + data.opacity *= 0.5 + 0.5 * ( progress - 500 ) / 500.0; + } + } + // Call the next effect. + effects->paintWindow( w, mask, region, data ); + } + +// The function that is called after the painting pass is finished. When an animation is going on, +// it can damage some areas so that the next painting pass has to repaint them again. +void HowtoEffect::postPaintWindow( Scene::Window* w ) + { + // Is this the window to be faded out and in again? + if( w->window() == fade_window ) + { + // Damage the whole window, this will cause it to be repainted the next painting pass. + w->window()->addDamageFull(); // trigger next animation repaint + } + // Call the next effect. + effects->postPaintWindow( w ); + } + +// This function is called when a new window becomes active. +void HowtoEffect::windowActivated( Toplevel* c ) + { + // Set the window to be faded (or NULL if no window is active). + fade_window = c; + if( fade_window != NULL ) + { + // If there is a window to be faded, reset the progress to zero. + progress = 0; + // And damage the window so that it needs to be repainted. + c->addDamageFull(); + } + } + +// This function is called when a window is destroyed. +void HowtoEffect::windowDeleted( Toplevel* c ) + { + // If the window to be faded out and in is destroyed, just reset the pointer. + // This effect then will do nothing and just call the next effect. + if( fade_window == c ) + fade_window = NULL; + } + +// That's all. Don't forget to enable the effect as described at the beginning of this file. + +} // namespace diff --git a/effects/howto.h b/effects/howto.h new file mode 100644 index 0000000000..1e54b23c0a --- /dev/null +++ b/effects/howto.h @@ -0,0 +1,69 @@ +/***************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2006 Lubos Lunak + +You can Freely distribute this program under the GNU General Public +License. See the file "COPYING" for the exact licensing terms. +******************************************************************/ + +/* + + Files howto.cpp and howto.h implement HowtoEffect, a commented demo compositing + effect that fades out and again in a window after it has been activated. + +*/ + +#ifndef KWIN_HOWTO_H +#define KWIN_HOWTO_H + +// Include with base class for effects. +#include + +// Everything in KWin is in a namespace. There's no need to prefix names +// with KWin or K, there's no (big) need to care about symbol clashes. +namespace KWinInternal +{ + +// The class implementing the effect. +class HowtoEffect +// Inherit from the base class for effects. + : public Effect + { + public: + // There are two kinds of functions in an effect: + + // Functions related to painting: These allow the effect to affect painting. + + // A pre-paint function. It tells the compositing code how the painting will + // be affected by this effect. + virtual void prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time ); + + // A paint function. It actually performs the modifications to the painting. + virtual void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data ); + + // A post-paint function. It can be used for cleanups after painting, but with animations + // it is also used to trigger repaints during the next painting pass by manually "damaging" + // areas of the window. + virtual void postPaintWindow( Scene::Window* w ); + + // Notification functions: These inform the effect about changes such as a new window + // being activated. + + // The given window has been deleted (destroyed). + virtual void windowDeleted( Toplevel* c ); + + // The given window has been activated. + virtual void windowActivated( Toplevel* c ); + private: + // The window that will be faded out and in again. + Toplevel* fade_window; + + // The progress of the fading. + int progress; + }; + +} // namespace + +#endif