Integrate DesktopChangeSlide into DesktopGrid, so that

they can co-exist without conflicting.


svn path=/branches/work/kwin_composite/; revision=654687
This commit is contained in:
Luboš Luňák 2007-04-16 19:30:48 +00:00
parent 40002ec325
commit 09b5b47b1e
5 changed files with 188 additions and 270 deletions

View file

@ -1,218 +0,0 @@
/*****************************************************************
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.
******************************************************************/
#include "desktopchangeslide.h"
namespace KWin
{
KWIN_EFFECT( DesktopChangeSlide, DesktopChangeSlideEffect )
const int MAX_PROGRESS = 500; // ms
DesktopChangeSlideEffect::DesktopChangeSlideEffect()
: progress( MAX_PROGRESS )
{
}
void DesktopChangeSlideEffect::prePaintScreen( int* mask, QRegion* region, int time )
{
progress = qBound( 0, progress + time, MAX_PROGRESS );
// PAINT_SCREEN_BACKGROUND_FIRST is needed because screen will be actually painted more than once,
// so with normal screen painting second screen paint would erase parts of the first paint
if( progress != MAX_PROGRESS )
*mask |= PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST;
effects->prePaintScreen( mask, region, time );
}
void DesktopChangeSlideEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time )
{
if( progress != MAX_PROGRESS )
{
if( w->isOnAllDesktops())
{
if( painting_sticky )
*mask |= PAINT_WINDOW_TRANSFORMED;
else
w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
}
else if( w->isOnDesktop( painting_desktop ))
w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
else
w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
}
effects->prePaintWindow( w, mask, paint, clip, time );
}
void DesktopChangeSlideEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
{
if( progress == MAX_PROGRESS )
{
effects->paintScreen( mask, region, data );
return;
}
/*
Transformations are done by remembering starting position of the change and the progress
of it, the destination is computed from the current desktop. Positions of desktops
are done using their topleft corner.
*/
QPoint destPos = desktopPos( effects->currentDesktop());
QPoint diffPos = destPos - startPos;
int w = 0;
int h = 0;
if( effects->optionRollOverDesktops())
{
int x, y;
Qt::Orientation orientation;
effects->calcDesktopLayout( &x, &y, &orientation );
w = x * displayWidth();
h = y * displayHeight();
// wrap around if shorter
if( diffPos.x() > 0 && diffPos.x() > w / 2 )
diffPos.setX( diffPos.x() - w );
if( diffPos.x() < 0 && abs( diffPos.x()) > w / 2 )
diffPos.setX( diffPos.x() + w );
if( diffPos.y() > 0 && diffPos.y() > h / 2 )
diffPos.setY( diffPos.y() - h );
if( diffPos.y() < 0 && abs( diffPos.y()) > h / 2 )
diffPos.setY( diffPos.y() + h );
}
QPoint currentPos = startPos + progress * diffPos / MAX_PROGRESS;
QSize displaySize( displayWidth(), displayHeight());
QRegion currentRegion = QRect( currentPos, displaySize );
if( effects->optionRollOverDesktops())
{
currentRegion |= ( currentRegion & QRect( -w, 0, w, h )).translated( w, 0 );
currentRegion |= ( currentRegion & QRect( 0, -h, w, h )).translated( 0, h );
currentRegion |= ( currentRegion & QRect( w, 0, w, h )).translated( -w, 0 );
currentRegion |= ( currentRegion & QRect( 0, h, w, h )).translated( 0, -h );
}
bool do_sticky = true;
for( int desktop = 1;
desktop <= effects->numberOfDesktops();
++desktop )
{
QRect desktopRect( desktopPos( desktop ), displaySize );
if( currentRegion.contains( desktopRect )) // part of the desktop needs painting
{
painting_desktop = desktop;
painting_sticky = do_sticky;
painting_diff = desktopRect.topLeft() - currentPos;
if( effects->optionRollOverDesktops())
{
if( painting_diff.x() > displayWidth())
painting_diff.setX( painting_diff.x() - w );
if( painting_diff.x() < -displayWidth())
painting_diff.setX( painting_diff.x() + w );
if( painting_diff.y() > displayHeight())
painting_diff.setY( painting_diff.y() - h );
if( painting_diff.y() < -displayHeight())
painting_diff.setY( painting_diff.y() + h );
}
do_sticky = false; // paint on-all-desktop windows only once
ScreenPaintData d = data;
d.xTranslate += painting_diff.x();
d.yTranslate += painting_diff.y();
// TODO mask parts that are not visible?
effects->paintScreen( mask, region, d );
}
}
}
void DesktopChangeSlideEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{
if( progress != MAX_PROGRESS )
{ // don't move windows on all desktops (compensate screen transformation)
if( w->isOnAllDesktops()) // TODO also fix 'Workspace::movingClient'
{
data.xTranslate -= painting_diff.x();
data.yTranslate -= painting_diff.y();
}
}
effects->paintWindow( w, mask, region, data );
}
void DesktopChangeSlideEffect::postPaintScreen()
{
if( progress != MAX_PROGRESS )
effects->addRepaintFull(); // trigger next animation repaint
effects->postPaintScreen();
}
// Gives a position of the given desktop when all desktops are arranged in a grid
QPoint DesktopChangeSlideEffect::desktopPos( int desktop )
{
int x, y;
Qt::Orientation orientation;
effects->calcDesktopLayout( &x, &y, &orientation );
--desktop; // make it start with 0
if( orientation == Qt::Vertical )
return QPoint(( desktop % x ) * displayWidth(), ( desktop / x ) * displayHeight());
else
return QPoint(( desktop / y ) * displayWidth(), ( desktop % y ) * displayHeight());
}
void DesktopChangeSlideEffect::desktopChanged( int old )
{
if( progress != MAX_PROGRESS ) // old slide still in progress
{
QPoint diffPos = desktopPos( old ) - startPos;
int w = 0;
int h = 0;
if( effects->optionRollOverDesktops())
{
int x, y;
Qt::Orientation orientation;
effects->calcDesktopLayout( &x, &y, &orientation );
w = x * displayWidth();
h = y * displayHeight();
// wrap around if shorter
if( diffPos.x() > 0 && diffPos.x() > w / 2 )
diffPos.setX( diffPos.x() - w );
if( diffPos.x() < 0 && abs( diffPos.x()) > w / 2 )
diffPos.setX( diffPos.x() + w );
if( diffPos.y() > 0 && diffPos.y() > h / 2 )
diffPos.setY( diffPos.y() - h );
if( diffPos.y() < 0 && abs( diffPos.y()) > h / 2 )
diffPos.setY( diffPos.y() + h );
}
QPoint currentPos = startPos + progress * diffPos / MAX_PROGRESS;
QRegion currentRegion = QRect( currentPos, QSize( displayWidth(), displayHeight()));
if( effects->optionRollOverDesktops())
{
currentRegion |= ( currentRegion & QRect( -w, 0, w, h )).translated( w, 0 );
currentRegion |= ( currentRegion & QRect( 0, -h, w, h )).translated( 0, h );
currentRegion |= ( currentRegion & QRect( w, 0, w, h )).translated( -w, 0 );
currentRegion |= ( currentRegion & QRect( 0, h, w, h )).translated( 0, -h );
}
QRect desktopRect( desktopPos( effects->currentDesktop()), QSize( displayWidth(), displayHeight()));
if( currentRegion.contains( desktopRect ))
{ // current position is in new current desktop (e.g. quickly changing back),
// don't do full progress
if( abs( currentPos.x() - desktopRect.x()) > abs( currentPos.y() - desktopRect.y()))
progress = MAX_PROGRESS - MAX_PROGRESS * abs( currentPos.x() - desktopRect.x()) / displayWidth();
else
progress = MAX_PROGRESS - MAX_PROGRESS * abs( currentPos.y() - desktopRect.y()) / displayHeight();
}
else // current position is not on current desktop, do full progress
progress = 0;
diffPos = desktopRect.topLeft() - currentPos;
// Compute starting point for this new move (given current and end positions)
startPos = desktopRect.topLeft() - diffPos * MAX_PROGRESS / ( MAX_PROGRESS - progress );
}
else
{
progress = 0;
startPos = desktopPos( old );
}
effects->addRepaintFull();
}
} // namespace

