/*****************************************************************
 KWin - the KDE window manager
 This file is part of the KDE project.

Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>

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"

namespace KWin
{

// This macro creates entry function for the plugin. First argument is name, second is class name.
KWIN_EFFECT( howto, HowtoEffect )

// 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( EffectWindow* w, WindowPrePaintData& data, int time )
    {
    // Is this window the one that is going to be faded out and in again?
    if( w == 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.
            // Use a helper that also takes care of changing the clipping rectangle.
            data.setTranslucent();
            }
        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, data, 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
//   then special care needs to be taken, because the region may be infiniteRegion(), meaning
//   everything needs to be painted
// data - painting data that can be modified to do some simple transformations
void HowtoEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
    {
    // Is this the window to be faded out and in again?
    if( w == 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 add repaints of some areas so that the next painting pass has to repaint them again.
void HowtoEffect::postPaintWindow( EffectWindow* w )
    {
    // Is this the window to be faded out and in again?
    if( w == fade_window )
        {
        // Trigger repaint of the whole window, this will cause it to be repainted the next painting pass.
        w->addRepaintFull(); // trigger next animation repaint
        }
    // Call the next effect.
    effects->postPaintWindow( w );
    }

// This function is called when a new window becomes active.
void HowtoEffect::windowActivated( EffectWindow* 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 add repaint to the window so that it needs to be repainted.
        c->addRepaintFull();
        }
    }

// This function is called when a window is closed.
void HowtoEffect::windowClosed( EffectWindow* c )
    {
    // If the window to be faded out and in is closed, 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. Now only the matching .desktop file is needed.


} // namespace
