diff --git a/COMPOSITE_TODO b/COMPOSITE_TODO index 7b3a22dab0..81c2a6901c 100644 --- a/COMPOSITE_TODO +++ b/COMPOSITE_TODO @@ -1,93 +1,99 @@ -* = not done +This file lists TODO items for the compositing code. + +See file HACKING for details on developing KWin. +See effects/howto.* for a HOWTO on writting effects. +See documentation in source (mainly in scene.cpp) for description +of the design of the compositing framework. + +TODO +================================= + +* = not done, will be either done by me, or should be at least discussed first with me ++ = not done, I don't plan on doing it that soon + - in other words, these should be the best ones for you if you want to help +! = like +, but they should be relatively simple + - in other words, these should be the best if you want to get started with the code / = work in progress ? = should it be done? -See the HACKING file for KWin details. The composite-related sources are mostly -composite.cpp and scene_opengl.cpp (TODO: add comments and general overview). -Sources: +General TODO +================================= -- glcompmgr : http://lists.freedesktop.org/archives/xorg/2006-July/017006.html , - http://www.mail-archive.com/compiz%40lists.freedesktop.org/msg00023.html - - simple and easy to understand - - works even without texture_from_pixmap extension - - claims to support several different gfx cards -- compiz : git clone git://anongit.freedesktop.org/git/xorg/app/compiz - - the ultimate - - glxcompmgr : git clone git://anongit.freedesktop.org/git/xorg/app/glxcompgr - - a rather old version of compiz, but also simpler and as such simpler - to understand -- libcm (metacity) : cvs -d :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome co libcm - - no idea about it - -- http://opengl.org - documentation - OpenGL Redbook, GLX docs, extensions docs - -TODO: - -* Check/make it work with other gfx cards - - I've tested only with nvidia with the 9625 beta drivers and 8776 stable drivers so far - - I have absolutely no idea about other gfx cards, needs to be tested - * ati - * intel - * who knows what else - -? Xgl support - - Compiz itself doesn't work when compiled with the libGL from nvidia, - it ships its own and links against it - ? might be worth trying to use that libGL as well - - it may be just because of the special libGL, but when testing with Xgl - it even seemed non-conformant - none of the provided configs had - GLX_RENDER_TYPE with GLX_RGBA_BIT even though required by GLX - and other funny things. Indeed, it may be just me being still pretty - clueless about these things. - * is there a good reason to support Xgl? With the 9625 nvidia drivers - it seems to work fine without them - -? AIGLX support - - no idea about this at all - * find out if it works - -* XComposite overlay window +! XComposite overlay window - X.Org 7.1 and newer have XComposite extension version 0.3, which allows creating an overlay window to paint to instead of painting to the root window - - I still run older X.Org here - the code in glcompmgr for this is in HAVE_OVERLAYS, stealing primarily from here should be better since it's simpler and the code so far has been modelled more after glcompmgr - the code in compiz for this is in USE_COW - * use double-buffering with the overlay window - kwin already has code +! - use double-buffering with the overlay window - kwin already has code for double-buffered destination drawable, but I haven't been able to test it - -* when relying on extensions, detect that they are available - - some of the glcompmgr code probably depends on OpenGL/GLX extensions that may - not be always available, probably the same with compiz - * find out which code relies on extensions and add checks + - should be only needed for OpenGL code, I think this doesn't matter for XRender ? alpha clear hack - * find out if it affects performance - * if yes, try to find a better way of solving the problem - - since kompmgr has an option to make only the decoration transparent, ++ - find out if it affects performance ++ - if yes, try to find a better way of solving the problem +! - since kompmgr has an option to make only the decoration transparent, it should be possible to do the same here - if the window has alpha and a decoration or if there should be only the decoration transparent, paint first the contents and then the decoration - this should make it possible to paint the decoration without the random alpha that is right now handled by the alpha hack -/ design framework for graphical effects - - modelling it after compiz seems to make a lot of sense +* don't add workspace damage in Toplevel::addDamage() + - instead add damage of windows to the screen only before doing the painting + - this should prevent repaints because of changing obscured windows -* update only those parts of the screen that have been changed - - for paintSimpleScreen() - it currently sets region to the whole screen - * instead of using glXSwapBuffers() there should be glCopyPixels() used - - compiz has such code in evenLoop() in the if() block for COMP_SCREEN_DAMAGE_REGION_MASK - * perhaps syncing to vblank will be needed to avoid flicker - * XCopyArea() should not update the whole screen but only the affected areas +* wait for decoration repaints + - it is sometimes visible that the window contents are painted first and the decoration + only afterwards with a small delay + - maybe posted paint events need to be processed immediatelly, or maybe the compositing + code should not update the window until the decoration is finished painting -* sync to vblank +* handle XRandr changes + - output buffers and similar probably need recreating when the screen size changes + + +OpenGL TODO +================================= + ++ Check/make it work with other gfx cards + - I've tested only with nvidia with the 9625 beta drivers and 8776 stable drivers so far + - I have absolutely no idea about other gfx cards, needs to be tested ++ - ati ++ - intel ++ - who knows what else + +? Xgl support + - Compiz itself doesn't work when compiled with the libGL from nvidia, + it ships its own and links against it +? - might be worth trying to use that libGL as well + - it may be just because of the special libGL, but when testing with Xgl + it even seemed non-conformant - none of the provided configs had + GLX_RENDER_TYPE with GLX_RGBA_BIT even though required by GLX + and other funny things. Indeed, it may be just me being still pretty + clueless about these things. +? - is there a good reason to support Xgl? With the 9625 nvidia drivers + it seems to work fine without them and there's AIGLX + +? AIGLX support + - no idea about this at all ++ - find out if it works + +! when relying on extensions, detect that they are available + - some of the glcompmgr code probably depends on OpenGL/GLX extensions that may + not be always available, probably the same with compiz +! - find out which code relies on extensions and add checks +! - it seems that some systems (using older X.org?) will need local versions + of some #defines like GLX_TEXTURE_FORMAT_EXT + - Beryl has this code in beryl.h + ++ sync to vblank - currently the compositing code is run with 20ms timer, i.e. constant 50fps - the GLX_SGI_video_sync extension should be used - compiz uses this, no idea about it though -? GL_ARB_texture_rectangle vs GL_ARB_texture_non_power_of_two ++ GL_ARB_texture_rectangle vs GL_ARB_texture_non_power_of_two - code currently uses GL_ARB_texture_rectangle (GL_TEXTURE_RECTANGLE_ARB), using normal textures when GL_ARB_texture_non_power_of_two is available should(?) be preferred @@ -95,26 +101,98 @@ TODO: ? in SceneOpenGL::bindTexture() with tfp_mode, with some gfx cards it seems to be faster to not short-circuit the texture binding when there's been no damage - * confirm and try to find out when to do it and when not ++ - confirm and try to find out when to do it and when not -* SceneXrender::Window::performPaint() doesn't use xScale/yScale +! update only those parts of the screen that have been changed + - for paintSimpleScreen() - it currently sets region to the whole screen +! - instead of using glXSwapBuffers() there should be glCopyPixels() used + - compiz has such code in evenLoop() in the if() block for COMP_SCREEN_DAMAGE_REGION_MASK ++ - perhaps syncing to vblank will be needed to avoid flicker +! - XCopyArea() should not update the whole screen but only the affected areas + + +XRender TODO +============================== + ++ SceneXrender::Window::performPaint() doesn't use xScale/yScale - XRenderSetPictureTransform() should be capable of doing this - note that the matrix used seems to be weird (it doesn't act like the normal transformation matrix as far as I can tell) + +Effects framework TODO +============================== + +/ design framework for graphical effects + - modelling it after compiz seems to make a lot of sense + * solve somehow disappearing windows - i.e. when a window is e.g. closed, the Client/Unmanaged object is destroyed, but animations should be going on - ? maybe animations could be done actually before the state change, it makes sense to destroy +? - maybe animations could be done actually before the state change, it makes sense to destroy the window only after it's finished exploding or really minimizing the window only after the animation of minimizing to the taskbar is done, however this looks very hairy and error-prone - ? maybe the animation effects should keep the necessary info themselves, so that the object +? - maybe the animation effects should keep the necessary info themselves, so that the object can be destroyed - the problem here may be what to do when the window again reappears, a new object will be created, but the old animation should be stopped - compare window id's? - ? maybe just keep the object around in a special list + - another problem is that then the window won't exist at all in the scene functions, + so e.g. no paintWindow() will be called for it +? - maybe just keep the object around in a special list -* don't add workspace damage in Toplevel::addDamage() - - instead add damage of windows to the screen only before doing the painting - - this should prevent repaints because of obscured windows +* more notification functions for effects are needed + - currently there are only very few notification functions (windowAdded, windowActivated,...) +! - virtual desktop change +! - window state changes + ? more + +* shadows + +* support for effects involving more virtual desktops + - currently effects are limited to only the active virtual desktop + +* support for grabbing input + - during some more complicated effects, input (at least mouse) should be disabled, + because currently there is no way to do input redirection + + +Effects TODO +=============================== + ++ adapt the kcontrol module used by Kompmgr + - in kcmkwin/kwinoptions +! - uses ~/.xcompmgr, convert to use normal KConfig +? - 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 ++ - all effects from the Opacity tab should be already doable +! - applying translucency only to the decoration + - use clientSize() and clientPos() from Client + - see also the alpha clear hack todo entry +! - not usign ARGB visuals + - 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) ++ - 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 + - Client::animateMinimizeOrUnminimize() + - Client::setShade() + ++ zoom effect + - enlarge a portion of the screen +! - would require adding xScale/yScale to ScreenPaintData + - should be doable even for XRender + +? other effects diff --git a/composite.cpp b/composite.cpp index e3ad68ac5e..3aecc54f4e 100644 --- a/composite.cpp +++ b/composite.cpp @@ -8,6 +8,23 @@ You can Freely distribute this program under the GNU General Public License. See the file "COPYING" for the exact licensing terms. ******************************************************************/ +/* + Code related to compositing (redirecting windows to pixmaps and tracking + window damage). + + Docs: + + XComposite (the protocol, but the function calls map to it): + http://gitweb.freedesktop.org/?p=xorg/proto/compositeproto.git;a=blob;hb=HEAD;f=protocol + + XDamage (again the protocol): + http://gitweb.freedesktop.org/?p=xorg/proto/damageproto.git;a=blob;hb=HEAD;f=protocol + + Composite HOWTO from Fredrik: + http://ktown.kde.org/~fredrik/composite_howto.html + +*/ + #include "utils.h" #include "workspace.h" #include "client.h" @@ -125,7 +142,7 @@ void Workspace::addDamageFull() damage_region = QRegion( 0, 0, displayWidth(), displayHeight()); } -void Workspace::compositeTimeout() +void Workspace::performCompositing() { // The event loop apparently tries to fire a QTimer as often as possible, even // at the expense of not processing many X events. This means that the composite @@ -139,6 +156,8 @@ void Workspace::compositeTimeout() scene->idle(); return; } + // create a list of all windows in the stacking order + // TODO keep this list like now a stacking order of Client window is kept ToplevelList windows; Window* children; unsigned int children_count; @@ -156,11 +175,13 @@ void Workspace::compositeTimeout() else if( Unmanaged* c = findUnmanaged( HandleMatchPredicate( children[ i ] ))) windows.append( c ); } - scene->prePaint(); + scene->initPaint(); scene->paint( damage_region, windows ); + // clear all damage damage_region = QRegion(); foreach( Toplevel* c, windows ) c->resetDamage(); + // run post-pass only after clearing the damage scene->postPaint(); lastCompositePaint.start(); } diff --git a/scene.cpp b/scene.cpp index 6868e92c40..3ecd2fbaa8 100644 --- a/scene.cpp +++ b/scene.cpp @@ -8,6 +8,65 @@ You can Freely distribute this program under the GNU General Public License. See the file "COPYING" for the exact licensing terms. ******************************************************************/ +/* + (NOTE: The compositing code is work in progress. As such this design + documentation may get outdated in some areas.) + + The base class for compositing, implementing shared functionality + between the OpenGL and XRender backends. + + Design: + + When compositing is turned on, XComposite extension is used to redirect + drawing of windows to pixmaps and XDamage extension is used to get informed + about damage (changes) to window contents. This code is mostly in composite.cpp . + + Workspace::performCompositing() starts one painting pass. Painting is done + by painting the screen, which in turn paints every window. Painting can be affected + using effects, which are chained. E.g. painting a screen means that actually + paintScreen() of the first effect is called, which possibly does modifications + and calls next effect's paintScreen() and so on, until Scene::finalPaintScreen() + is called. + + There are 3 phases of every paint (not necessarily done together): + The pre-paint phase, the paint phase and the post-paint phase. + + The pre-paint phase is used to find out about how the painting will be actually + done (i.e. what the effects will do). For example when only a part of the screen + needs to be updated and no effect will do any transformation it is possible to use + an optimized paint function. How the painting will be done is controlled + by the mask argument, see PAINT_WINDOW_* and PAINT_SCREEN_* flags in scene.h . + For example an effect that decides to paint a normal windows as translucent + will need to modify the mask in its prePaintWindow() to include + the PAINT_WINDOW_TRANSLUCENT flag. The paintWindow() function will then get + the mask with this flag turned on and will also paint using transparency. + + The paint pass does the actual painting, based on the information collected + using the pre-paint pass. After running through the effects' paintScreen() + either paintGenericScreen() or optimized paintSimpleScreen() are called. + Those call paintWindow() on windows (not necessarily all), possibly using + clipping to optimize performance and calling paintWindow() first with only + PAINT_WINDOW_OPAQUE to paint the opaque parts and then later + with PAINT_WINDOW_TRANSLUCENT to paint the transparent parts. Function + paintWindow() again goes through effects' paintWindow() until + finalPaintWindow() is called, which calls the window's performPaint() to + do the actual painting. + + The post-paint can be used for cleanups and is also used for scheduling + repaints during the next painting pass for animations. Effects wanting to + repaint certain parts can manually damage them during post-paint and repaint + of these parts will be done during the next paint pass. + + + Various notes: + + - When the screen or a window are transformed (*_TRANSFORMED flag), clipping + and similar optimizations are not done (too complicated), so in such cases + infiniteRegion() should be always used. Make sure not to make any transformations + of such regions. + +*/ + #include "scene.h" #include @@ -33,7 +92,7 @@ Scene::~Scene() { } -void Scene::prePaint() +void Scene::initPaint() { effects->startPaint(); // do the rest of prepaint pass together with paint pass @@ -47,43 +106,48 @@ void Scene::paintScreen( int* mask, QRegion* region ) updateTimeDiff(); // preparation step effects->prePaintScreen( mask, region, time_diff ); + // optimized painting is not possible with transformations if( *mask & ( PAINT_SCREEN_TRANSFORMED | PAINT_WINDOW_TRANSFORMED )) *mask &= ~PAINT_SCREEN_REGION; - // TODO call also prePaintWindow() for all windows ScreenPaintData data; effects->paintScreen( *mask, *region, data ); } +// Compute time since the last painting pass. void Scene::updateTimeDiff() { if( last_time.isNull()) { - // has been idle for some time, time_diff would be huge + // Painting has been idle (optimized out) for some time, + // which means time_diff would be huge and would break animations. + // Simply set it to zero. time_diff = 0; } else time_diff = last_time.elapsed(); - if( time_diff < 0 ) + if( time_diff < 0 ) // check time rollback time_diff = 0; last_time.start();; } +// Painting pass is optimized away. void Scene::idle() { + // Don't break time since last paint for the next pass. last_time = QTime(); } // the function that'll be eventually called by paintScreen() above void Scene::finalPaintScreen( int mask, QRegion region, ScreenPaintData& data ) { - if( mask & PAINT_SCREEN_REGION ) + if( mask & PAINT_SCREEN_REGION ) // can do optimized case? paintSimpleScreen( mask, region ); else paintGenericScreen( mask, data ); } -// the generic painting code that should eventually handle even -// transformations +// The generic painting code that can handle even transformations. +// It simply paints bottom-to-top. void Scene::paintGenericScreen( int orig_mask, ScreenPaintData ) { paintBackground( infiniteRegion()); @@ -99,9 +163,13 @@ void Scene::paintGenericScreen( int orig_mask, ScreenPaintData ) } } -// the optimized case without any transformations at all +// The optimized case without any transformations at all. +// It can paint only the requested region and can use clipping +// to reduce painting and improve performance. void Scene::paintSimpleScreen( int orig_mask, QRegion region ) { + // TODO PAINT_WINDOW_* flags don't belong here, that's why it's in the assert, + // perhaps the two enums should be separated assert(( orig_mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED | PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_OPAQUE )) == 0 ); QList< Phase2Data > phase2; @@ -120,12 +188,15 @@ void Scene::paintSimpleScreen( int orig_mask, QRegion region ) QRegion damage = region; // preparation step effects->prePaintWindow( w, &mask, &damage, time_diff ); + // 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 )); if( mask & PAINT_WINDOW_OPAQUE ) { paintWindow( w, mask, region ); - if( ( mask & PAINT_WINDOW_TRANSLUCENT ) == 0 ) // window is not transparent, can clip windows below + // 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()); } } @@ -159,25 +230,10 @@ void Scene::postPaint() effects->postPaintScreen(); foreach( Window* w, stacking_order ) effects->postPaintWindow( w ); + // do cleanup stacking_order.clear(); } -void Scene::windowGeometryShapeChanged( Toplevel* ) - { - } - -void Scene::windowOpacityChanged( Toplevel* ) - { - } - -void Scene::windowAdded( Toplevel* ) - { - } - -void Scene::windowDeleted( Toplevel* ) - { - } - //**************************************** // Scene::Window //**************************************** @@ -198,9 +254,13 @@ void Scene::Window::free() void Scene::Window::discardShape() { + // it is created on-demand and cached, simply + // reset the flag shape_valid = false; } +// Find out the shape of the window using the XShape extension +// or if not shape is set then simply it's the window geometry. QRegion Scene::Window::shape() const { if( !shape_valid ) diff --git a/scene.h b/scene.h index c316468d2a..7c8057006e 100644 --- a/scene.h +++ b/scene.h @@ -23,45 +23,73 @@ class Workspace; class WindowPaintData; class ScreenPaintData; +// The base class for compositing backends. class Scene { public: Scene( Workspace* ws ); virtual ~Scene() = 0; class Window; - virtual void prePaint(); - // repaints the given screen areas, windows provides the stacking order + // Called before calling paint() to perform initialization (does not + // do the prepaint pass though) + virtual void initPaint(); + // Repaints the given screen areas, windows provides the stacking order. + // The entry point for the main part of the painting pass. virtual void paint( QRegion damage, ToplevelList windows ) = 0; + // Called to perform post paint cleanup and for animations to prepare + // for next pass. virtual void postPaint(); + + // Notification function - KWin core informs about changes. + // Used to mainly discard cached data. + // shape/size of a window changed - virtual void windowGeometryShapeChanged( Toplevel* ); + virtual void windowGeometryShapeChanged( Toplevel* ) = 0; // opacity of a window changed - virtual void windowOpacityChanged( Toplevel* ); + virtual void windowOpacityChanged( Toplevel* ) = 0; // a new window has been created - virtual void windowAdded( Toplevel* ); + virtual void windowAdded( Toplevel* ) = 0; // a window has been destroyed - virtual void windowDeleted( Toplevel* ); + virtual void windowDeleted( Toplevel* ) = 0; + // Flags controlling how painting is done. enum { + // Window (or at least part of it) will be painted opaque. PAINT_WINDOW_OPAQUE = 1 << 0, + // Window (or at least part of it) will be painted translucent. PAINT_WINDOW_TRANSLUCENT = 1 << 1, + // Window will be painted with transformed geometry. PAINT_WINDOW_TRANSFORMED = 1 << 2, + // Paint only a region of the screen (can be optimized, cannot + // be used together with TRANSFORMED flags). PAINT_SCREEN_REGION = 1 << 3, + // Whole screen will be painted with transformed geometry. PAINT_SCREEN_TRANSFORMED = 1 << 4 }; // there's nothing to paint (adjust time_diff later) void idle(); protected: + // shared implementation, starts painting the screen void paintScreen( int* mask, QRegion* region ); friend class EffectsHandler; + // called after all effects had their paintScreen() called void finalPaintScreen( int mask, QRegion region, ScreenPaintData& data ); + // shared implementation of painting the screen in the generic + // (unoptimized) way virtual void paintGenericScreen( int mask, ScreenPaintData data ); + // shared implementation of painting the screen in an optimized way virtual void paintSimpleScreen( int mask, QRegion region ); + // paint the background (not the desktop background - the whole background) virtual void paintBackground( QRegion region ) = 0; + // called after all effects had their paintWindow() called void finalPaintWindow( Window* w, int mask, QRegion region, WindowPaintData& data ); + // shared implementation, starts painting the window virtual void paintWindow( Window* w, int mask, QRegion region ); + // infinite region, i.e. everything static QRegion infiniteRegion(); + // compute time since the last repaint void updateTimeDiff(); + // saved data for 2nd pass of optimized screen painting struct Phase2Data { Phase2Data( Window* w, QRegion r, int m ) : window( w ), region( r ), mask( m ) {} @@ -69,26 +97,36 @@ class Scene QRegion region; int mask; }; + // windows in their stacking order QVector< Window* > stacking_order; + // time since last repaint int time_diff; QTime last_time; Workspace* wspace; }; +// The base class for windows representations in composite backends class Scene::Window { public: Window( Toplevel* c ); virtual ~Window(); - virtual void free(); // is often copied by value, use manually instead of dtor + // this class is often copied by value, use manually instead of dtor + virtual void free(); + // perform the actual painting of the window virtual void performPaint( int mask, QRegion region, WindowPaintData data ) = 0; int x() const; int y() const; int width() const; int height() const; + // access to the internal window class + // TODO eventually get rid of this Toplevel* window(); + // is the window visible at all bool isVisible() const; + // is the window fully opaque bool isOpaque() const; + // shape of the window QRegion shape() const; void discardShape(); Window() {} // QMap sucks even in Qt4 @@ -103,7 +141,7 @@ extern Scene* scene; inline QRegion Scene::infiniteRegion() - { // INT_MIN / 2 because it's width/height (INT_MIN+INT_MAX==-1) + { // INT_MIN / 2 because width/height is used (INT_MIN+INT_MAX==-1) return QRegion( INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX ); } diff --git a/scene_basic.cpp b/scene_basic.cpp index 91846e6dbd..8e135ccc01 100644 --- a/scene_basic.cpp +++ b/scene_basic.cpp @@ -8,6 +8,13 @@ You can Freely distribute this program under the GNU General Public License. See the file "COPYING" for the exact licensing terms. ******************************************************************/ +/* + This is very simple compositing code using only plain X. It doesn't use any effects + or anything like that, it merely draws everything as it would be visible without + compositing. It was the first compositing code in KWin and is usable only for testing + and as the very simple "this is how it works". +*/ + #include "scene_basic.h" #include "utils.h" @@ -16,10 +23,6 @@ License. See the file "COPYING" for the exact licensing terms. namespace KWinInternal { -//**************************************** -// SceneBasic -//**************************************** - SceneBasic::SceneBasic( Workspace* ws ) : Scene( ws ) { @@ -56,9 +59,27 @@ void SceneBasic::paint( QRegion, ToplevelList windows ) XFlush( display()); } +// These functions are not used at all, SceneBasic +// is not using inherited functionality. + void SceneBasic::paintBackground( QRegion ) { - // empty, not using inherited functionality + } + +void SceneBasic::windowGeometryShapeChanged( Toplevel* ) + { + } + +void SceneBasic::windowOpacityChanged( Toplevel* ) + { + } + +void SceneBasic::windowAdded( Toplevel* ) + { + } + +void SceneBasic::windowDeleted( Toplevel* ) + { } } // namespace diff --git a/scene_basic.h b/scene_basic.h index d972fe05a6..61cd5420b0 100644 --- a/scene_basic.h +++ b/scene_basic.h @@ -25,6 +25,10 @@ class SceneBasic virtual void paint( QRegion damage, ToplevelList windows ); protected: virtual void paintBackground( QRegion region ); + virtual void windowGeometryShapeChanged( Toplevel* ); + virtual void windowOpacityChanged( Toplevel* ); + virtual void windowAdded( Toplevel* ); + virtual void windowDeleted( Toplevel* ); }; } // namespace diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 3af7ccd04b..c19b4ceaa1 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -8,8 +8,49 @@ You can Freely distribute this program under the GNU General Public License. See the file "COPYING" for the exact licensing terms. Based on glcompmgr code by Felix Bellaby. +Using code from Compiz and Beryl. ******************************************************************/ +/* + This is the OpenGL-based compositing code. It is the primary and most powerful + compositing backend. + +Sources and other compositing managers: +======================================= + +- http://opengl.org + - documentation + - OpenGL Redbook + - GLX docs + - extensions docs + +- glcompmgr + - http://lists.freedesktop.org/archives/xorg/2006-July/017006.html , + - http://www.mail-archive.com/compiz%40lists.freedesktop.org/msg00023.html + - simple and easy to understand + - works even without texture_from_pixmap extension + - claims to support several different gfx cards + +- compiz + - git clone git://anongit.freedesktop.org/git/xorg/app/compiz + - the ultimate + - glxcompmgr + - git clone git://anongit.freedesktop.org/git/xorg/app/glxcompgr + - a rather old version of compiz, but also simpler and as such simpler + to understand + +- beryl + - the community fork of Compiz + - http://beryl-project.org + - svn co svn://metascape.afraid.org/svnroot/beryl + +- libcm (metacity) + - cvs -d :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome co libcm + - not much idea about it, the model differs a lot from KWin/Compiz/Beryl + - does not seem to be very powerful or with that much development going on + +*/ + #include "scene_opengl.h" #include "utils.h" @@ -25,22 +66,39 @@ namespace KWinInternal // SceneOpenGL //**************************************** +// the config used for windows GLXFBConfig SceneOpenGL::fbcdrawable; +// GLX content GLXContext SceneOpenGL::context; -GLXPixmap SceneOpenGL::glxroot; +// the destination drawable where the compositing is done +GLXDrawable SceneOpenGL::glxroot; bool SceneOpenGL::tfp_mode; // using glXBindTexImageEXT (texture_from_pixmap) bool SceneOpenGL::root_db; // destination drawable is double-buffered bool SceneOpenGL::copy_buffer_hack; // workaround for nvidia < 1.0-9xxx drivers +// finding of OpenGL extensions functions +typedef void (*glXFuncPtr)(); +typedef glXFuncPtr (*glXGetProcAddress_func)( const GLubyte* ); + +static glXFuncPtr getProcAddress( const char* name ) + { + glXFuncPtr ret = NULL; + if( glXGetProcAddress != NULL ) + ret = glXGetProcAddress( ( const GLubyte* ) name ); + if( ret == NULL ) + ret = ( glXFuncPtr ) dlsym( RTLD_DEFAULT, name ); + return ret; + } + +// texture_from_pixmap extension functions typedef void (*glXBindTexImageEXT_func)( Display* dpy, GLXDrawable drawable, int buffer, const int* attrib_list ); typedef void (*glXReleaseTexImageEXT_func)( Display* dpy, GLXDrawable drawable, int buffer ); -typedef void (*glXFuncPtr)(); -typedef glXFuncPtr (*glXGetProcAddress_func)( const GLubyte* ); -glXBindTexImageEXT_func glXBindTexImageEXT; glXReleaseTexImageEXT_func glXReleaseTexImageEXT; glXGetProcAddress_func glXGetProcAddress; +glXBindTexImageEXT_func glXBindTexImageEXT; +// detect OpenGL error (add to various places in code to pinpoint the place) static void checkGLError( const char* txt ) { GLenum err = glGetError(); @@ -48,6 +106,7 @@ static void checkGLError( const char* txt ) kWarning() << "GL error (" << txt << "): 0x" << QString::number( err, 16 ) << endl; } +// attributes for finding a double-buffered root window config const int root_db_attrs[] = { GLX_DOUBLEBUFFER, True, @@ -60,6 +119,7 @@ const int root_db_attrs[] = None }; +// attributes for finding a non-double-buffered root window config static const int root_buffer_attrs[] = { GLX_DOUBLEBUFFER, False, @@ -72,6 +132,7 @@ static const int root_buffer_attrs[] = None }; +// attributes for finding config for windows const int drawable_attrs[] = { GLX_DOUBLEBUFFER, False, @@ -85,6 +146,7 @@ const int drawable_attrs[] = None }; +// attributes for finding config for windows when using tfp const int drawable_tfp_attrs[] = { GLX_DOUBLEBUFFER, False, @@ -99,16 +161,6 @@ const int drawable_tfp_attrs[] = None }; -static glXFuncPtr getProcAddress( const char* name ) - { - glXFuncPtr ret = NULL; - if( glXGetProcAddress != NULL ) - ret = glXGetProcAddress( ( const GLubyte* ) name ); - if( ret == NULL ) - ret = ( glXFuncPtr ) dlsym( RTLD_DEFAULT, name ); - return ret; - } - SceneOpenGL::SceneOpenGL( Workspace* ws ) : Scene( ws ) { @@ -116,6 +168,7 @@ SceneOpenGL::SceneOpenGL( Workspace* ws ) int dummy; if( !glXQueryExtension( display(), &dummy, &dummy )) return; + // handle OpenGL extensions functions glXGetProcAddress = (glXGetProcAddress_func) getProcAddress( "glxGetProcAddress" ); if( glXGetProcAddress == NULL ) glXGetProcAddress = (glXGetProcAddress_func) getProcAddress( "glxGetProcAddressARB" ); @@ -125,7 +178,7 @@ SceneOpenGL::SceneOpenGL( Workspace* ws ) // use copy buffer hack from glcompmgr (called COPY_BUFFER there) - nvidia drivers older than // 1.0-9xxx don't update pixmaps properly, so do a copy first copy_buffer_hack = !tfp_mode; // TODO detect that it's nvidia < 1.0-9xxx driver - initBuffer(); + initBuffer(); // create destination buffer if( tfp_mode ) { if( !findConfig( drawable_tfp_attrs, fbcdrawable )) @@ -140,6 +193,7 @@ SceneOpenGL::SceneOpenGL( Workspace* ws ) assert( false ); context = glXCreateNewContext( display(), fbcroot, GLX_RGBA_TYPE, NULL, GL_FALSE ); glXMakeContextCurrent( display(), glxroot, glxroot, context ); + // OpenGL scene setup glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho( 0, displayWidth(), 0, displayHeight(), 0, 65535 ); @@ -167,6 +221,7 @@ SceneOpenGL::~SceneOpenGL() checkGLError( "Cleanup" ); } +// create destination buffer void SceneOpenGL::initBuffer() { XWindowAttributes attrs; @@ -182,12 +237,14 @@ void SceneOpenGL::initBuffer() } if( root_db ) { + // root window is double-buffered, paint directly to it buffer = rootWindow(); glxroot = glXCreateWindow( display(), fbcroot, buffer, NULL ); glDrawBuffer( GL_BACK ); } else { + // no double-buffered root, paint to a buffer and copy to root window XGCValues gcattr; gcattr.subwindow_mode = IncludeInferiors; gcroot = XCreateGC( display(), rootWindow(), GCSubwindowMode, &gcattr ); @@ -197,6 +254,7 @@ void SceneOpenGL::initBuffer() } } +// print info about found configs static void debugFBConfig( GLXFBConfig* fbconfigs, int i, const int* attrs ) { int pos = 0; @@ -214,6 +272,7 @@ static void debugFBConfig( GLXFBConfig* fbconfigs, int i, const int* attrs ) } } +// find config matching the given attributes and possibly the given X visual bool SceneOpenGL::findConfig( const int* attrs, GLXFBConfig& config, VisualID visual ) { int cnt; @@ -263,6 +322,7 @@ bool SceneOpenGL::findConfig( const int* attrs, GLXFBConfig& config, VisualID vi return false; } +// the entry function for painting void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels ) { foreach( Toplevel* c, toplevels ) @@ -275,10 +335,13 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels ) glPushMatrix(); glClearColor( 0, 0, 0, 1 ); glClear( GL_COLOR_BUFFER_BIT ); + // OpenGL has (0,0) in the bottom-left corner while X has it in the top-left corner, + // which is annoying and confusing. Therefore flip the whole OpenGL scene upside down + // and move it up, so that it actually uses the same coordinate system like X. glScalef( 1, -1, 1 ); glTranslatef( 0, -displayHeight(), 0 ); int mask = 0; - paintScreen( &mask, &damage ); + paintScreen( &mask, &damage ); // call generic implementation glPopMatrix(); // TODO only partial repaint for mask & PAINT_SCREEN_REGION if( root_db ) @@ -296,7 +359,7 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels ) void SceneOpenGL::paintGenericScreen( int mask, ScreenPaintData data ) { if( mask & PAINT_SCREEN_TRANSFORMED ) - { + { // apply screen transformations glPushMatrix(); glTranslatef( data.xTranslate, data.yTranslate, 0 ); } @@ -309,6 +372,7 @@ void SceneOpenGL::paintGenericScreen( int mask, ScreenPaintData data ) void SceneOpenGL::paintSimpleScreen( int mask, QRegion region ) { // TODO repaint only damaged areas (means also don't do glXSwapBuffers and similar) + // For now always force redrawing of the whole area. region = QRegion( 0, 0, displayWidth(), displayHeight()); Scene::paintSimpleScreen( mask, region ); } @@ -376,16 +440,17 @@ void SceneOpenGL::Window::free() discardTexture(); } +// Bind the window pixmap to an OpenGL texture. void SceneOpenGL::Window::bindTexture() { if( texture != 0 && toplevel->damage().isEmpty() - && !tfp_mode ) // interestingly this makes tfp slower + && !tfp_mode ) // TODO interestingly this makes tfp slower with some gfx cards { // texture doesn't need updating, just bind it glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture ); return; } - // TODO cache pixmaps here if possible + // Get the pixmap with the window contents Pixmap window_pix = toplevel->createWindowPixmap(); Pixmap pix = window_pix; // HACK @@ -425,11 +490,11 @@ void SceneOpenGL::Window::bindTexture() glXWaitX(); } if( tfp_mode ) - { + { // tfp mode, simply bind the pixmap to texture if( texture == None ) glGenTextures( 1, &texture ); if( bound_pixmap != None ) - { + { // release old if needed glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT ); glXDestroyGLXPixmap( display(), bound_glxpixmap ); XFreePixmap( display(), bound_pixmap ); @@ -448,7 +513,7 @@ void SceneOpenGL::Window::bindTexture() glXBindTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT, NULL ); } else - { + { // non-tfp case, copy pixmap contents to a texture GLXDrawable pixmap = glXCreatePixmap( display(), fbcdrawable, pix, NULL ); glXMakeContextCurrent( display(), pixmap, pixmap, context ); glReadBuffer( GL_FRONT ); @@ -509,6 +574,8 @@ void SceneOpenGL::Window::discardTexture() texture = 0; } +// paint a quad (rectangle), ty1/ty2 are texture coordinates (for handling +// swapped y coordinate, see below) static void quadPaint( int x1, int y1, int x2, int y2, int ty1, int ty2 ) { glTexCoord2i( x1, ty1 ); @@ -521,8 +588,11 @@ static void quadPaint( int x1, int y1, int x2, int y2, int ty1, int ty2 ) glVertex2i( x1, y2 ); } +// paint the window void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintData data ) { + // check if there is something to paint (e.g. don't paint if the window + // is only opaque and only PAINT_WINDOW_TRANSLUCENT is requested) bool opaque = isOpaque() && data.opacity == 1.0; if( mask & ( PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT )) {} @@ -544,6 +614,7 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat return; bindTexture(); glPushMatrix(); + // do required transformations int x = toplevel->x(); int y = toplevel->y(); if( mask & PAINT_WINDOW_TRANSFORMED ) @@ -554,6 +625,7 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat glTranslatef( x, y, 0 ); if(( mask & PAINT_WINDOW_TRANSFORMED ) && ( data.xScale != 1 || data.yScale != 1 )) glScalef( data.xScale, data.yScale, 1 ); + // setup blending of transparent windows bool was_blend = glIsEnabled( GL_BLEND ); if( !opaque ) { @@ -562,6 +634,8 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat } if( data.opacity != 1.0 ) { + // the window is additionally configured to have its opacity adjusted, + // do it if( toplevel->hasAlpha()) { glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); @@ -580,6 +654,7 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat } } glEnable( GL_TEXTURE_RECTANGLE_ARB ); + // actually paint the window glBegin( GL_QUADS ); foreach( QRect r, region.rects()) { @@ -587,6 +662,8 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat int y2 = r.y() + r.height(); int ty1 = y1; int ty2 = y2; + // tfp can result in the texture having y coordinate inverted (because + // of the internal format), so do the inversion if needed if( !texture_y_inverted ) // "!" because of converting to OpenGL coords { ty1 = height() - y1; diff --git a/scene_opengl.h b/scene_opengl.h index 9a83f8c521..515121e6ad 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -64,9 +64,9 @@ class SceneOpenGL::Window Window() {} // QMap sucks even in Qt4 private: Texture texture; - bool texture_y_inverted; - Pixmap bound_pixmap; - GLXPixmap bound_glxpixmap; // only for tfp_mode + bool texture_y_inverted; // texture has y inverted + Pixmap bound_pixmap; // the pixmap the texture is bound to, only for tfp_mode + GLXPixmap bound_glxpixmap; // the glx pixmap the texture is bound to, only for tfp_mode }; } // namespace diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 9d5d3083ac..2c86d8d8c5 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -8,6 +8,27 @@ You can Freely distribute this program under the GNU General Public License. See the file "COPYING" for the exact licensing terms. ******************************************************************/ +/* + This is the XRender-based compositing code. The primary compositing + backend is the OpenGL-based one, which should be more powerful + and also possibly better documented. This backend is mostly for cases + when the OpenGL backend cannot be used for some reason (insufficient + performance, no usable OpenGL support at all, etc.) + The plan is to keep it around as long as needed/possible, but if it + proves to be too much hassle it will be dropped in the future. + + Docs: + + XRender (the protocol, but the function calls map to it): + http://webcvs.freedesktop.org/xlibs/Render/protocol + (I couldn't find it in the freedesktop git repository, so this one + is a bit older, but it shouldn't matter.) + + XFixes (again, the protocol): + http://gitweb.freedesktop.org/?p=xorg/proto/fixesproto.git;a=blob;hb=HEAD;f=protocol + +*/ + #include "scene_xrender.h" #ifdef HAVE_XRENDER @@ -23,12 +44,13 @@ namespace KWinInternal // SceneXrender //**************************************** +// kDebug() support for the XserverRegion type struct RegionDebug { RegionDebug( XserverRegion r ) : rr( r ) {} XserverRegion rr; }; - + #ifdef NDEBUG inline kndbgstream& operator<<( kndbgstream& stream, RegionDebug ) { return stream; } @@ -55,15 +77,11 @@ ScreenPaintData SceneXrender::screen_paint; SceneXrender::SceneXrender( Workspace* ws ) : Scene( ws ) { + // create XRender picture for the root window format = XRenderFindVisualFormat( display(), DefaultVisual( display(), DefaultScreen( display()))); XRenderPictureAttributes pa; pa.subwindow_mode = IncludeInferiors; front = XRenderCreatePicture( display(), rootWindow(), format, CPSubwindowMode, &pa ); - XRectangle xr; - xr.x = SHRT_MIN / 2; - xr.y = SHRT_MIN / 2; - xr.width = SHRT_MAX; - xr.height = SHRT_MAX; createBuffer(); } @@ -77,6 +95,7 @@ SceneXrender::~SceneXrender() (*it).free(); } +// the entry point for painting void SceneXrender::paint( QRegion damage, ToplevelList toplevels ) { foreach( Toplevel* c, toplevels ) @@ -112,6 +131,7 @@ void SceneXrender::paintGenericScreen( int mask, ScreenPaintData data ) Scene::paintGenericScreen( mask, data ); } +// fill the screen background void SceneXrender::paintBackground( QRegion region ) { if( region != infiniteRegion()) @@ -156,8 +176,8 @@ void SceneXrender::windowAdded( Toplevel* c ) windows[ c ] = Window( c ); } -// TODO handle xrandr changes - +// Create the compositing buffer. The root window is not double-buffered, +// so it is done manually using this buffer, void SceneXrender::createBuffer() { if( buffer != None ) @@ -167,6 +187,9 @@ void SceneXrender::createBuffer() XFreePixmap( display(), pixmap ); // The picture owns the pixmap now } +// Convert QRegion to XserverRegion. This code uses XserverRegion +// only when really necessary as the shared implementation uses +// QRegion. XserverRegion SceneXrender::toXserverRegion( QRegion region ) { QVector< QRect > rects = region.rects(); @@ -204,6 +227,7 @@ void SceneXrender::Window::free() discardShape(); } +// Create XRender picture for the pixmap with the window contents. Picture SceneXrender::Window::picture() { if( !toplevel->damage().isEmpty() && _picture != None ) @@ -213,9 +237,10 @@ Picture SceneXrender::Window::picture() } if( _picture == None && format != NULL ) { + // Get the pixmap with the window contents. Pixmap window_pix = toplevel->createWindowPixmap(); Pixmap pix = window_pix; - // HACK the same like with opengl + // HACK the same alpha clear hack like with opengl, see there Client* c = dynamic_cast< Client* >( toplevel ); bool alpha_clear = c != NULL && c->hasAlpha() && !c->noBorder(); #define ALPHA_CLEAR_COPY @@ -268,6 +293,7 @@ void SceneXrender::Window::discardAlpha() alpha = None; } +// Create XRender picture for the alpha mask. Picture SceneXrender::Window::alphaMask( double opacity ) { if( isOpaque() && opacity == 1.0 ) @@ -285,6 +311,7 @@ Picture SceneXrender::Window::alphaMask( double opacity ) alpha_cached_opacity = 1.0; return None; } + // Create a 1x1 8bpp pixmap containing the given opacity in the alpha channel. Pixmap pixmap = XCreatePixmap( display(), rootWindow(), 1, 1, 8 ); XRenderPictFormat* format = XRenderFindStandardFormat( display(), PictStandardA8 ); XRenderPictureAttributes pa; @@ -298,8 +325,10 @@ Picture SceneXrender::Window::alphaMask( double opacity ) return alpha; } +// paint the window void SceneXrender::Window::performPaint( int mask, QRegion region, WindowPaintData data ) { + // check if there is something to paint bool opaque = isOpaque() && data.opacity == 1.0; if( mask & ( PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT )) {} @@ -319,9 +348,10 @@ void SceneXrender::Window::performPaint( int mask, QRegion region, WindowPaintDa XFixesSetPictureClipRegion( display(), buffer, 0, 0, clip_region ); XFixesDestroyRegion( display(), clip_region ); } - Picture pic = picture(); + Picture pic = picture(); // get XRender picture if( pic == None ) // The render format can be null for GL and/or Xv visuals return; + // do required transformations int x = toplevel->x(); int y = toplevel->y(); if( mask & PAINT_SCREEN_TRANSFORMED ) diff --git a/workspace.cpp b/workspace.cpp index da66f04068..5ed2bb1a67 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -42,6 +42,9 @@ License. See the file "COPYING" for the exact licensing terms. #include "group.h" #include "rules.h" #include "kwinadaptor.h" +#include "unmanaged.h" +#include "scene.h" +#include "effects.h" #include #include @@ -122,7 +125,8 @@ Workspace::Workspace( bool restore ) topmenu_space( NULL ), set_active_client_recursion( 0 ), block_stacking_updates( 0 ), - forced_global_mouse_grab( false ) + forced_global_mouse_grab( false ), + damage_region( None ) { new KWinAdaptor( "org.kde.kwin", "/KWin", QDBusConnection::sessionBus(), this ); @@ -166,10 +170,12 @@ Workspace::Workspace( bool restore ) ColormapChangeMask | SubstructureRedirectMask | SubstructureNotifyMask | - FocusChangeMask // for NotifyDetailNone + FocusChangeMask | // for NotifyDetailNone + ExposureMask ); - Shape::init(); + Extensions::init(); + setupCompositing(); // compatibility long data = 1; @@ -318,6 +324,7 @@ void Workspace::init() connect(&reconfigureTimer, SIGNAL(timeout()), this, SLOT(slotReconfigure())); connect( &updateToolWindowsTimer, SIGNAL( timeout()), this, SLOT( slotUpdateToolWindows())); + connect( &compositeTimer, SIGNAL( timeout()), SLOT( performCompositing())); connect(KGlobalSettings::self(), SIGNAL(appearanceChanged()), this, SLOT(slotReconfigure())); @@ -355,7 +362,11 @@ void Workspace::init() XWindowAttributes attr; XGetWindowAttributes(display(), wins[i], &attr); if (attr.override_redirect ) + { + if( attr.map_state != IsUnmapped && attr.c_class != InputOnly && compositing()) + createUnmanaged( wins[ i ] ); continue; + } if( topmenu_space && topmenu_space->winId() == wins[ i ] ) continue; if (attr.map_state != IsUnmapped) @@ -418,6 +429,7 @@ void Workspace::init() Workspace::~Workspace() { + finishCompositing(); blockStackingUpdates( true ); // TODO grabXServer(); // use stacking_order, so that kwin --replace keeps stacking order @@ -429,6 +441,10 @@ Workspace::~Workspace() (*it)->releaseWindow( true ); // no removeClient() is called ! } + for( UnmanagedList::ConstIterator it = unmanaged.begin(); + it != unmanaged.end(); + ++it ) + (*it)->release(); delete desktop_widget; delete tab_box; delete popupinfo; @@ -472,6 +488,26 @@ Client* Workspace::createClient( Window w, bool is_mapped ) return NULL; } addClient( c, Allowed ); + if( scene ) + scene->windowAdded( c ); + if( effects ) + effects->windowAdded( c ); + return c; + } + +Unmanaged* Workspace::createUnmanaged( Window w ) + { + Unmanaged* c = new Unmanaged( this ); + if( !c->track( w )) + { + Unmanaged::deleteUnmanaged( c, Allowed ); + return NULL; + } + addUnmanaged( c, Allowed ); + if( scene ) + scene->windowAdded( c ); + if( effects ) + effects->windowAdded( c ); return c; } @@ -514,6 +550,11 @@ void Workspace::addClient( Client* c, allowed_t ) updateToolWindows( true ); } +void Workspace::addUnmanaged( Unmanaged* c, allowed_t ) + { + unmanaged.append( c ); + } + /* Destroys the client \a c */ @@ -533,6 +574,10 @@ void Workspace::removeClient( Client* c, allowed_t ) Notify::raise( Notify::Delete ); Q_ASSERT( clients.contains( c ) || desktops.contains( c )); + if( scene ) + scene->windowDeleted( c ); + if( effects ) + effects->windowDeleted( c ); clients.removeAll( c ); desktops.removeAll( c ); unconstrained_stacking_order.removeAll( c ); @@ -568,6 +613,16 @@ void Workspace::removeClient( Client* c, allowed_t ) updateClientArea(); } +void Workspace::removeUnmanaged( Unmanaged* c, allowed_t ) + { + assert( unmanaged.contains( c )); + if( scene ) + scene->windowDeleted( c ); + if( effects ) + effects->windowDeleted( c ); + unmanaged.removeAll( c ); + } + void Workspace::updateFocusChains( Client* c, FocusChainChange change ) { if( !c->wantsTabFocus()) // doesn't want tab focus, remove @@ -864,7 +919,7 @@ void Workspace::slotSettingsChanged(int category) /*! Reread settings */ -KWIN_PROCEDURE( CheckBorderSizesProcedure, cl->checkBorderSizes() ); +KWIN_PROCEDURE( CheckBorderSizesProcedure, Client, cl->checkBorderSizes() ); void Workspace::slotReconfigure() { @@ -921,6 +976,11 @@ void Workspace::slotReconfigure() updateTopMenuGeometry(); updateCurrentTopMenu(); } + + if( options->useTranslucency ) + setupCompositing(); + else + finishCompositing(); loadWindowRules(); for( ClientList::Iterator it = clients.begin(); @@ -1622,7 +1682,7 @@ void Workspace::slotGrabWindow() QPixmap snapshot = QPixmap::grabWindow( active_client->frameId() ); //No XShape - no work. - if( Shape::available()) + if( Extensions::shapeAvailable()) { //As the first step, get the mask from XShape. int count, order; @@ -2335,7 +2395,7 @@ void Workspace::helperDialog( const QString& message, const Client* c ) { KAction* action = keys->action( "Window Operations Menu" ); QString shortcut = QString( "%1 (%2)" ).arg( action->text() ) - .arg( action->globalShortcut().seq( 0 ).toString()); + .arg( action->shortcut().seq( 0 ).toString()); args << "--msgbox" << i18n( "You have selected to show a window without its border.\n" "Without the border, you will not be able to enable the border " @@ -2348,7 +2408,7 @@ void Workspace::helperDialog( const QString& message, const Client* c ) { KAction* action = keys->action( "Window Operations Menu" ); QString shortcut = QString( "%1 (%2)" ).arg( action->text() ) - .arg( action->globalShortcut().seq( 0 ).toString()); + .arg( action->shortcut().seq( 0 ).toString()); args << "--msgbox" << i18n( "You have selected to show a window in fullscreen mode.\n" "If the application itself does not have an option to turn the fullscreen " diff --git a/workspace.h b/workspace.h index f42e6b7ebe..f61fdc2ce0 100644 --- a/workspace.h +++ b/workspace.h @@ -420,7 +420,7 @@ class Workspace : public QObject, public KDecorationDefines void setPopupClientOpacity(int v); void resetClientOpacity(); void setTransButtonText(int value); - void compositeTimeout(); + void performCompositing(); protected: bool keyPressMouseEmulation( XKeyEvent& ev );