View file

@ -1,4 +0,0 @@
[Desktop Entry]
Encoding=UTF-8
Name=DesktopChangeSlide
X-KDE-Library=kwin4_effect_builtins

View file

@ -1,41 +0,0 @@
/*****************************************************************
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.
******************************************************************/
#ifndef KWIN_DESKTOPCHANGESLIDE_H
#define KWIN_DESKTOPCHANGESLIDE_H
#include <kwineffects.h>
namespace KWin
{
class DesktopChangeSlideEffect
: public Effect
{
public:
DesktopChangeSlideEffect();
virtual void prePaintScreen( int* mask, QRegion* region, int time );
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
virtual void postPaintScreen();
virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time );
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
virtual void desktopChanged( int old );
private:
QPoint desktopPos( int desktop );
QPoint startPos;
int progress;
int painting_desktop;
bool painting_sticky;
QPoint painting_diff;
};
} // namespace
#endif

View file

@ -20,10 +20,13 @@ namespace KWin
KWIN_EFFECT( DesktopGrid, DesktopGridEffect ) KWIN_EFFECT( DesktopGrid, DesktopGridEffect )
const int PROGRESS_TIME = 500; // ms
DesktopGridEffect::DesktopGridEffect() DesktopGridEffect::DesktopGridEffect()
: progress( 0 ) : progress( 0 )
, activated( false ) , activated( false )
, keyboard_grab( false ) , keyboard_grab( false )
, slide( false )
{ {
KActionCollection* actionCollection = new KActionCollection( this ); KActionCollection* actionCollection = new KActionCollection( this );
KAction* a = static_cast< KAction* >( actionCollection->addAction( "ShowDesktopGrid" )); KAction* a = static_cast< KAction* >( actionCollection->addAction( "ShowDesktopGrid" ));
@ -34,12 +37,25 @@ DesktopGridEffect::DesktopGridEffect()
void DesktopGridEffect::prePaintScreen( int* mask, QRegion* region, int time ) void DesktopGridEffect::prePaintScreen( int* mask, QRegion* region, int time )
{ {
if( progress != 0 || activated ) if( slide )
{
progress = qMin( 1.0, progress + time / double( PROGRESS_TIME ));
// PAINT_SCREEN_BACKGROUND_FIRST is needed because screen will be actually painted more than once,
// so with normal screen painting second screen paint would erase parts of the first paint
if( progress != 1 )
*mask |= PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST;
else
{
slide = false;
progress = 0;
}
}
else if( progress != 0 || activated )
{ {
if( activated ) if( activated )
progress = qMin( 1.0, progress + time / 500. ); progress = qMin( 1.0, progress + time / double( PROGRESS_TIME ));
else else
progress = qMax( 0.0, progress - time / 500. ); progress = qMax( 0.0, progress - time / double( PROGRESS_TIME ));
// PAINT_SCREEN_BACKGROUND_FIRST is needed because screen will be actually painted more than once, // PAINT_SCREEN_BACKGROUND_FIRST is needed because screen will be actually painted more than once,
// so with normal screen painting second screen paint would erase parts of the first paint // so with normal screen painting second screen paint would erase parts of the first paint
if( progress != 0 ) if( progress != 0 )
@ -59,7 +75,21 @@ void DesktopGridEffect::prePaintScreen( int* mask, QRegion* region, int time )
void DesktopGridEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) void DesktopGridEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time )
{ {
if( progress != 0 ) if( slide )
{
if( w->isOnAllDesktops())
{
if( slide_painting_sticky )
*mask |= PAINT_WINDOW_TRANSFORMED;
else
w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
}
else if( w->isOnDesktop( painting_desktop ))
w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
else
w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
}
else if( progress != 0 )
{ {
if( w->isOnDesktop( painting_desktop )) if( w->isOnDesktop( painting_desktop ))
w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
@ -76,6 +106,11 @@ void DesktopGridEffect::paintScreen( int mask, QRegion region, ScreenPaintData&
effects->paintScreen( mask, region, data ); effects->paintScreen( mask, region, data );
return; return;
} }
if( slide )
{
paintSlide( mask, region, data );
return;
}
for( int desktop = 1; for( int desktop = 1;
desktop <= effects->numberOfDesktops(); desktop <= effects->numberOfDesktops();
++desktop ) ++desktop )
@ -96,9 +131,87 @@ void DesktopGridEffect::paintScreen( int mask, QRegion region, ScreenPaintData&
} }
} }
void DesktopGridEffect::paintSlide( int mask, QRegion region, const ScreenPaintData& data )
{
/*
Transformations are done by remembering starting position of the change and the progress
of it, the destination is computed from the current desktop. Positions of desktops
are done using their topleft corner.
*/
QPoint destPos = desktopRect( effects->currentDesktop(), false ).topLeft();
QPoint diffPos = destPos - slide_start_pos;
int w = 0;
int h = 0;
if( effects->optionRollOverDesktops())
{
int x, y;
Qt::Orientation orientation;
effects->calcDesktopLayout( &x, &y, &orientation );
w = x * displayWidth();
h = y * displayHeight();
// wrap around if shorter
if( diffPos.x() > 0 && diffPos.x() > w / 2 )
diffPos.setX( diffPos.x() - w );
if( diffPos.x() < 0 && abs( diffPos.x()) > w / 2 )
diffPos.setX( diffPos.x() + w );
if( diffPos.y() > 0 && diffPos.y() > h / 2 )
diffPos.setY( diffPos.y() - h );
if( diffPos.y() < 0 && abs( diffPos.y()) > h / 2 )
diffPos.setY( diffPos.y() + h );
}
QPoint currentPos = slide_start_pos + progress * diffPos;
QSize displaySize( displayWidth(), displayHeight());
QRegion currentRegion = QRect( currentPos, displaySize );
if( effects->optionRollOverDesktops())
{
currentRegion |= ( currentRegion & QRect( -w, 0, w, h )).translated( w, 0 );
currentRegion |= ( currentRegion & QRect( 0, -h, w, h )).translated( 0, h );
currentRegion |= ( currentRegion & QRect( w, 0, w, h )).translated( -w, 0 );
currentRegion |= ( currentRegion & QRect( 0, h, w, h )).translated( 0, -h );
}
bool do_sticky = true;
for( int desktop = 1;
desktop <= effects->numberOfDesktops();
++desktop )
{
QRect rect = desktopRect( desktop, false );
if( currentRegion.contains( rect )) // part of the desktop needs painting
{
painting_desktop = desktop;
slide_painting_sticky = do_sticky;
slide_painting_diff = rect.topLeft() - currentPos;
if( effects->optionRollOverDesktops())
{
if( slide_painting_diff.x() > displayWidth())
slide_painting_diff.setX( slide_painting_diff.x() - w );
if( slide_painting_diff.x() < -displayWidth())
slide_painting_diff.setX( slide_painting_diff.x() + w );
if( slide_painting_diff.y() > displayHeight())
slide_painting_diff.setY( slide_painting_diff.y() - h );
if( slide_painting_diff.y() < -displayHeight())
slide_painting_diff.setY( slide_painting_diff.y() + h );
}
do_sticky = false; // paint on-all-desktop windows only once
ScreenPaintData d = data;
d.xTranslate += slide_painting_diff.x();
d.yTranslate += slide_painting_diff.y();
// TODO mask parts that are not visible?
effects->paintScreen( mask, region, d );
}
}
}
void DesktopGridEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) void DesktopGridEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{ {
if( progress != 0 ) if( slide )
{ // don't move windows on all desktops (compensate screen transformation)
if( w->isOnAllDesktops()) // TODO also fix 'Workspace::movingClient'
{
data.xTranslate -= slide_painting_diff.x();
data.yTranslate -= slide_painting_diff.y();
}
}
else if( progress != 0 )
{ {
if( painting_desktop != hover_desktop ) if( painting_desktop != hover_desktop )
data.brightness *= 0.7; data.brightness *= 0.7;
@ -108,6 +221,8 @@ void DesktopGridEffect::paintWindow( EffectWindow* w, int mask, QRegion region,
void DesktopGridEffect::postPaintScreen() void DesktopGridEffect::postPaintScreen()
{ {
if( slide )
effects->addRepaintFull();
if( activated ? progress != 1 : progress != 0 ) if( activated ? progress != 1 : progress != 0 )
effects->addRepaintFull(); // trigger next animation repaint effects->addRepaintFull(); // trigger next animation repaint
effects->postPaintScreen(); effects->postPaintScreen();
@ -149,9 +264,69 @@ int DesktopGridEffect::posToDesktop( const QPoint& pos ) const
return 0; return 0;
} }
void DesktopGridEffect::desktopChanged( int ) void DesktopGridEffect::desktopChanged( int old )
{ {
setActive( false ); if( activated )
setActive( false );
else
slideDesktopChanged( old );
}
void DesktopGridEffect::slideDesktopChanged( int old )
{
if( slide ) // old slide still in progress
{
QPoint diffPos = desktopRect( old, false ).topLeft() - slide_start_pos;
int w = 0;
int h = 0;
if( effects->optionRollOverDesktops())
{
int x, y;
Qt::Orientation orientation;
effects->calcDesktopLayout( &x, &y, &orientation );
w = x * displayWidth();
h = y * displayHeight();
// wrap around if shorter
if( diffPos.x() > 0 && diffPos.x() > w / 2 )
diffPos.setX( diffPos.x() - w );
if( diffPos.x() < 0 && abs( diffPos.x()) > w / 2 )
diffPos.setX( diffPos.x() + w );
if( diffPos.y() > 0 && diffPos.y() > h / 2 )
diffPos.setY( diffPos.y() - h );
if( diffPos.y() < 0 && abs( diffPos.y()) > h / 2 )
diffPos.setY( diffPos.y() + h );
}
QPoint currentPos = slide_start_pos + progress * diffPos;
QRegion currentRegion = QRect( currentPos, QSize( displayWidth(), displayHeight()));
if( effects->optionRollOverDesktops())
{
currentRegion |= ( currentRegion & QRect( -w, 0, w, h )).translated( w, 0 );
currentRegion |= ( currentRegion & QRect( 0, -h, w, h )).translated( 0, h );
currentRegion |= ( currentRegion & QRect( w, 0, w, h )).translated( -w, 0 );
currentRegion |= ( currentRegion & QRect( 0, h, w, h )).translated( 0, -h );
}
QRect rect = desktopRect( effects->currentDesktop(), false );
if( currentRegion.contains( rect ))
{ // current position is in new current desktop (e.g. quickly changing back),
// don't do full progress
if( abs( currentPos.x() - rect.x()) > abs( currentPos.y() - rect.y()))
progress = 1 - abs( currentPos.x() - rect.x()) / float( displayWidth());
else
progress = 1 - abs( currentPos.y() - rect.y()) / float( displayHeight());
}
else // current position is not on current desktop, do full progress
progress = 0;
diffPos = rect.topLeft() - currentPos;
// Compute starting point for this new move (given current and end positions)
slide_start_pos = rect.topLeft() - diffPos * 1 / ( 1 - progress );
}
else
{
progress = 0;
slide_start_pos = desktopRect( old, false ).topLeft();
slide = true;
}
effects->addRepaintFull();
} }
void DesktopGridEffect::toggle() void DesktopGridEffect::toggle()

View file

@ -39,12 +39,18 @@ class DesktopGridEffect
void setActive( bool active ); void setActive( bool active );
void setup(); void setup();
void finish(); void finish();
void paintSlide( int mask, QRegion region, const ScreenPaintData& data );
void slideDesktopChanged( int old );
float progress; float progress;
bool activated; bool activated;
int painting_desktop; int painting_desktop;
int hover_desktop; int hover_desktop;
Window input; Window input;
bool keyboard_grab; bool keyboard_grab;
bool slide;
QPoint slide_start_pos;
bool slide_painting_sticky;
QPoint slide_painting_diff;
}; };
} // namespace } // namespace