diff --git a/CMakeLists.txt b/CMakeLists.txt index c510e98812..5514872573 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ set(kwin_KDEINIT_SRCS scene_xrender.cpp scene_opengl.cpp glutils.cpp + deleted.cpp effects.cpp effects/fadein.cpp effects/fadeout.cpp diff --git a/COMPOSITE_TODO b/COMPOSITE_TODO index 2cc811e473..e5cab9c054 100644 --- a/COMPOSITE_TODO +++ b/COMPOSITE_TODO @@ -67,10 +67,12 @@ General TODO * handle properly deleted windows that reappear (windowReadded() function?) -? consider using an extra class for representing deleted windows +/ consider using an extra class for representing deleted windows - cleaning up Client/Unmanaged instances may still leave e.g. timers around if they're overlooked - an extra class could copy some interesting data and "replace" the old instance ++ Deleted::windowType() does not work + OpenGL TODO ================================= @@ -224,6 +226,10 @@ Effects TODO initiated by the user or by the application * - fade-out needs framework for disappearing windows (see the todo entry) ++ add API that'll hide the internals (for making backwards compatibility easier, etc.) + - effects should have access only to classes from this API + - hide the fact that Client/Unmanaged become Deleted in windowClosed() + + minimize/shade effects - to replace the ones from KWin core - Client::animateMinimizeOrUnminimize() diff --git a/client.cpp b/client.cpp index 2edfccd33b..daab947696 100644 --- a/client.cpp +++ b/client.cpp @@ -30,6 +30,7 @@ License. See the file "COPYING" for the exact licensing terms. #include "rules.h" #include "scene.h" #include "effects.h" +#include "deleted.h" #include #include @@ -108,6 +109,7 @@ Client::Client( Workspace *ws ) shade_mode = ShadeNone; active = false; + deleting = false; keep_above = false; keep_below = false; motif_noborder = false; @@ -174,11 +176,16 @@ void Client::deleteClient( Client* c, allowed_t ) */ void Client::releaseWindow( bool on_shutdown ) { - assert( !deleting()); - delete_refcount = 1; + assert( !deleting ); + deleting = true; if( effects ) - effects->windowClosed( this ); - finishCompositing( false ); // don't discard pixmap + { + Deleted* del = Deleted::create( this ); + effects->windowClosed( this, del ); + scene->windowClosed( this, del ); + del->unrefWindow(); + } + finishCompositing(); workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules StackingUpdatesBlocker blocker( workspace()); if (moveResizeMode) @@ -193,9 +200,7 @@ void Client::releaseWindow( bool on_shutdown ) if( !on_shutdown ) workspace()->clientHidden( this ); XUnmapWindow( display(), frameId()); // destroying decoration would cause ugly visual effect -// destroyDecoration(); - delete decoration; - decoration = NULL; + destroyDecoration(); cleanGrouping(); if( !on_shutdown ) { @@ -203,11 +208,9 @@ void Client::releaseWindow( bool on_shutdown ) // only when the window is being unmapped, not when closing down KWin // (NETWM sections 5.5,5.7) info->setDesktop( 0 ); - // desk = 0; - do not reset internal state, it may still be used by effects + desk = 0; info->setState( 0, info->state()); // reset all state flags } - else - workspace()->addDeleted( this, Allowed ); XDeleteProperty( display(), client, atoms->kde_net_wm_user_creation_time); XDeleteProperty( display(), client, atoms->net_frame_extents ); XDeleteProperty( display(), client, atoms->kde_net_wm_frame_strut ); @@ -225,25 +228,30 @@ void Client::releaseWindow( bool on_shutdown ) // may do map+unmap before we initially map the window by calling rawShow() from manage(). XUnmapWindow( display(), client ); } - cleanUp(); client = None; XDestroyWindow( display(), wrapper ); wrapper = None; XDestroyWindow( display(), frameId()); // frame = None; --block_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry - unrefWindow(); // will delete if recount is == 0 + workspace()->addDamage( geometry()); + deleteClient( this, Allowed ); } // like releaseWindow(), but this one is called when the window has been already destroyed // (e.g. the application closed it) void Client::destroyClient() { - assert( !deleting()); - delete_refcount = 1; + assert( !deleting ); + deleting = true; if( effects ) - effects->windowClosed( this ); - finishCompositing( false ); // don't discard pixmap + { + Deleted* del = Deleted::create( this ); + effects->windowClosed( this, del ); + scene->windowClosed( this, del ); + del->unrefWindow(); + } + finishCompositing(); workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules StackingUpdatesBlocker blocker( workspace()); if (moveResizeMode) @@ -255,50 +263,16 @@ void Client::destroyClient() setModal( false ); hidden = true; // so that it's not considered visible anymore workspace()->clientHidden( this ); -// destroyDecoration(); - delete decoration; - decoration = NULL; + destroyDecoration(); cleanGrouping(); workspace()->removeClient( this, Allowed ); - cleanUp(); client = None; // invalidate XDestroyWindow( display(), wrapper ); wrapper = None; XDestroyWindow( display(), frameId()); // frame = None; --block_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry - unrefWindow(); // will delete if recount is == 0 - } - -// All clean-up code shared between releaseWindow() and destroyClient(). -// Clean up everything that should not affect a deleted Client until it's -// really deleted by unrefWindow(). I.e. stop watching events, turn off timers -// and so on. -void Client::cleanUp() - { - if( Extensions::shapeAvailable()) - XShapeSelectInput( display(), client, NoEventMask ); - XSelectInput( display(), client, NoEventMask ); - delete autoRaiseTimer; - autoRaiseTimer = NULL; - delete shadeHoverTimer; - shadeHoverTimer = NULL; - delete ping_timer; - ping_timer = NULL; - delete process_killer; - process_killer = NULL; - delete demandAttentionKNotifyTimer; - demandAttentionKNotifyTimer = NULL; - } - -void Client::unrefWindow() - { - if( --delete_refcount > 0 ) - return; - workspace()->removeDeleted( this ); workspace()->addDamage( geometry()); - destroyDecoration( true ); // only now gravitate etc., otherwise window pixmap would be wrong - discardWindowPixmap(); deleteClient( this, Allowed ); } @@ -343,9 +317,9 @@ void Client::updateDecoration( bool check_workspace_pos, bool force ) addDamageFull(); } -void Client::destroyDecoration( bool force ) +void Client::destroyDecoration() { - if( decoration != NULL || force ) + if( decoration != NULL ) { delete decoration; decoration = NULL; @@ -360,7 +334,7 @@ void Client::destroyDecoration( bool force ) workarea_diff_y = save_workarea_diff_y; if( compositing() ) discardWindowPixmap(); - if( scene != NULL && !deleting()) + if( scene != NULL && !deleting ) scene->windowGeometryShapeChanged( this ); addDamageFull(); } @@ -895,7 +869,7 @@ void Client::toggleShade() void Client::updateVisibility() { - if( deleting()) + if( deleting ) return; bool show = true; if( hidden ) @@ -953,7 +927,7 @@ void Client::updateVisibility() void Client::setMappingState(int s) { assert( client != None ); - assert( !deleting() || s == WithdrawnState ); + assert( !deleting || s == WithdrawnState ); if( mapping_state == s ) return; bool was_unmanaged = ( mapping_state == WithdrawnState ); diff --git a/client.h b/client.h index 9a458cef90..1148a39a3c 100644 --- a/client.h +++ b/client.h @@ -91,7 +91,6 @@ class Client void releaseWindow( bool on_shutdown = false ); void destroyClient(); - virtual void unrefWindow(); enum Sizemode // how to resize the window in order to obey constains (mainly aspect ratios) { @@ -358,7 +357,6 @@ class Client void updateWindowRules(); void finishWindowRules(); void setShortcutInternal( const KShortcut& cut ); - void cleanUp(); void updateWorkareaDiffs(); void checkDirection( int new_diff, int old_diff, QRect& rect, const QRect& area ); @@ -387,7 +385,7 @@ class Client void embedClient( Window w, const XWindowAttributes &attr ); void detectNoBorder(); - void destroyDecoration( bool force = false ); + void destroyDecoration(); void updateFrameExtents(); void rawShow(); // just shows it @@ -432,6 +430,7 @@ class Client ClientList transients_list; // SELI make this ordered in stacking order? ShadeMode shade_mode; uint active :1; + uint deleting : 1; // true when doing cleanup and destroying the client uint keep_above : 1; // NET::KeepAbove (was stays_on_top) uint skip_taskbar :1; uint original_skip_taskbar :1; // unaffected by KWin diff --git a/composite.cpp b/composite.cpp index 94c43c22c3..8229ae881c 100644 --- a/composite.cpp +++ b/composite.cpp @@ -29,6 +29,7 @@ License. See the file "COPYING" for the exact licensing terms. #include "workspace.h" #include "client.h" #include "unmanaged.h" +#include "deleted.h" #include "effects.h" #include "scene.h" #include "scene_basic.h" @@ -137,13 +138,17 @@ void Workspace::finishCompositing() return; delete cm_selection; foreach( Client* c, clients ) - scene->windowDeleted( c ); + scene->windowClosed( c, NULL ); foreach( Unmanaged* c, unmanaged ) + scene->windowClosed( c, NULL ); + foreach( Deleted* c, deleted ) scene->windowDeleted( c ); foreach( Client* c, clients ) c->finishCompositing(); foreach( Unmanaged* c, unmanaged ) c->finishCompositing(); + foreach( Deleted* c, deleted ) + c->finishCompositing(); XCompositeUnredirectSubwindows( display(), rootWindow(), CompositeRedirectManual ); compositeTimer.stop(); delete effects; @@ -222,7 +227,7 @@ void Workspace::performCompositing() else if( Unmanaged* c = findUnmanaged( HandleMatchPredicate( children[ i ] ))) windows.append( c ); } - foreach( Toplevel* c, pending_deleted ) // TODO remember stacking order somehow + foreach( Deleted* c, deleted ) // TODO remember stacking order somehow windows.append( c ); QRegion damage = damage_region; // clear all damage, so that post-pass can add damage for the next repaint @@ -292,13 +297,12 @@ void Toplevel::setupCompositing() damage_region = QRegion( 0, 0, width(), height()); } -void Toplevel::finishCompositing( bool discard_pixmap ) +void Toplevel::finishCompositing() { if( damage_handle == None ) return; XDamageDestroy( display(), damage_handle ); - if( discard_pixmap ) - discardWindowPixmap(); + discardWindowPixmap(); damage_handle = None; damage_region = QRegion(); } diff --git a/effects.cpp b/effects.cpp index 6e8de4a0c1..c4dd4ef363 100644 --- a/effects.cpp +++ b/effects.cpp @@ -47,11 +47,11 @@ void Effect::windowAdded( Toplevel* ) { } -void Effect::windowClosed( Toplevel* ) +void Effect::windowClosed( Toplevel*, Deleted* ) { } -void Effect::windowDeleted( Toplevel* ) +void Effect::windowDeleted( Deleted* ) { } @@ -147,16 +147,16 @@ void EffectsHandler::windowAdded( Toplevel* c ) e->windowAdded( c ); } -void EffectsHandler::windowDeleted( Toplevel* c ) +void EffectsHandler::windowDeleted( Deleted* c ) { foreach( Effect* e, effects ) e->windowDeleted( c ); } -void EffectsHandler::windowClosed( Toplevel* c ) +void EffectsHandler::windowClosed( Toplevel* c, Deleted* deleted ) { foreach( Effect* e, effects ) - e->windowClosed( c ); + e->windowClosed( c, deleted ); } void EffectsHandler::windowActivated( Toplevel* c ) diff --git a/effects.h b/effects.h index 607b3cd2b6..7b06a111ac 100644 --- a/effects.h +++ b/effects.h @@ -73,8 +73,8 @@ class Effect // called when moved/resized or once after it's finished virtual void windowUserMovedResized( Toplevel* c, bool first, bool last ); virtual void windowAdded( Toplevel* c ); - virtual void windowDeleted( Toplevel* c ); - virtual void windowClosed( Toplevel* c ); + virtual void windowClosed( Toplevel* c, Deleted* deleted ); + virtual void windowDeleted( Deleted* c ); virtual void windowActivated( Toplevel* c ); virtual void windowMinimized( Toplevel* c ); virtual void windowUnminimized( Toplevel* c ); @@ -111,8 +111,8 @@ class EffectsHandler void startPaint(); void windowUserMovedResized( Toplevel* c, bool first, bool last ); void windowAdded( Toplevel* c ); - void windowClosed( Toplevel* c ); - void windowDeleted( Toplevel* c ); + void windowClosed( Toplevel* c, Deleted* deleted ); + void windowDeleted( Deleted* c ); void windowActivated( Toplevel* c ); void windowMinimized( Toplevel* c ); void windowUnminimized( Toplevel* c ); diff --git a/effects/dialogparent.cpp b/effects/dialogparent.cpp index f8b529298f..aa7614ea7f 100644 --- a/effects/dialogparent.cpp +++ b/effects/dialogparent.cpp @@ -84,7 +84,7 @@ void DialogParentEffect::windowActivated( Toplevel* t ) } } -void DialogParentEffect::windowDeleted( Toplevel* t ) +void DialogParentEffect::windowClosed( Toplevel* t, Deleted* ) { // If this window is a dialog, we need to damage it's parent window, so // that the effect could be run for it diff --git a/effects/dialogparent.h b/effects/dialogparent.h index aa622e654b..43a19cb4f8 100644 --- a/effects/dialogparent.h +++ b/effects/dialogparent.h @@ -32,7 +32,7 @@ class DialogParentEffect virtual void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data ); virtual void postPaintWindow( Scene::Window* w ); - virtual void windowDeleted( Toplevel* c ); + virtual void windowClosed( Toplevel* c, Deleted* ); virtual void windowActivated( Toplevel* c ); protected: diff --git a/effects/fadein.cpp b/effects/fadein.cpp index 95ea075f1c..083636eb79 100644 --- a/effects/fadein.cpp +++ b/effects/fadein.cpp @@ -57,7 +57,7 @@ void FadeInEffect::windowAdded( Toplevel* c ) } } -void FadeInEffect::windowDeleted( Toplevel* c ) +void FadeInEffect::windowClosed( Toplevel* c, Deleted* ) { windows.remove( c ); } diff --git a/effects/fadein.h b/effects/fadein.h index 80ea76589d..698b9d88e4 100644 --- a/effects/fadein.h +++ b/effects/fadein.h @@ -27,7 +27,7 @@ class FadeInEffect virtual void postPaintWindow( Scene::Window* w ); // TODO react also on virtual desktop changes virtual void windowAdded( Toplevel* c ); - virtual void windowDeleted( Toplevel* c ); + virtual void windowClosed( Toplevel* c, Deleted* ); private: QMap< const Toplevel*, double > windows; }; diff --git a/effects/fadeout.cpp b/effects/fadeout.cpp index ac37504f3e..5b8a4fed57 100644 --- a/effects/fadeout.cpp +++ b/effects/fadeout.cpp @@ -11,6 +11,7 @@ License. See the file "COPYING" for the exact licensing terms. #include "fadeout.h" #include +#include namespace KWinInternal { @@ -28,7 +29,7 @@ void FadeOutEffect::prePaintWindow( Scene::Window* w, int* mask, QRegion* region else { windows.remove( w->window()); - w->window()->unrefWindow(); + static_cast< Deleted* >( w->window())->unrefWindow(); } } effects->prePaintWindow( w, mask, region, time ); @@ -50,18 +51,18 @@ void FadeOutEffect::postPaintWindow( Scene::Window* w ) effects->postPaintWindow( w ); } -void FadeOutEffect::windowClosed( Toplevel* c ) +void FadeOutEffect::windowClosed( Toplevel* c, Deleted* d ) { Client* cc = dynamic_cast< Client* >( c ); if( cc == NULL || cc->isOnCurrentDesktop()) { - windows[ c ] = 1; // count down to 0 - c->addDamageFull(); - c->refWindow(); + windows[ d ] = 1; // count down to 0 + d->addDamageFull(); + d->refWindow(); } } -void FadeOutEffect::windowDeleted( Toplevel* c ) +void FadeOutEffect::windowDeleted( Deleted* c ) { windows.remove( c ); } diff --git a/effects/fadeout.h b/effects/fadeout.h index 2b6dfb9983..ffb0303fbc 100644 --- a/effects/fadeout.h +++ b/effects/fadeout.h @@ -26,8 +26,8 @@ class FadeOutEffect virtual void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data ); virtual void postPaintWindow( Scene::Window* w ); // TODO react also on virtual desktop changes - virtual void windowClosed( Toplevel* c ); - virtual void windowDeleted( Toplevel* c ); + virtual void windowClosed( Toplevel* c, Deleted* d ); + virtual void windowDeleted( Deleted* c ); private: QMap< const Toplevel*, double > windows; }; diff --git a/effects/howto.cpp b/effects/howto.cpp index 481db48048..a518567eac 100644 --- a/effects/howto.cpp +++ b/effects/howto.cpp @@ -20,6 +20,7 @@ License. See the file "COPYING" for the exact licensing terms. // Include the class definition. #include "howto.h" +#include "deleted.h" // Note that currently effects need to be manually enabled in the EffectsHandler // class constructor (in effects.cpp). @@ -137,8 +138,15 @@ void HowtoEffect::windowActivated( Toplevel* c ) } } +// TODO +void HowtoEffect::windowClosed( Toplevel* c, Deleted* d ) + { + if( fade_window == c ) + fade_window = d; + } + // This function is called when a window is destroyed. -void HowtoEffect::windowDeleted( Toplevel* c ) +void HowtoEffect::windowDeleted( Deleted* 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. diff --git a/effects/howto.h b/effects/howto.h index 1e54b23c0a..609543ad69 100644 --- a/effects/howto.h +++ b/effects/howto.h @@ -51,8 +51,11 @@ class HowtoEffect // Notification functions: These inform the effect about changes such as a new window // being activated. + // TODO + virtual void windowClosed( Toplevel* c, Deleted* d ); + // The given window has been deleted (destroyed). - virtual void windowDeleted( Toplevel* c ); + virtual void windowDeleted( Deleted* c ); // The given window has been activated. virtual void windowActivated( Toplevel* c ); diff --git a/effects/presentwindows.cpp b/effects/presentwindows.cpp index 3edb0c3c0d..8695202fc1 100644 --- a/effects/presentwindows.cpp +++ b/effects/presentwindows.cpp @@ -131,7 +131,7 @@ void PresentWindowsEffect::windowActivated( Toplevel* t ) rearrangeWindows(); } -void PresentWindowsEffect::windowDeleted( Toplevel* t ) +void PresentWindowsEffect::windowClosed( Toplevel* t, Deleted* ) { rearrangeWindows(); } diff --git a/effects/presentwindows.h b/effects/presentwindows.h index f2861bf713..bf6a35363e 100644 --- a/effects/presentwindows.h +++ b/effects/presentwindows.h @@ -35,7 +35,7 @@ class PresentWindowsEffect virtual void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data ); virtual void postPaintScreen(); - virtual void windowDeleted( Toplevel* c ); + virtual void windowClosed( Toplevel* c, Deleted* ); virtual void windowActivated( Toplevel* c ); virtual void windowInputMouseEvent( Window w, QEvent* e ); diff --git a/effects/scalein.cpp b/effects/scalein.cpp index 0ae2368724..850a97dc43 100644 --- a/effects/scalein.cpp +++ b/effects/scalein.cpp @@ -65,7 +65,7 @@ void ScaleInEffect::windowAdded( Toplevel* c ) } } -void ScaleInEffect::windowDeleted( Toplevel* c ) +void ScaleInEffect::windowClosed( Toplevel* c, Deleted* ) { windows.remove( c ); } diff --git a/effects/scalein.h b/effects/scalein.h index 5b34344622..8904bc85ed 100644 --- a/effects/scalein.h +++ b/effects/scalein.h @@ -28,7 +28,7 @@ class ScaleInEffect virtual void postPaintWindow( Scene::Window* w ); // TODO react also on virtual desktop changes virtual void windowAdded( Toplevel* c ); - virtual void windowDeleted( Toplevel* c ); + virtual void windowClosed( Toplevel* c, Deleted* ); private: QMap< const Toplevel*, double > windows; }; diff --git a/effects/shakymove.cpp b/effects/shakymove.cpp index 639f2e2d4e..a6f39fe644 100644 --- a/effects/shakymove.cpp +++ b/effects/shakymove.cpp @@ -62,7 +62,7 @@ void ShakyMoveEffect::windowUserMovedResized( Toplevel* c, bool first, bool last } } -void ShakyMoveEffect::windowDeleted( Toplevel* c ) +void ShakyMoveEffect::windowClosed( Toplevel* c, Deleted* ) { windows.remove( c ); if( windows.isEmpty()) diff --git a/effects/shakymove.h b/effects/shakymove.h index 722ad8e366..0def91d043 100644 --- a/effects/shakymove.h +++ b/effects/shakymove.h @@ -30,7 +30,7 @@ class ShakyMoveEffect virtual void prePaintScreen( int* mask, QRegion* region, int time ); virtual void prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time ); virtual void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data ); - virtual void windowDeleted( Toplevel* c ); + virtual void windowClosed( Toplevel* c, Deleted* ); private slots: void tick(); private: diff --git a/scene.cpp b/scene.cpp index ffe738ff87..d740ff0317 100644 --- a/scene.cpp +++ b/scene.cpp @@ -64,6 +64,7 @@ License. See the file "COPYING" for the exact licensing terms. #include #include "client.h" +#include "deleted.h" #include "effects.h" namespace KWinInternal @@ -290,7 +291,7 @@ QRegion Scene::Window::shape() const bool Scene::Window::isVisible() const { - if( toplevel->deleting()) + if( dynamic_cast< Deleted* >( toplevel ) != NULL ) return false; if( Client* c = dynamic_cast< Client* >( toplevel )) return c->isShown( true ) && c->isOnCurrentDesktop(); diff --git a/scene.h b/scene.h index 3ae7077dc8..7907e09547 100644 --- a/scene.h +++ b/scene.h @@ -20,6 +20,7 @@ namespace KWinInternal { class Workspace; +class Deleted; class WindowPaintData; class ScreenPaintData; @@ -43,8 +44,10 @@ class Scene virtual void windowOpacityChanged( Toplevel* ) = 0; // a new window has been created virtual void windowAdded( Toplevel* ) = 0; + // a window has been closed + virtual void windowClosed( Toplevel*, Deleted* ) = 0; // a window has been destroyed - virtual void windowDeleted( Toplevel* ) = 0; + virtual void windowDeleted( Deleted* ) = 0; // Flags controlling how painting is done. enum { @@ -128,6 +131,7 @@ class Scene::Window // shape of the window QRegion shape() const; void discardShape(); + void updateToplevel( Toplevel* c ); Window() {} // QMap sucks even in Qt4 protected: Toplevel* toplevel; @@ -174,6 +178,12 @@ Toplevel* Scene::Window::window() return toplevel; } +inline +void Scene::Window::updateToplevel( Toplevel* c ) + { + toplevel = c; + } + } // namespace #endif diff --git a/scene_basic.cpp b/scene_basic.cpp index 480958fba9..59c92c52b3 100644 --- a/scene_basic.cpp +++ b/scene_basic.cpp @@ -77,7 +77,11 @@ void SceneBasic::windowAdded( Toplevel* ) { } -void SceneBasic::windowDeleted( Toplevel* ) +void SceneBasic::windowClosed( Toplevel*, Deleted* ) + { + } + +void SceneBasic::windowDeleted( Deleted* ) { } diff --git a/scene_basic.h b/scene_basic.h index 61cd5420b0..181fc00376 100644 --- a/scene_basic.h +++ b/scene_basic.h @@ -28,7 +28,8 @@ class SceneBasic virtual void windowGeometryShapeChanged( Toplevel* ); virtual void windowOpacityChanged( Toplevel* ); virtual void windowAdded( Toplevel* ); - virtual void windowDeleted( Toplevel* ); + virtual void windowClosed( Toplevel*, Deleted* ); + virtual void windowDeleted( Deleted* ); }; } // namespace diff --git a/scene_opengl.cpp b/scene_opengl.cpp index dae85254e9..b49d17a4d1 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -59,6 +59,7 @@ Sources and other compositing managers: #include "utils.h" #include "client.h" +#include "deleted.h" #include "effects.h" #include "glutils.h" @@ -565,7 +566,24 @@ void SceneOpenGL::windowAdded( Toplevel* c ) windows[ c ] = Window( c ); } -void SceneOpenGL::windowDeleted( Toplevel* c ) +void SceneOpenGL::windowClosed( Toplevel* c, Deleted* deleted ) + { + assert( windows.contains( c )); + if( deleted != NULL ) + { // replace c with deleted + Window& w = windows[ c ]; + w.updateToplevel( deleted ); + windows[ deleted ] = w; + windows.remove( c ); + } + else + { + windows[ c ].free(); + windows.remove( c ); + } + } + +void SceneOpenGL::windowDeleted( Deleted* c ) { assert( windows.contains( c )); windows[ c ].free(); diff --git a/scene_opengl.h b/scene_opengl.h index 4a0e25df8a..c9e9933f44 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -31,7 +31,8 @@ class SceneOpenGL virtual void windowGeometryShapeChanged( Toplevel* ); virtual void windowOpacityChanged( Toplevel* ); virtual void windowAdded( Toplevel* ); - virtual void windowDeleted( Toplevel* ); + virtual void windowClosed( Toplevel*, Deleted* ); + virtual void windowDeleted( Deleted* ); protected: virtual void paintGenericScreen( int mask, ScreenPaintData data ); virtual void paintBackground( QRegion region ); diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 4d85666e58..70f8691d6f 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -33,6 +33,7 @@ License. See the file "COPYING" for the exact licensing terms. #include "toplevel.h" #include "client.h" +#include "deleted.h" #include "effects.h" namespace KWinInternal @@ -230,7 +231,24 @@ void SceneXrender::windowOpacityChanged( Toplevel* c ) w.discardAlpha(); } -void SceneXrender::windowDeleted( Toplevel* c ) +void SceneXrender::windowClosed( Toplevel* c, Deleted* deleted ) + { + assert( windows.contains( c )); + if( deleted != NULL ) + { // replace c with deleted + Window& w = windows[ c ]; + w.updateToplevel( deleted ); + windows[ deleted ] = w; + windows.remove( c ); + } + else + { + windows[ c ].free(); + windows.remove( c ); + } + } + +void SceneXrender::windowDeleted( Deleted* c ) { assert( windows.contains( c )); windows[ c ].free(); diff --git a/scene_xrender.h b/scene_xrender.h index c5db75c5cf..e24f089224 100644 --- a/scene_xrender.h +++ b/scene_xrender.h @@ -33,7 +33,8 @@ class SceneXrender virtual void windowGeometryShapeChanged( Toplevel* ); virtual void windowOpacityChanged( Toplevel* ); virtual void windowAdded( Toplevel* ); - virtual void windowDeleted( Toplevel* ); + virtual void windowClosed( Toplevel*, Deleted* ); + virtual void windowDeleted( Deleted* ); Picture bufferPicture(); protected: virtual void paintBackground( QRegion region ); diff --git a/toplevel.cpp b/toplevel.cpp index 618af3e875..0343c2c1af 100644 --- a/toplevel.cpp +++ b/toplevel.cpp @@ -15,7 +15,6 @@ namespace KWinInternal Toplevel::Toplevel( Workspace* ws ) : vis( None ) - , delete_refcount( -1 ) , id( None ) , wspace( ws ) , window_pix( None ) @@ -79,6 +78,21 @@ void Toplevel::detectShape( Window id ) is_shape = Extensions::hasShape( id ); } +// used only by Deleted::copy() +void Toplevel::copyToDeleted( Toplevel* c ) + { + geom = c->geom; + vis = c->vis; + bit_depth = c->bit_depth; + id = c->id; + wspace = c->wspace; + window_pix = c->window_pix; + c->window_pix = None; + damage_handle = None; + damage_region = c->damage_region; + is_shape = c->is_shape; + } + } // namespace #include "toplevel.moc" diff --git a/toplevel.h b/toplevel.h index 14fa0081b1..3bb658e212 100644 --- a/toplevel.h +++ b/toplevel.h @@ -59,18 +59,13 @@ class Toplevel int depth() const; bool hasAlpha() const; void setupCompositing(); - void finishCompositing( bool discard_pixmap = true ); + void finishCompositing(); void addDamage( const QRect& r ); void addDamage( int x, int y, int w, int h ); void addDamageFull(); QRegion damage() const; void resetDamage( const QRect& r ); - // used by effects to keep the window around for e.g. fadeout effects when it's destroyed - void refWindow(); - virtual void unrefWindow() = 0; - bool deleting() const; - protected: virtual ~Toplevel(); void setHandle( Window id ); @@ -81,10 +76,11 @@ class Toplevel QRect geom; Visual* vis; int bit_depth; - int delete_refcount; virtual void debug( kdbgstream& stream ) const = 0; + void copyToDeleted( Toplevel* c ); friend kdbgstream& operator<<( kdbgstream& stream, const Toplevel* ); private: + // when adding new data members, check also copyToDeleted() Window id; Workspace* wspace; Pixmap window_pix; @@ -226,17 +222,6 @@ inline bool Toplevel::hasAlpha() const return depth() == 32; } -inline void Toplevel::refWindow() - { - assert( delete_refcount >= 0 ); - ++delete_refcount; - } - -inline bool Toplevel::deleting() const - { - return delete_refcount >= 0; - } - #ifdef NDEBUG inline kndbgstream& operator<<( kndbgstream& stream, const Toplevel* ) { return stream; } diff --git a/unmanaged.cpp b/unmanaged.cpp index 56981c5c4a..750862bff3 100644 --- a/unmanaged.cpp +++ b/unmanaged.cpp @@ -12,6 +12,7 @@ License. See the file "COPYING" for the exact licensing terms. #include "workspace.h" #include "effects.h" +#include "deleted.h" #include @@ -70,24 +71,18 @@ bool Unmanaged::track( Window w ) void Unmanaged::release() { - assert( !deleting()); - delete_refcount = 1; if( effects ) - effects->windowClosed( this ); - finishCompositing( false ); // don't discard pixmap + { + Deleted* del = Deleted::create( this ); + effects->windowClosed( this, del ); + scene->windowClosed( this, del ); + del->unrefWindow(); + } + finishCompositing(); workspace()->removeUnmanaged( this, Allowed ); if( Extensions::shapeAvailable()) XShapeSelectInput( display(), handle(), NoEventMask ); XSelectInput( display(), handle(), NoEventMask ); - unrefWindow(); // will delete if recount is == 0 - } - -void Unmanaged::unrefWindow() - { - if( --delete_refcount > 0 ) - return; - discardWindowPixmap(); - workspace()->removeDeleted( this ); workspace()->addDamage( geometry()); deleteUnmanaged( this, Allowed ); } diff --git a/unmanaged.h b/unmanaged.h index d7feb99738..7cc6dc87aa 100644 --- a/unmanaged.h +++ b/unmanaged.h @@ -30,7 +30,6 @@ class Unmanaged virtual NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const; static void deleteUnmanaged( Unmanaged* c, allowed_t ); virtual double opacity() const; - virtual void unrefWindow(); protected: virtual void debug( kdbgstream& stream ) const; private: diff --git a/utils.h b/utils.h index 88d9e745f4..32d1f9449a 100644 --- a/utils.h +++ b/utils.h @@ -75,6 +75,7 @@ const QPoint invalidPoint( INT_MIN, INT_MIN ); class Toplevel; class Client; class Unmanaged; +class Deleted; class Group; class Options; @@ -84,6 +85,8 @@ typedef QList< Client* > ClientList; typedef QList< const Client* > ConstClientList; typedef QList< Unmanaged* > UnmanagedList; typedef QList< const Unmanaged* > ConstUnmanagedList; +typedef QList< Deleted* > DeletedList; +typedef QList< const Deleted* > ConstDeletedList; typedef QList< Group* > GroupList; typedef QList< const Group* > ConstGroupList; diff --git a/workspace.cpp b/workspace.cpp index 2c0408959d..78cb793862 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -616,31 +616,28 @@ void Workspace::removeClient( Client* c, allowed_t ) tab_box->repaint(); updateClientArea(); - - addDeleted( c, Allowed ); } void Workspace::removeUnmanaged( Unmanaged* c, allowed_t ) { assert( unmanaged.contains( c )); unmanaged.removeAll( c ); - addDeleted( c, Allowed ); } -void Workspace::addDeleted( Toplevel* c, allowed_t ) +void Workspace::addDeleted( Deleted* c, allowed_t ) { - assert( !pending_deleted.contains( c )); - pending_deleted.append( c ); + assert( !deleted.contains( c )); + deleted.append( c ); } -void Workspace::removeDeleted( Toplevel* c ) +void Workspace::removeDeleted( Deleted* c, allowed_t ) { - assert( pending_deleted.contains( c )); + assert( deleted.contains( c )); if( scene ) scene->windowDeleted( c ); if( effects ) effects->windowDeleted( c ); - pending_deleted.removeAll( c ); + deleted.removeAll( c ); } void Workspace::updateFocusChains( Client* c, FocusChainChange change ) diff --git a/workspace.h b/workspace.h index e96c7f8f7e..322b8dc515 100644 --- a/workspace.h +++ b/workspace.h @@ -247,8 +247,8 @@ class Workspace : public QObject, public KDecorationDefines Group* findClientLeaderGroup( const Client* c ) const; void removeUnmanaged( Unmanaged*, allowed_t ); // only called from Unmanaged::release() - void removeDeleted( Toplevel* ); - void addDeleted( Toplevel*, allowed_t ); + void removeDeleted( Deleted*, allowed_t ); + void addDeleted( Deleted*, allowed_t ); bool checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data ); @@ -558,7 +558,7 @@ class Workspace : public QObject, public KDecorationDefines ClientList clients; ClientList desktops; UnmanagedList unmanaged; - ToplevelList pending_deleted; + DeletedList deleted; ClientList unconstrained_stacking_order; ClientList stacking_order;