From 8b5b40e4e8b2503828773149fcb5ef9db156466d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Sun, 25 Mar 2007 10:48:07 +0000 Subject: [PATCH] Shadows. Right not it's only flat black rectangle, but otherwise everything should work. svn path=/branches/work/kwin_composite/; revision=646315 --- CMakeLists.txt | 1 + COMPOSITE_TODO | 14 +++-- client.cpp | 8 +-- composite.cpp | 19 +++++- effects.cpp | 31 ++++++++-- effects.h | 11 +++- effects/boxswitch.cpp | 4 +- effects/boxswitch.h | 2 +- effects/desktopchangeslide.cpp | 4 +- effects/desktopchangeslide.h | 2 +- effects/dialogparent.cpp | 4 +- effects/dialogparent.h | 2 +- effects/drunken.cpp | 4 +- effects/drunken.h | 2 +- effects/explosioneffect.cpp | 4 +- effects/explosioneffect.h | 2 +- effects/fade.cpp | 4 +- effects/fade.h | 2 +- effects/fallapart.cpp | 4 +- effects/fallapart.h | 2 +- effects/flame.cpp | 4 +- effects/flame.h | 2 +- effects/howto.cpp | 4 +- effects/howto.h | 2 +- effects/maketransparent.cpp | 4 +- effects/maketransparent.h | 2 +- effects/minimizeanimation.cpp | 4 +- effects/minimizeanimation.h | 2 +- effects/presentwindows.cpp | 4 +- effects/presentwindows.h | 2 +- effects/scalein.cpp | 4 +- effects/scalein.h | 2 +- effects/shadow.cpp | 86 +++++++++++++++++++++++++++ effects/shadow.h | 35 +++++++++++ effects/shakymove.cpp | 4 +- effects/shakymove.h | 2 +- effects/wavywindows.cpp | 4 +- effects/wavywindows.h | 2 +- events.cpp | 2 +- geometry.cpp | 8 +-- scene.cpp | 43 ++++++++++---- scene.h | 6 ++ scene_opengl.cpp | 2 - scene_xrender.cpp | 32 ++++++---- toplevel.h | 3 + unmanaged.cpp | 2 +- workspace.h | 105 +++++++++++++++++++++++++-------- 47 files changed, 379 insertions(+), 119 deletions(-) create mode 100644 effects/shadow.cpp create mode 100644 effects/shadow.h diff --git a/CMakeLists.txt b/CMakeLists.txt index be2a18cb0e..9cea5eba95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ set(kwin_KDEINIT_SRCS effects/fallapart.cpp effects/drunken.cpp effects/flame.cpp + effects/shadow.cpp effects/test_input.cpp effects/test_thumbnail.cpp ) diff --git a/COMPOSITE_TODO b/COMPOSITE_TODO index 0d93e849b7..d630110a13 100644 --- a/COMPOSITE_TODO +++ b/COMPOSITE_TODO @@ -137,6 +137,9 @@ XRender TODO + SceneXrender::Window::performPaint() doesn't use saturation + SceneXrender::Window::performPaint() doesn't use brightness ++ SceneXrender::paintTransformedScreen() doesn't handle properly extending of painted area + in window's pre-paint - see the transformedShape() comment + Effects framework TODO ============================== @@ -146,7 +149,9 @@ Effects framework TODO ! - window state changes ? more -* shadows +/ shadows ++ - right now is only a rectangle, probably needs some shape support ++ - right now is only a flat black color, probably should be improved / support for grabbing input - during some more complicated effects, input (at least mouse) should be disabled, @@ -178,7 +183,7 @@ Effects TODO ? - I don't think these effects should be plugins or anything like that, probably simply write to kwinrc and use the Option class in KWin -+ implements all effects Kompmgr could do +/ implements all effects Kompmgr could do + - all effects from the Opacity tab should be already doable ! - applying translucency only to the decoration - use clientSize() and clientPos() from Client @@ -187,15 +192,12 @@ Effects TODO - just clear the alpha channel in the alpha clear hack - or do it while painting (see also the alpha clear hack todo entry) ! - the rest - should be simple -* - shadows - - framework is not ready for them yet (see the todo entry) +/ - shadows + - tab Effects -! - fade-in should be simple + - fade between changes - will need notification about opacity changes - not sure if this is doable for other opacity changes then the ones initiated by the user or by the application -* - fade-out needs framework for disappearing windows (see the todo entry) + minimize/shade effects - to replace the ones from KWin core diff --git a/client.cpp b/client.cpp index 97100121ac..acd1f4b518 100644 --- a/client.cpp +++ b/client.cpp @@ -191,7 +191,7 @@ void Client::releaseWindow( bool on_shutdown ) finishWindowRules(); ++block_geometry_updates; if( isOnCurrentDesktop() && isShown( true )) - workspace()->addRepaint( geometry()); + addWorkspaceRepaint( geometry()); setMappingState( WithdrawnState ); setModal( false ); // otherwise its mainwindow wouldn't get focus hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags) @@ -257,7 +257,7 @@ void Client::destroyClient() finishWindowRules(); ++block_geometry_updates; if( isOnCurrentDesktop() && isShown( true )) - workspace()->addRepaint( geometry()); + addWorkspaceRepaint( geometry()); setModal( false ); hidden = true; // so that it's not considered visible anymore workspace()->clientHidden( this ); @@ -655,7 +655,7 @@ void Client::setShade( ShadeMode mode ) // TODO all this unmapping, resizing etc. feels too much duplicated from elsewhere if ( isShade()) { // shade_mode == ShadeNormal - workspace()->addRepaint( geometry()); + addWorkspaceRepaint( geometry()); // shade shade_geometry_change = true; QSize s( sizeForClientSize( QSize( clientSize()))); @@ -826,7 +826,7 @@ void Client::rawShow() */ void Client::rawHide() { - workspace()->addRepaint( geometry()); + addWorkspaceRepaint( geometry()); // Here it may look like a race condition, as some other client might try to unmap // the window between these two XSelectInput() calls. However, they're supposed to // use XWithdrawWindow(), which also sends a synthetic event to the root window, diff --git a/composite.cpp b/composite.cpp index f835a36873..9e3100b536 100644 --- a/composite.cpp +++ b/composite.cpp @@ -246,8 +246,10 @@ void Workspace::performCompositing() if( children != NULL ) XFree( children ); foreach( Toplevel* c, windows ) - { // this could be possibly optimized WRT obscuring, but that'd need being already - // past prePaint() phase - probably not worth it + { // This could be possibly optimized WRT obscuring, but that'd need being already + // past prePaint() phase - probably not worth it. + // TODO I think effects->transformWindowDamage() doesn't need to be called here, + // pre-paint will extend painted window areas as necessary. repaints_region |= c->repaints().translated( c->pos()); c->resetRepaints( c->rect()); } @@ -470,4 +472,17 @@ void Toplevel::resetRepaints( const QRect& r ) repaints_region -= r; } +void Toplevel::addWorkspaceRepaint( int x, int y, int w, int h ) + { + addWorkspaceRepaint( QRect( x, y, w, h )); + } + +void Toplevel::addWorkspaceRepaint( const QRect& r2 ) + { + if( !compositing()) + return; + QRect r = effects->transformWindowDamage( effectWindow(), r2 ); + workspace()->addRepaint( r ); + } + } // namespace diff --git a/effects.cpp b/effects.cpp index 2d50ca7077..695ff98a1d 100644 --- a/effects.cpp +++ b/effects.cpp @@ -26,6 +26,7 @@ License. See the file "COPYING" for the exact licensing terms. #include "effects/minimizeanimation.h" #include "effects/presentwindows.h" #include "effects/scalein.h" +#include "effects/shadow.h" #include "effects/shakymove.h" #include "effects/shiftworkspaceup.h" #include "effects/showfps.h" @@ -128,9 +129,9 @@ void Effect::postPaintScreen() effects->postPaintScreen(); } -void Effect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void Effect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void Effect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) @@ -148,6 +149,11 @@ void Effect::drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintD effects->drawWindow( w, mask, region, data ); } +QRect Effect::transformWindowDamage( EffectWindow* w, const QRect& r ) + { + return effects->transformWindowDamage( w, r ); + } + void Effect::setPositionTransformations( WindowPaintData& data, QRect& region, EffectWindow* w, const QRect& r, Qt::AspectRatioMode aspect ) { @@ -172,6 +178,7 @@ EffectsHandler::EffectsHandler() : current_paint_screen( 0 ) , current_paint_window( 0 ) , current_draw_window( 0 ) + , current_transform( 0 ) { if( !compositing()) return; @@ -200,6 +207,7 @@ EffectsHandler::EffectsHandler() registerEffect("DesktopChangeSlide", new GenericEffectFactory); registerEffect("BoxSwitch", new GenericEffectFactory); registerEffect("Drunken", new GenericEffectFactory); + registerEffect("Shadow", new GenericEffectFactory); registerEffect("TestInput", new GenericEffectFactory); registerEffect("TestThumbnail", new GenericEffectFactory); @@ -319,6 +327,7 @@ void EffectsHandler::startPaint() assert( current_paint_screen == 0 ); assert( current_paint_window == 0 ); assert( current_draw_window == 0 ); + assert( current_transform == 0 ); } // the idea is that effects call this function again which calls the next one @@ -353,11 +362,11 @@ void EffectsHandler::postPaintScreen() // no special final code } -void EffectsHandler::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void EffectsHandler::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { if( current_paint_window < loaded_effects.size()) { - loaded_effects[current_paint_window++].second->prePaintWindow( w, mask, region, time ); + loaded_effects[current_paint_window++].second->prePaintWindow( w, mask, paint, clip, time ); --current_paint_window; } // no special final code @@ -395,6 +404,18 @@ void EffectsHandler::drawWindow( EffectWindow* w, int mask, QRegion region, Wind scene->finalDrawWindow( w, mask, region, data ); } +QRect EffectsHandler::transformWindowDamage( EffectWindow* w, const QRect& r ) + { + if( current_transform < loaded_effects.size()) + { + QRect rr = loaded_effects[current_transform++].second->transformWindowDamage( w, r ); + --current_transform; + return rr; + } + else + return r; + } + Window EffectsHandler::createInputWindow( Effect* e, int x, int y, int w, int h, const QCursor& cursor ) { XSetWindowAttributes attrs; @@ -502,6 +523,7 @@ void EffectsHandler::loadEffect( const QString& name ) assert( current_paint_screen == 0 ); assert( current_paint_window == 0 ); assert( current_draw_window == 0 ); + assert( current_transform == 0 ); for(QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); it++) { @@ -529,6 +551,7 @@ void EffectsHandler::unloadEffect( const QString& name ) assert( current_paint_screen == 0 ); assert( current_paint_window == 0 ); assert( current_draw_window == 0 ); + assert( current_transform == 0 ); for( QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); it++) { diff --git a/effects.h b/effects.h index 2924585aff..6647a6e255 100644 --- a/effects.h +++ b/effects.h @@ -68,13 +68,18 @@ class Effect 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* region, int time ); + virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ); // paintWindow() can do various transformations virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); virtual void postPaintWindow( EffectWindow* w ); // drawWindow() is used even for thumbnails etc. - it can alter the window itself where it // makes sense (e.g.darkening out unresponsive windows), but it cannot do transformations virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); + // This function is used e.g. by the shadow effect which adds area around windows + // that needs to be painted as well - e.g. when a window is hidden and the workspace needs + // to be repainted at that area, shadow's transformWindowDamage() adds the shadow area + // to it, so that it is repainted as well. + virtual QRect transformWindowDamage( EffectWindow* w, const QRect& r ); // called when moved/resized or once after it's finished virtual void windowUserMovedResized( EffectWindow* c, bool first, bool last ); virtual void windowOpacityChanged( EffectWindow* c, double old_opacity ); @@ -135,10 +140,11 @@ class EffectsHandler void prePaintScreen( int* mask, QRegion* region, int time ); void paintScreen( int mask, QRegion region, ScreenPaintData& data ); void postPaintScreen(); - void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + void prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ); void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); void postPaintWindow( EffectWindow* w ); void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); + QRect transformWindowDamage( EffectWindow* w, const QRect& r ); // Functions for handling input - e.g. when an Expose-like effect is shown, an input window // covering the whole screen is created and all mouse events will be intercepted by it. // The effect's windowInputMouseEvent() will get called with such events. @@ -181,6 +187,7 @@ class EffectsHandler int current_paint_screen; int current_paint_window; int current_draw_window; + int current_transform; }; // This class is a representation of a window used by/for Effect classes. diff --git a/effects/boxswitch.cpp b/effects/boxswitch.cpp index e7f2b0ddaf..5e88a3d3f5 100644 --- a/effects/boxswitch.cpp +++ b/effects/boxswitch.cpp @@ -44,7 +44,7 @@ void BoxSwitchEffect::prePaintScreen( int* mask, QRegion* region, int time ) effects->prePaintScreen( mask, region, time ); } -void BoxSwitchEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void BoxSwitchEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { if( mActivated ) { @@ -67,7 +67,7 @@ void BoxSwitchEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* regio } } } - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void BoxSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data ) diff --git a/effects/boxswitch.h b/effects/boxswitch.h index f11a683345..434d375d36 100644 --- a/effects/boxswitch.h +++ b/effects/boxswitch.h @@ -33,7 +33,7 @@ class BoxSwitchEffect virtual void prePaintScreen( int* mask, QRegion* region, int time ); virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data ); - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + 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 windowInputMouseEvent( Window w, QEvent* e ); diff --git a/effects/desktopchangeslide.cpp b/effects/desktopchangeslide.cpp index f1d01705c3..7466a47ff9 100644 --- a/effects/desktopchangeslide.cpp +++ b/effects/desktopchangeslide.cpp @@ -33,7 +33,7 @@ void DesktopChangeSlideEffect::prePaintScreen( int* mask, QRegion* region, int t effects->prePaintScreen( mask, region, time ); } -void DesktopChangeSlideEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void DesktopChangeSlideEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { if( progress != MAX_PROGRESS ) { @@ -50,7 +50,7 @@ void DesktopChangeSlideEffect::prePaintWindow( EffectWindow* w, int* mask, QRegi *mask |= Scene::PAINT_WINDOW_TRANSFORMED; } } - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void DesktopChangeSlideEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data ) diff --git a/effects/desktopchangeslide.h b/effects/desktopchangeslide.h index c3340b9722..2dd498e8bc 100644 --- a/effects/desktopchangeslide.h +++ b/effects/desktopchangeslide.h @@ -24,7 +24,7 @@ class 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* region, int time ); + 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: diff --git a/effects/dialogparent.cpp b/effects/dialogparent.cpp index ba176ec57c..7375436a25 100644 --- a/effects/dialogparent.cpp +++ b/effects/dialogparent.cpp @@ -19,7 +19,7 @@ License. See the file "COPYING" for the exact licensing terms. namespace KWinInternal { -void DialogParentEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void DialogParentEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { // How long does it take for the effect to get it's full strength (in ms) const float changeTime = 200; @@ -38,7 +38,7 @@ void DialogParentEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* re } // Call the next effect - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void DialogParentEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) diff --git a/effects/dialogparent.h b/effects/dialogparent.h index 9c272491ef..6df0e52329 100644 --- a/effects/dialogparent.h +++ b/effects/dialogparent.h @@ -28,7 +28,7 @@ class DialogParentEffect : public Effect { public: - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + 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 postPaintWindow( EffectWindow* w ); diff --git a/effects/drunken.cpp b/effects/drunken.cpp index 2d6e814823..194b696e1d 100644 --- a/effects/drunken.cpp +++ b/effects/drunken.cpp @@ -22,7 +22,7 @@ void DrunkenEffect::prePaintScreen( int* mask, QRegion* region, int time ) effects->prePaintScreen( mask, region, time ); } -void DrunkenEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void DrunkenEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { if( windows.contains( w )) { @@ -32,7 +32,7 @@ void DrunkenEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, else windows.remove( w ); } - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void DrunkenEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) diff --git a/effects/drunken.h b/effects/drunken.h index e4d5be95ed..7f5ce0fc9f 100644 --- a/effects/drunken.h +++ b/effects/drunken.h @@ -21,7 +21,7 @@ class DrunkenEffect { public: virtual void prePaintScreen( int* mask, QRegion* region, int time ); - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + 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 postPaintWindow( EffectWindow* w ); virtual void windowAdded( EffectWindow* w ); diff --git a/effects/explosioneffect.cpp b/effects/explosioneffect.cpp index 96752f8343..2ac551945c 100644 --- a/effects/explosioneffect.cpp +++ b/effects/explosioneffect.cpp @@ -93,7 +93,7 @@ void ExplosionEffect::prePaintScreen( int* mask, QRegion* region, int time ) effects->prePaintScreen(mask, region, time); } -void ExplosionEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void ExplosionEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { if( mWindows.contains( w )) { @@ -112,7 +112,7 @@ void ExplosionEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* regio } } - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void ExplosionEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) diff --git a/effects/explosioneffect.h b/effects/explosioneffect.h index bcecba8196..ef39973760 100644 --- a/effects/explosioneffect.h +++ b/effects/explosioneffect.h @@ -30,7 +30,7 @@ class ExplosionEffect ExplosionEffect(); virtual void prePaintScreen( int* mask, QRegion* region, int time ); - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + 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 postPaintScreen(); diff --git a/effects/fade.cpp b/effects/fade.cpp index 3aefb98681..a45e1b1caf 100644 --- a/effects/fade.cpp +++ b/effects/fade.cpp @@ -22,7 +22,7 @@ FadeEffect::FadeEffect() { } -void FadeEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void FadeEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { if( windows.contains( w )) { @@ -55,7 +55,7 @@ void FadeEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, in w->enablePainting( Scene::Window::PAINT_DISABLED_BY_DELETE ); } } - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void FadeEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) diff --git a/effects/fade.h b/effects/fade.h index 674adc94b2..988b15b4b2 100644 --- a/effects/fade.h +++ b/effects/fade.h @@ -21,7 +21,7 @@ class FadeEffect { public: FadeEffect(); - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + 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 postPaintWindow( EffectWindow* w ); // TODO react also on virtual desktop changes diff --git a/effects/fallapart.cpp b/effects/fallapart.cpp index d6d2e02bd6..d786524b00 100644 --- a/effects/fallapart.cpp +++ b/effects/fallapart.cpp @@ -25,7 +25,7 @@ void FallApartEffect::prePaintScreen( int* mask, QRegion* region, int time ) effects->prePaintScreen(mask, region, time); } -void FallApartEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void FallApartEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { if( windows.contains( w )) { @@ -47,7 +47,7 @@ void FallApartEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* regio } } } - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void FallApartEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) diff --git a/effects/fallapart.h b/effects/fallapart.h index ab13dc7c1e..7df54816b2 100644 --- a/effects/fallapart.h +++ b/effects/fallapart.h @@ -21,7 +21,7 @@ class FallApartEffect { public: virtual void prePaintScreen( int* mask, QRegion* region, int time ); - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + 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 postPaintScreen(); virtual void windowClosed( EffectWindow* c ); diff --git a/effects/flame.cpp b/effects/flame.cpp index 6920ddad0a..e0fb5f3020 100644 --- a/effects/flame.cpp +++ b/effects/flame.cpp @@ -23,7 +23,7 @@ void FlameEffect::prePaintScreen( int* mask, QRegion* region, int time ) effects->prePaintScreen(mask, region, time); } -void FlameEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void FlameEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { if( windows.contains( w )) { @@ -45,7 +45,7 @@ void FlameEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, i } } } - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void FlameEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) diff --git a/effects/flame.h b/effects/flame.h index 03c9fa8e15..7d015c96bc 100644 --- a/effects/flame.h +++ b/effects/flame.h @@ -21,7 +21,7 @@ class FlameEffect { public: virtual void prePaintScreen( int* mask, QRegion* region, int time ); - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + 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 postPaintWindow( EffectWindow* w ); virtual void windowClosed( EffectWindow* c ); diff --git a/effects/howto.cpp b/effects/howto.cpp index 8b9f89682e..5e0550d5bb 100644 --- a/effects/howto.cpp +++ b/effects/howto.cpp @@ -38,7 +38,7 @@ namespace KWinInternal // 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, int* mask, QRegion* region, int time ) +void HowtoEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { // Is this window the one that is going to be faded out and in again? if( w == fade_window ) @@ -63,7 +63,7 @@ void HowtoEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, i } // 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 ); + effects->prePaintWindow( w, mask, paint, clip, time ); } // The function that handles the actual painting. Some simple modifications are possible diff --git a/effects/howto.h b/effects/howto.h index 5fb774ee2d..57604b2d1d 100644 --- a/effects/howto.h +++ b/effects/howto.h @@ -38,7 +38,7 @@ class HowtoEffect // A pre-paint function. It tells the compositing code how the painting will // be affected by this effect. - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ); // A paint function. It actually performs the modifications to the painting. virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); diff --git a/effects/maketransparent.cpp b/effects/maketransparent.cpp index 40cc8d8c66..c939f76689 100644 --- a/effects/maketransparent.cpp +++ b/effects/maketransparent.cpp @@ -15,7 +15,7 @@ License. See the file "COPYING" for the exact licensing terms. namespace KWinInternal { -void MakeTransparentEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void MakeTransparentEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { const Client* c = dynamic_cast< const Client* >( w->window()); if(( c != NULL && ( c->isMove() || c->isResize())) || w->window()->isDialog()) @@ -23,7 +23,7 @@ void MakeTransparentEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* *mask |= Scene::PAINT_WINDOW_TRANSLUCENT; *mask &= ~Scene::PAINT_WINDOW_OPAQUE; } - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void MakeTransparentEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) diff --git a/effects/maketransparent.h b/effects/maketransparent.h index 8efef398a2..e1d7fd81ef 100644 --- a/effects/maketransparent.h +++ b/effects/maketransparent.h @@ -21,7 +21,7 @@ class MakeTransparentEffect { public: virtual void windowUserMovedResized( EffectWindow* c, bool first, bool last ); - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ); virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); }; diff --git a/effects/minimizeanimation.cpp b/effects/minimizeanimation.cpp index 920363e2da..910aae17ac 100644 --- a/effects/minimizeanimation.cpp +++ b/effects/minimizeanimation.cpp @@ -37,7 +37,7 @@ void MinimizeAnimationEffect::prePaintScreen( int* mask, QRegion* region, int ti effects->prePaintScreen(mask, region, time); } -void MinimizeAnimationEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void MinimizeAnimationEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { const float changeTime = 500; if( mAnimationProgress.contains( w )) @@ -69,7 +69,7 @@ void MinimizeAnimationEffect::prePaintWindow( EffectWindow* w, int* mask, QRegio mActiveAnimations--; } - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void MinimizeAnimationEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) diff --git a/effects/minimizeanimation.h b/effects/minimizeanimation.h index fe80fcd1fd..d22f709469 100644 --- a/effects/minimizeanimation.h +++ b/effects/minimizeanimation.h @@ -28,7 +28,7 @@ class MinimizeAnimationEffect MinimizeAnimationEffect(); virtual void prePaintScreen( int* mask, QRegion* region, int time ); - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + 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 postPaintScreen(); diff --git a/effects/presentwindows.cpp b/effects/presentwindows.cpp index 745f22915d..82fa1089a9 100644 --- a/effects/presentwindows.cpp +++ b/effects/presentwindows.cpp @@ -68,7 +68,7 @@ void PresentWindowsEffect::prePaintScreen( int* mask, QRegion* region, int time effects->prePaintScreen(mask, region, time); } -void PresentWindowsEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void PresentWindowsEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { if( mActiveness > 0.0f && mWindowData.contains(w->window()) ) { @@ -83,7 +83,7 @@ void PresentWindowsEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* *mask |= Scene::PAINT_WINDOW_TRANSLUCENT; } - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void PresentWindowsEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) diff --git a/effects/presentwindows.h b/effects/presentwindows.h index d6043b9fc4..8483b1001b 100644 --- a/effects/presentwindows.h +++ b/effects/presentwindows.h @@ -31,7 +31,7 @@ class PresentWindowsEffect virtual void prePaintScreen( int* mask, QRegion* region, int time ); - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + 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 postPaintScreen(); diff --git a/effects/scalein.cpp b/effects/scalein.cpp index addb2cb8fd..0e508bac0b 100644 --- a/effects/scalein.cpp +++ b/effects/scalein.cpp @@ -22,7 +22,7 @@ void ScaleInEffect::prePaintScreen( int* mask, QRegion* region, int time ) effects->prePaintScreen( mask, region, time ); } -void ScaleInEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void ScaleInEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { if( windows.contains( w )) { @@ -32,7 +32,7 @@ void ScaleInEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, else windows.remove( w ); } - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void ScaleInEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) diff --git a/effects/scalein.h b/effects/scalein.h index be4a4b3c52..2fdec92191 100644 --- a/effects/scalein.h +++ b/effects/scalein.h @@ -21,7 +21,7 @@ class ScaleInEffect { public: virtual void prePaintScreen( int* mask, QRegion* region, int time ); - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + 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 postPaintWindow( EffectWindow* w ); // TODO react also on virtual desktop changes diff --git a/effects/shadow.cpp b/effects/shadow.cpp new file mode 100644 index 0000000000..42c30bfd5f --- /dev/null +++ b/effects/shadow.cpp @@ -0,0 +1,86 @@ +/***************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2007 Lubos Lunak + +You can Freely distribute this program under the GNU General Public +License. See the file "COPYING" for the exact licensing terms. +******************************************************************/ + +#include "shadow.h" + +#ifdef HAVE_OPENGL +#include +#endif + +namespace KWinInternal +{ + +ShadowEffect::ShadowEffect() + : shadowXOffset( 10 ) + , shadowYOffset( 10 ) + { + } + +void ShadowEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) + { + *mask |= Scene::PAINT_WINDOW_TRANSLUCENT; + *paint |= ( QRegion( w->geometry()) & *paint ).translated( shadowXOffset, shadowYOffset ); + effects->prePaintWindow( w, mask, paint, clip, time ); + } + +void ShadowEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) + { + drawShadow( w, mask, region, data.opacity ); + effects->paintWindow( w, mask, region, data ); + } + +void ShadowEffect::postPaintWindow( EffectWindow* w ) + { + effects->postPaintWindow( w ); + } + +QRect ShadowEffect::transformWindowDamage( EffectWindow* w, const QRect& r ) + { + QRect r2 = r | r.translated( shadowXOffset, shadowYOffset ); + return effects->transformWindowDamage( w, r2 ); + } + +void ShadowEffect::drawShadow( EffectWindow* w, int mask, QRegion region, double opacity ) + { + if(( mask & Scene::PAINT_WINDOW_TRANSLUCENT ) == 0 ) + return; + glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + glColor4f( 0, 0, 0, 0.2 * opacity ); // black + QRect r( w->geometry()); + r.moveBy( shadowXOffset, shadowYOffset ); + glEnableClientState( GL_VERTEX_ARRAY ); + int verts[ 4 * 2 ] = + { + r.x(), r.y(), + r.x(), r.y() + r.height(), + r.x() + r.width(), r.y() + r.height(), + r.x() + r.width(), r.y() + }; + glVertexPointer( 2, GL_INT, 0, verts ); + if( mask & ( Scene::PAINT_WINDOW_TRANSFORMED | Scene::PAINT_SCREEN_TRANSFORMED )) + glDrawArrays( GL_QUADS, 0, 4 ); + else + { // clip by region + glEnable( GL_SCISSOR_TEST ); + int dh = displayHeight(); + foreach( QRect r, region.rects()) + { + // Scissor rect has to be given in OpenGL coords + glScissor(r.x(), dh - r.y() - r.height(), r.width(), r.height()); + glDrawArrays( GL_QUADS, 0, 4 ); + } + } + glDisableClientState( GL_VERTEX_ARRAY ); + glPopAttrib(); + } + +} // namespace diff --git a/effects/shadow.h b/effects/shadow.h new file mode 100644 index 0000000000..6c18d1387a --- /dev/null +++ b/effects/shadow.h @@ -0,0 +1,35 @@ +/***************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2007 Lubos Lunak + +You can Freely distribute this program under the GNU General Public +License. See the file "COPYING" for the exact licensing terms. +******************************************************************/ + +#ifndef KWIN_SHADOW_H +#define KWIN_SHADOW_H + +#include + +namespace KWinInternal +{ + +class ShadowEffect + : public Effect + { + public: + ShadowEffect(); + 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 postPaintWindow( EffectWindow* w ); + virtual QRect transformWindowDamage( EffectWindow* w, const QRect& r ); + private: + void drawShadow( EffectWindow* w, int mask, QRegion region, double opacity ); + int shadowXOffset, shadowYOffset; + }; + +} // namespace + +#endif diff --git a/effects/shakymove.cpp b/effects/shakymove.cpp index 4c8a7f8c52..112b514086 100644 --- a/effects/shakymove.cpp +++ b/effects/shakymove.cpp @@ -30,11 +30,11 @@ void ShakyMoveEffect::prePaintScreen( int* mask, QRegion* region, int time ) effects->prePaintScreen( mask, region, time ); } -void ShakyMoveEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void ShakyMoveEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { if( windows.contains( w )) *mask |= Scene::PAINT_WINDOW_TRANSFORMED; - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void ShakyMoveEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) diff --git a/effects/shakymove.h b/effects/shakymove.h index fdb0efd78c..46d1e381c4 100644 --- a/effects/shakymove.h +++ b/effects/shakymove.h @@ -25,7 +25,7 @@ class ShakyMoveEffect public: ShakyMoveEffect(); virtual void prePaintScreen( int* mask, QRegion* region, int time ); - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + 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 windowUserMovedResized( EffectWindow* c, bool first, bool last ); virtual void windowClosed( EffectWindow* c ); diff --git a/effects/wavywindows.cpp b/effects/wavywindows.cpp index ea22e42275..775732019d 100644 --- a/effects/wavywindows.cpp +++ b/effects/wavywindows.cpp @@ -41,7 +41,7 @@ void WavyWindowsEffect::prePaintScreen( int* mask, QRegion* region, int time ) effects->prePaintScreen(mask, region, time); } -void WavyWindowsEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ) +void WavyWindowsEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* paint, QRegion* clip, int time ) { // This window will be transformed by the effect *mask |= Scene::PAINT_WINDOW_TRANSFORMED; @@ -52,7 +52,7 @@ void WavyWindowsEffect::prePaintWindow( EffectWindow* w, int* mask, QRegion* reg // pixels big glwin->requestVertexGrid(30); - effects->prePaintWindow( w, mask, region, time ); + effects->prePaintWindow( w, mask, paint, clip, time ); } void WavyWindowsEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) diff --git a/effects/wavywindows.h b/effects/wavywindows.h index c8da148c56..9b452c6860 100644 --- a/effects/wavywindows.h +++ b/effects/wavywindows.h @@ -28,7 +28,7 @@ class WavyWindowsEffect WavyWindowsEffect(); virtual void prePaintScreen( int* mask, QRegion* region, int time ); - virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); + 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 postPaintScreen(); diff --git a/events.cpp b/events.cpp index 63aa1506e6..8043a95b72 100644 --- a/events.cpp +++ b/events.cpp @@ -1665,7 +1665,7 @@ void Unmanaged::configureNotifyEvent( XConfigureEvent* e ) QRect newgeom( e->x, e->y, e->width, e->height ); if( newgeom == geom ) return; - workspace()->addRepaint( geometry()); // damage old area + addWorkspaceRepaint( geometry()); // damage old area QRect old = geom; geom = newgeom; discardWindowPixmap(); diff --git a/geometry.cpp b/geometry.cpp index 4056106aa0..1571379c1b 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -1707,7 +1707,7 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force ) if( effects != NULL ) effects->windowGeometryShapeChanged( effectWindow(), geom_before_block ); } - workspace()->addRepaint( geom_before_block ); + addWorkspaceRepaint( geom_before_block ); geom_before_block = geom; } @@ -1768,7 +1768,7 @@ void Client::plainResize( int w, int h, ForceGeometry_t force ) scene->windowGeometryShapeChanged( this ); if( effects != NULL ) effects->windowGeometryShapeChanged( effectWindow(), geom_before_block ); - workspace()->addRepaint( geom_before_block ); + addWorkspaceRepaint( geom_before_block ); geom_before_block = geom; } @@ -1791,8 +1791,8 @@ void Client::move( int x, int y, ForceGeometry_t force ) updateWindowRules(); checkMaximizeGeometry(); // client itself is not damaged - workspace()->addRepaint( geom_before_block ); - workspace()->addRepaint( geom ); // trigger repaint of window's new location + addWorkspaceRepaint( geom_before_block ); + addWorkspaceRepaint( geom ); // trigger repaint of window's new location geom_before_block = geom; } diff --git a/scene.cpp b/scene.cpp index 2ffc71d406..e53405d214 100644 --- a/scene.cpp +++ b/scene.cpp @@ -109,6 +109,7 @@ void Scene::paintScreen( int* mask, QRegion* region ) { // whole screen, not transformed, force region to be full *region = QRegion( 0, 0, displayWidth(), displayHeight()); } + painted_region = *region; if( *mask & PAINT_SCREEN_BACKGROUND_FIRST ) paintBackground( *region ); ScreenPaintData data; @@ -116,6 +117,9 @@ void Scene::paintScreen( int* mask, QRegion* region ) effects->postPaintScreen(); foreach( Window* w, stacking_order ) effects->postPaintWindow( effectWindow( w )); + *region |= painted_region; + // make sure not to go outside of the screen area + *region &= QRegion( 0, 0, displayWidth(), displayHeight()); } // Compute time since the last painting pass. @@ -161,12 +165,13 @@ void Scene::paintGenericScreen( int orig_mask, ScreenPaintData ) { int mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT ); w->resetPaintingEnabled(); - QRegion damage = infiniteRegion(); + QRegion paint = infiniteRegion(); // no clipping, so doesn't really matter + QRegion clip = QRegion(); // preparation step - effects->prePaintWindow( effectWindow( w ), &mask, &damage, time_diff ); + effects->prePaintWindow( effectWindow( w ), &mask, &paint, &clip, time_diff ); if( !w->isPaintingEnabled()) continue; - paintWindow( w, mask, damage ); + paintWindow( w, mask, infiniteRegion()); } } @@ -180,6 +185,7 @@ void Scene::paintSimpleScreen( int orig_mask, QRegion region ) assert(( orig_mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED | PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_OPAQUE )) == 0 ); QList< Phase2Data > phase2; + QRegion allclips; // Draw each opaque window top to bottom, subtracting the bounding rect of // each window from the clip region after it's been drawn. for( int i = stacking_order.count() - 1; // top to bottom @@ -187,25 +193,32 @@ void Scene::paintSimpleScreen( int orig_mask, QRegion region ) --i ) { Window* w = stacking_order[ i ]; - if( region.isEmpty()) // completely clipped - continue; int mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT ); w->resetPaintingEnabled(); - QRegion damage = region; + QRegion paint = region; + QRegion clip = w->isOpaque() ? w->shape().translated( w->x(), w->y()) : QRegion(); // preparation step - effects->prePaintWindow( effectWindow( w ), &mask, &damage, time_diff ); + effects->prePaintWindow( effectWindow( w ), &mask, &paint, &clip, time_diff ); if( !w->isPaintingEnabled()) continue; + paint -= allclips; // make sure to avoid already clipped areas + if( paint.isEmpty()) // completely clipped + continue; + if( paint != region ) // prepaint added area to draw + { + region |= paint; // make sure other windows in that area get painted too + painted_region |= paint; // make sure it makes it to the screen + } // If the window is transparent, the transparent part will be done // in the 2nd pass. if( mask & PAINT_WINDOW_TRANSLUCENT ) - phase2.prepend( Phase2Data( w, region, mask )); + phase2.prepend( Phase2Data( w, paint, mask )); if( mask & PAINT_WINDOW_OPAQUE ) { - paintWindow( w, mask, region ); - // If the window is not transparent at all, it can clip windows below. - if( ( mask & PAINT_WINDOW_TRANSLUCENT ) == 0 ) - region -= w->shape().translated( w->x(), w->y()); + paintWindow( w, mask, paint ); + // The window can clip by its opaque parts the windows below. + region -= clip; + allclips |= clip; } } if( !( orig_mask & PAINT_SCREEN_BACKGROUND_FIRST )) @@ -213,10 +226,14 @@ void Scene::paintSimpleScreen( int orig_mask, QRegion region ) // Now walk the list bottom to top, drawing translucent windows. // That we draw bottom to top is important now since we're drawing translucent objects // and also are clipping only by opaque windows. + QRegion add_paint; foreach( Phase2Data d, phase2 ) { Window* w = d.window; - paintWindow( w, d.mask, d.region ); + paintWindow( w, d.mask, d.region | add_paint ); + // It is necessary to also add paint regions of windows below, because their + // pre-paint's might have extended the paint area, so those areas need to be painted too. + add_paint |= d.region; } } diff --git a/scene.h b/scene.h index 030d1269da..0819e4a9b5 100644 --- a/scene.h +++ b/scene.h @@ -106,6 +106,12 @@ class Scene }; // windows in their stacking order QVector< Window* > stacking_order; + // The region which actually has been painted by paintScreen() and should be + // copied from the buffer to the screen. I.e. the region returned from Scene::paintScreen(). + // Since prePaintWindow() can extend areas to paint, these changes would have to propagate + // up all the way from paintSimpleScreen() up to paintScreen(), so save them here rather + // than propagate them up in arguments. + QRegion painted_region; // time since last repaint int time_diff; QTime last_time; diff --git a/scene_opengl.cpp b/scene_opengl.cpp index f654c1edf2..5a74c37bd6 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -557,8 +557,6 @@ void SceneOpenGL::waitSync() // actually paint to the screen (double-buffer swap or copy from pixmap buffer) void SceneOpenGL::flushBuffer( int mask, QRegion damage ) { - if( mask & PAINT_SCREEN_REGION )// make sure not to go outside visible screen - damage &= QRegion( 0, 0, displayWidth(), displayHeight()); if( db ) { if( mask & PAINT_SCREEN_REGION ) diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 39db4e2be7..6a6a1a8562 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -157,6 +157,7 @@ void SceneXrender::paintTransformedScreen( int orig_mask ) { QRegion region( 0, 0, displayWidth(), displayHeight()); QList< Phase2Data > phase2; + QRegion allclips; // Draw each opaque window top to bottom, subtracting the bounding rect of // each window from the clip region after it's been drawn. for( int i = stacking_order.count() - 1; // top to bottom @@ -164,26 +165,33 @@ void SceneXrender::paintTransformedScreen( int orig_mask ) --i ) { Window* w = static_cast< Window* >( stacking_order[ i ] ); - if( region.isEmpty()) // completely clipped - continue; int mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT ); w->resetPaintingEnabled(); - QRegion damage = region; + QRegion paint = region; + // TODO this is wrong, transformedShape() should be used here, but is not known yet + QRegion clip = w->isOpaque() ? region : QRegion(); // preparation step - effects->prePaintWindow( effectWindow( w ), &mask, &damage, time_diff ); + effects->prePaintWindow( effectWindow( w ), &mask, &paint, &clip, time_diff ); if( !w->isPaintingEnabled()) continue; + paint -= allclips; // make sure to avoid already clipped areas + if( paint.isEmpty()) // completely clipped + continue; + if( paint != region ) // prepaint added area to draw + { + region |= paint; // make sure other windows in that area get painted too + painted_region |= paint; // make sure it makes it to the screen + } // If the window is transparent, the transparent part will be done // in the 2nd pass. if( mask & PAINT_WINDOW_TRANSLUCENT ) - phase2.prepend( Phase2Data( w, region, mask )); + phase2.prepend( Phase2Data( w, paint, mask )); if( mask & PAINT_WINDOW_OPAQUE ) { w->setTransformedShape( QRegion()); - paintWindow( w, mask, region ); - // If the window is not transparent at all, it can clip windows below. - if( ( mask & PAINT_WINDOW_TRANSLUCENT ) == 0 ) - region -= w->transformedShape(); + paintWindow( w, mask, paint ); + // The window can clip by its opaque parts the windows below. + region -= w->transformedShape(); } } if( !( orig_mask & PAINT_SCREEN_BACKGROUND_FIRST )) @@ -191,10 +199,14 @@ void SceneXrender::paintTransformedScreen( int orig_mask ) // Now walk the list bottom to top, drawing translucent windows. // That we draw bottom to top is important now since we're drawing translucent objects // and also are clipping only by opaque windows. + QRegion add_paint; foreach( Phase2Data d, phase2 ) { Scene::Window* w = d.window; - paintWindow( w, d.mask, d.region ); + paintWindow( w, d.mask, d.region | add_paint ); + // It is necessary to also add paint regions of windows below, because their + // pre-paint's might have extended the paint area, so those areas need to be painted too. + add_paint |= d.region; } } diff --git a/toplevel.h b/toplevel.h index b01276f5f9..bb56a43fec 100644 --- a/toplevel.h +++ b/toplevel.h @@ -90,6 +90,9 @@ class Toplevel void addRepaint( const QRect& r ); void addRepaint( int x, int y, int w, int h ); void addRepaintFull(); + // these call workspace->addRepaint(), but first transform the damage if needed + void addWorkspaceRepaint( const QRect& r ); + void addWorkspaceRepaint( int x, int y, int w, int h ); QRegion repaints() const; void resetRepaints( const QRect& r ); QRegion damage() const; diff --git a/unmanaged.cpp b/unmanaged.cpp index fab53eaf60..8f8e7244ee 100644 --- a/unmanaged.cpp +++ b/unmanaged.cpp @@ -80,7 +80,7 @@ void Unmanaged::release() if( Extensions::shapeAvailable()) XShapeSelectInput( display(), window(), NoEventMask ); XSelectInput( display(), window(), NoEventMask ); - workspace()->addRepaint( geometry()); + addWorkspaceRepaint( geometry()); disownDataPassedToDeleted(); del->unrefWindow(); deleteUnmanaged( this, Allowed ); diff --git a/workspace.h b/workspace.h index f5f7b5e66b..b243e21d98 100644 --- a/workspace.h +++ b/workspace.h @@ -18,6 +18,8 @@ License. See the file "COPYING" for the exact licensing terms. #include #include #include +#include +#include #include "utils.h" #include "kdecoration.h" @@ -77,7 +79,7 @@ class Workspace : public QObject, public KDecorationDefines virtual ~Workspace(); static Workspace * self() { return _self; } - + bool workspaceEvent( XEvent * ); KDecoration* createDecoration( KDecorationBridge* bridge ); @@ -87,6 +89,9 @@ class Workspace : public QObject, public KDecorationDefines template< typename T > Client* findClient( T predicate ); template< typename T1, typename T2 > void forEachClient( T1 procedure, T2 predicate ); template< typename T > void forEachClient( T procedure ); + template< typename T > Unmanaged* findUnmanaged( T predicate ); + template< typename T1, typename T2 > void forEachUnmanaged( T1 procedure, T2 predicate ); + template< typename T > void forEachUnmanaged( T procedure ); QRect clientArea( clientAreaOption, const QPoint& p, int desktop ) const; QRect clientArea( clientAreaOption, const Client* c ) const; @@ -165,12 +170,17 @@ class Workspace : public QObject, public KDecorationDefines QWidget* desktopWidget(); // for TabBox + Client* currentTabBoxClient() const; + ClientList currentTabBoxClientList() const; + int currentTabBoxDesktop() const; Client* nextFocusChainClient(Client*) const; Client* previousFocusChainClient(Client*) const; Client* nextStaticClient(Client*) const; Client* previousStaticClient(Client*) const; int nextDesktopFocusChain( int iDesktop ) const; int previousDesktopFocusChain( int iDesktop ) const; + void refTabBox(); + void unrefTabBox(); void closeTabBox(); /** @@ -181,7 +191,7 @@ class Workspace : public QObject, public KDecorationDefines ClientList ensureStackingOrder( const ClientList& clients ) const; - Client* topClientOnDesktop( int desktop, bool unconstrained = false, bool only_normal = true ) const; + Client* topClientOnDesktop( int desktop, bool unconstrained = false ) const; Client* findDesktop( bool topmost, int desktop ) const; void sendClientToDesktop( Client* c, int desktop, bool dont_activate ); void windowToPreviousDesktop( Client* c ); @@ -190,6 +200,10 @@ class Workspace : public QObject, public KDecorationDefines // KDE4 remove me - and it's also in the DCOP interface :( void showWindowMenuAt( unsigned long id, int x, int y ); + void loadEffect( const QString& name ); + + void unloadEffect( const QString& name ); + /** * Shows the menu operations menu for the client and makes it active if * it's not already. @@ -213,8 +227,6 @@ class Workspace : public QObject, public KDecorationDefines WindowRules findWindowRules( const Client*, bool ); void rulesUpdated(); void discardUsedWindowRules( Client* c, bool withdraw ); - void disableRulesUpdates( bool disable ); - bool rulesUpdatesDisabled() const; // dcop interface void cascadeDesktop(); @@ -226,7 +238,7 @@ class Workspace : public QObject, public KDecorationDefines void circulateDesktopApplications(); QString desktopName( int desk ) const; - void setDesktopLayout(NET::Orientation o, int x, int y, NET::DesktopLayoutCorner c); + void setDesktopLayout(int o, int x, int y); void setShowingDesktop( bool showing ); void resetShowingDesktop( bool keep_hidden ); bool showingDesktop() const; @@ -236,14 +248,17 @@ class Workspace : public QObject, public KDecorationDefines void sendPingToWindow( Window w, Time timestamp ); // called from Client::pingWindow() void sendTakeActivity( Client* c, Time timestamp, long flags ); // called from Client::takeActivity() - // only called from Client::destroyClient() or Client::releaseWindow() - void removeClient( Client*, allowed_t ); + void removeClient( Client*, allowed_t ); // only called from Client::destroyClient() or Client::releaseWindow() void setActiveClient( Client*, allowed_t ); Group* findGroup( Window leader ) const; void addGroup( Group* group, allowed_t ); void removeGroup( Group* group, allowed_t ); Group* findClientLeaderGroup( const Client* c ) const; + void removeUnmanaged( Unmanaged*, allowed_t ); // only called from Unmanaged::release() + void removeDeleted( Deleted*, allowed_t ); + void addDeleted( Deleted*, allowed_t ); + bool checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data ); void focusToNull(); // SELI public? @@ -279,6 +294,19 @@ class Workspace : public QObject, public KDecorationDefines void toggleTopDockShadows(bool on); + // when adding repaints caused by a window, you probably want to use + // either Toplevel::addRepaint() or Toplevel::addWorkspaceRepaint() + void addRepaint( const QRect& r ); + void addRepaint( int x, int y, int w, int h ); + void addRepaintFull(); + // creates XComposite overlay window, call initOverlay() afterwards + bool createOverlay(); + // init overlay and the destination window in it + void setupOverlay( Window window ); + // destroys XComposite overlay window + void destroyOverlay(); + Window overlayWindow(); + public slots: void refresh(); // keybindings @@ -408,15 +436,14 @@ class Workspace : public QObject, public KDecorationDefines void cleanupTemporaryRules(); void writeWindowRules(); void slotBlockShortcuts(int data); - void slotReloadConfig(); - // kompmgr - void setPopupClientOpacity(int v); - void resetClientOpacity(); - void setTransButtonText(int value); - // end + void setPopupClientOpacity( QAction* action ); + void setupCompositing(); + void performCompositing(); + void lostCMSelection(); protected: bool keyPressMouseEmulation( XKeyEvent& ev ); + bool netCheck( XEvent* e ); private: void init(); @@ -460,6 +487,8 @@ class Workspace : public QObject, public KDecorationDefines // this is the right way to create a new client Client* createClient( Window w, bool is_mapped ); void addClient( Client* c, allowed_t ); + Unmanaged* createUnmanaged( Window w ); + void addUnmanaged( Unmanaged* c, allowed_t ); Window findSpecialEventWindow( XEvent* e ); @@ -501,6 +530,9 @@ class Workspace : public QObject, public KDecorationDefines void closeActivePopup(); void updateClientArea( bool force ); + + void finishCompositing(); + bool windowRepaintsPending() const; SystemTrayWindowList systemTrayWins; @@ -521,7 +553,6 @@ class Workspace : public QObject, public KDecorationDefines QList rules; KXMessages temporaryRulesMessages; QTimer rulesUpdatedTimer; - bool rules_updates_disabled; static const char* windowTypeToTxt( NET::WindowType type ); static NET::WindowType txtToWindowType( const char* txt ); static bool sessionInfoWindowTypeMatch( Client* c, SessionInfo* info ); @@ -538,10 +569,12 @@ class Workspace : public QObject, public KDecorationDefines ClientList clients; ClientList desktops; + UnmanagedList unmanaged; + DeletedList deleted; - ClientList unconstrained_stacking_order; // topmost last - ClientList stacking_order; // topmost last - QVector< ClientList > focus_chain; // currently ative last + ClientList unconstrained_stacking_order; + ClientList stacking_order; + QVector< ClientList > focus_chain; ClientList global_focus_chain; // this one is only for things like tabbox's MRU ClientList should_get_focus; // last is most recent ClientList attention_chain; @@ -575,6 +608,7 @@ class Workspace : public QObject, public KDecorationDefines QMenu *popup; QMenu *advanced_popup; + QMenu *trans_popup; QMenu *desk_popup; int desk_popup_index; @@ -658,12 +692,14 @@ class Workspace : public QObject, public KDecorationDefines bool forced_global_mouse_grab; friend class StackingUpdatesBlocker; - //kompmgr + KSelectionOwner* cm_selection; + QTimer compositeTimer; + QTime lastCompositePaint; + int compositeRate; + QRegion repaints_region; + Window overlay; // XComposite overlay window QSlider *transSlider; QPushButton *transButton; - - private: - friend bool performTransiencyCheck(); }; // helper for Workspace::blockStackingUpdates() being called in pairs (true/false) @@ -806,10 +842,9 @@ inline bool Workspace::globalShortcutsDisabled() const return global_shortcuts_disabled || global_shortcuts_disabled_for_client; } -inline -bool Workspace::rulesUpdatesDisabled() const +inline Window Workspace::overlayWindow() { - return rules_updates_disabled; + return overlay; } template< typename T > @@ -839,7 +874,27 @@ inline void Workspace::forEachClient( T procedure ) return forEachClient( procedure, TruePredicate()); } -KWIN_COMPARE_PREDICATE( ClientMatchPredicate, const Client*, cl == value ); +template< typename T > +inline Unmanaged* Workspace::findUnmanaged( T predicate ) + { + return findUnmanagedInList( unmanaged, predicate ); + } + +template< typename T1, typename T2 > +inline void Workspace::forEachUnmanaged( T1 procedure, T2 predicate ) + { + for ( UnmanagedList::ConstIterator it = unmanaged.begin(); it != unmanaged.end(); ++it) + if ( predicate( const_cast< const Unmanaged* >( *it))) + procedure( *it ); + } + +template< typename T > +inline void Workspace::forEachUnmanaged( T procedure ) + { + return forEachUnmanaged( procedure, TruePredicate()); + } + +KWIN_COMPARE_PREDICATE( ClientMatchPredicate, Client, const Client*, cl == value ); inline bool Workspace::hasClient( const Client* c ) { return findClient( ClientMatchPredicate( c ));