From 4110fc1c3a03ffcd500ce7a2266355fc58d9fb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Tue, 7 Nov 2006 22:44:39 +0000 Subject: [PATCH] Support for XComposite overlay window. svn path=/branches/work/kwin_composite/; revision=603137 --- COMPOSITE_TODO | 15 ++----- composite.cpp | 35 +++++++++++++++ events.cpp | 5 +-- scene_opengl.cpp | 111 ++++++++++++++++++++++++++++++----------------- scene_opengl.h | 10 ++--- utils.cpp | 17 ++++---- utils.h | 8 ++++ workspace.cpp | 97 ++++++++++++++++++++++++++++++----------- workspace.h | 68 +++++++++++++++++++++++++---- 9 files changed, 264 insertions(+), 102 deletions(-) diff --git a/COMPOSITE_TODO b/COMPOSITE_TODO index fb182558c2..c161e5eb55 100644 --- a/COMPOSITE_TODO +++ b/COMPOSITE_TODO @@ -49,6 +49,10 @@ General TODO ! - scene_xrender.cpp also requires XFixes ! - check whether it compiles fine without XComposite/XDamage +? XComposite overlay window +? - does it make any sense to use it instead of painting directly to the root window + when the root window's visual etc. are good? + OpenGL TODO ================================= @@ -90,17 +94,6 @@ OpenGL TODO of some #defines like GLX_TEXTURE_FORMAT_EXT - Beryl has this code in beryl.h -! 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 - - 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 - for double-buffered destination drawable, but I haven't been able to test it - - should be only needed for OpenGL code, I think this doesn't matter for XRender - ! improved GLXFBConfig support - it seems a different config for each depth would be needed - from http://lists.freedesktop.org/archives/xorg/2006-July/016859.html and diff --git a/composite.cpp b/composite.cpp index 041f9c2905..b26cd73151 100644 --- a/composite.cpp +++ b/composite.cpp @@ -35,6 +35,8 @@ License. See the file "COPYING" for the exact licensing terms. #include "scene_xrender.h" #include "scene_opengl.h" +#include + namespace KWinInternal { @@ -186,6 +188,39 @@ void Workspace::performCompositing() lastCompositePaint.start(); } +bool Workspace::createOverlay() + { + assert( overlay == None ); + if( !Extensions::compositeOverlayAvailable()) + return false; +#ifdef HAVE_XCOMPOSITE_OVERLAY + overlay = XCompositeGetOverlayWindow( display(), rootWindow()); + if( overlay == None ) + return false; + return true; +#else + return false; +#endif + } + +void Workspace::setupOverlay( Window w ) + { + assert( overlay != None ); + XShapeCombineRectangles( display(), overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted ); + XShapeCombineRectangles( display(), w, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted ); + XMapRaised( display(), overlay ); + } + +void Workspace::destroyOverlay() + { + if( overlay == None ) + return; +#ifdef HAVE_XCOMPOSITE_OVERLAY + XCompositeReleaseOverlayWindow( display(), overlay ); +#endif + overlay = None; + } + //**************************************** // Toplevel //**************************************** diff --git a/events.cpp b/events.cpp index 8ffac14b0e..3e7024c580 100644 --- a/events.cpp +++ b/events.cpp @@ -385,10 +385,7 @@ bool Workspace::workspaceEvent( XEvent * e ) if( c == NULL ) c = createUnmanaged( e->xmap.window ); if( c ) - { - c->windowEvent( e ); - return true; - } + return c->windowEvent( e ); } return ( e->xmap.event != e->xmap.window ); // hide wm typical event from Qt } diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 510fb5144a..613b9680b8 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -74,12 +74,12 @@ namespace KWinInternal // the config used for windows GLXFBConfig SceneOpenGL::fbcdrawable; // GLX content -GLXContext SceneOpenGL::ctxroot; +GLXContext SceneOpenGL::ctxbuffer; GLXContext SceneOpenGL::ctxdrawable; // the destination drawable where the compositing is done -GLXDrawable SceneOpenGL::glxroot; +GLXDrawable SceneOpenGL::glxbuffer; bool SceneOpenGL::tfp_mode; // using glXBindTexImageEXT (texture_from_pixmap) -bool SceneOpenGL::root_db; // destination drawable is double-buffered +bool SceneOpenGL::db; // destination drawable is double-buffered bool SceneOpenGL::copy_buffer_hack; // workaround for nvidia < 1.0-9xxx drivers // finding of OpenGL extensions functions @@ -125,8 +125,21 @@ const int root_db_attrs[] = None }; -// attributes for finding a non-double-buffered root window config -static const int root_buffer_attrs[] = +// attributes for finding a double-buffered destination window config +static const int buffer_db_attrs[] = + { + GLX_CONFIG_CAVEAT, GLX_NONE, + GLX_DOUBLEBUFFER, True, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + None + }; + +// attributes for finding a non-double-buffered destination pixmap config +static const int buffer_nondb_attrs[] = { GLX_CONFIG_CAVEAT, GLX_NONE, GLX_DOUBLEBUFFER, False, @@ -189,19 +202,21 @@ SceneOpenGL::SceneOpenGL( Workspace* ws ) initBuffer(); // create destination buffer if( tfp_mode ) { - if( !findConfig( drawable_tfp_attrs, fbcdrawable )) + if( !findConfig( drawable_tfp_attrs, &fbcdrawable )) { tfp_mode = false; - if( !findConfig( drawable_attrs, fbcdrawable )) + if( !findConfig( drawable_attrs, &fbcdrawable )) assert( false ); } } else - if( !findConfig( drawable_attrs, fbcdrawable )) + if( !findConfig( drawable_attrs, &fbcdrawable )) assert( false ); - ctxroot = glXCreateNewContext( display(), fbcroot, GLX_RGBA_TYPE, NULL, GL_FALSE ); - ctxdrawable = glXCreateNewContext( display(), fbcdrawable, GLX_RGBA_TYPE, ctxroot, GL_FALSE ); - glXMakeContextCurrent( display(), glxroot, glxroot, ctxroot ); + ctxbuffer = glXCreateNewContext( display(), fbcbuffer, GLX_RGBA_TYPE, NULL, GL_FALSE ); + ctxdrawable = glXCreateNewContext( display(), fbcdrawable, GLX_RGBA_TYPE, ctxbuffer, GL_FALSE ); + glXMakeContextCurrent( display(), glxbuffer, glxbuffer, ctxbuffer ); + if( db ) + glDrawBuffer( GL_BACK ); // OpenGL scene setup glMatrixMode( GL_PROJECTION ); glLoadIdentity(); @@ -209,7 +224,7 @@ SceneOpenGL::SceneOpenGL( Workspace* ws ) glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); checkGLError( "Init" ); - kDebug() << "Root DB:" << root_db << ", TFP:" << tfp_mode << endl; + kDebug() << "DB:" << db << ", TFP:" << tfp_mode << endl; } SceneOpenGL::~SceneOpenGL() @@ -218,15 +233,22 @@ SceneOpenGL::~SceneOpenGL() it != windows.end(); ++it ) (*it).free(); - if( root_db ) - glXDestroyWindow( display(), glxroot ); + // do cleanup after initBuffer() + if( buffer == rootWindow()) + glXDestroyWindow( display(), glxbuffer ); + else if( wspace->overlayWindow()) + { + glXDestroyWindow( display(), glxbuffer ); + XDestroyWindow( display(), buffer ); + wspace->destroyOverlay(); + } else { - glXDestroyPixmap( display(), glxroot ); + glXDestroyPixmap( display(), glxbuffer ); XFreeGC( display(), gcroot ); XFreePixmap( display(), buffer ); } - glXDestroyContext( display(), ctxroot ); + glXDestroyContext( display(), ctxbuffer ); glXDestroyContext( display(), ctxdrawable ); checkGLError( "Cleanup" ); } @@ -236,32 +258,39 @@ void SceneOpenGL::initBuffer() { XWindowAttributes attrs; XGetWindowAttributes( display(), rootWindow(), &attrs ); - if( findConfig( root_db_attrs, fbcroot, XVisualIDFromVisual( attrs.visual ))) - root_db = true; - else - { - if( findConfig( root_buffer_attrs, fbcroot )) - root_db = false; - else - assert( false ); - } - if( root_db ) + if( findConfig( root_db_attrs, &fbcbuffer, XVisualIDFromVisual( attrs.visual ))) { // root window is double-buffered, paint directly to it + // TODO no need to use overlay? + db = true; buffer = rootWindow(); - glxroot = glXCreateWindow( display(), fbcroot, buffer, NULL ); - glDrawBuffer( GL_BACK ); + glxbuffer = glXCreateWindow( display(), fbcbuffer, buffer, NULL ); } - else - { - // no double-buffered root, paint to a buffer and copy to root window + else if( findConfig( buffer_db_attrs, &fbcbuffer ) && wspace->createOverlay()) + { // we have overlay, try to create double-buffered window in it + XVisualInfo* visual = glXGetVisualFromFBConfig( display(), fbcbuffer ); + kDebug() << "Using overlay visual 0x" << QString::number( visual->visualid ) << endl; + XSetWindowAttributes attrs; + attrs.colormap = XCreateColormap( display(), rootWindow(), visual->visual, AllocNone ); + buffer = XCreateWindow( display(), wspace->overlayWindow(), 0, 0, displayWidth(), displayHeight(), + 0, QX11Info::appDepth(), InputOutput, visual->visual, CWColormap, &attrs ); + glxbuffer = glXCreateWindow( display(), fbcbuffer, buffer, NULL ); + wspace->setupOverlay( buffer ); + db = true; + XFree( visual ); + } + else if( findConfig( buffer_nondb_attrs, &fbcbuffer )) + { // cannot get any double-buffered drawable, will double-buffer using a pixmap + db = false; XGCValues gcattr; gcattr.subwindow_mode = IncludeInferiors; gcroot = XCreateGC( display(), rootWindow(), GCSubwindowMode, &gcattr ); buffer = XCreatePixmap( display(), rootWindow(), displayWidth(), displayHeight(), QX11Info::appDepth()); - glxroot = glXCreatePixmap( display(), fbcroot, buffer, NULL ); + glxbuffer = glXCreatePixmap( display(), fbcbuffer, buffer, NULL ); } + else + assert( false ); } // print info about found configs @@ -283,7 +312,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 ) +bool SceneOpenGL::findConfig( const int* attrs, GLXFBConfig* config, VisualID visual ) { int cnt; GLXFBConfig* fbconfigs = glXChooseFBConfig( display(), DefaultScreen( display()), @@ -292,7 +321,7 @@ bool SceneOpenGL::findConfig( const int* attrs, GLXFBConfig& config, VisualID vi { if( visual == None ) { - config = fbconfigs[ 0 ]; + *config = fbconfigs[ 0 ]; kDebug() << "Found FBConfig" << endl; debugFBConfig( fbconfigs, 0, attrs ); XFree( fbconfigs ); @@ -309,7 +338,7 @@ bool SceneOpenGL::findConfig( const int* attrs, GLXFBConfig& config, VisualID vi if( value == (int)visual ) { kDebug() << "Found FBConfig" << endl; - config = fbconfigs[ i ]; + *config = fbconfigs[ i ]; debugFBConfig( fbconfigs, i, attrs ); XFree( fbconfigs ); return true; @@ -354,8 +383,12 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels ) paintScreen( &mask, &damage ); // call generic implementation glPopMatrix(); // TODO only partial repaint for mask & PAINT_SCREEN_REGION - if( root_db ) - glXSwapBuffers( display(), glxroot ); + if( db ) + { + glXSwapBuffers( display(), glxbuffer ); + glXWaitGL(); + XFlush( display()); + } else { glFlush(); @@ -561,9 +594,9 @@ void SceneOpenGL::Window::bindTexture() glXWaitGL(); glXDestroyPixmap( display(), pixmap ); XFreePixmap( display(), pix ); - if( root_db ) + if( db ) glDrawBuffer( GL_BACK ); - glXMakeContextCurrent( display(), glxroot, glxroot, ctxroot ); + glXMakeContextCurrent( display(), glxbuffer, glxbuffer, ctxbuffer ); glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture ); } if( copy_buffer ) diff --git a/scene_opengl.h b/scene_opengl.h index 54c4a7d7e8..71f73c62ff 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -37,15 +37,15 @@ class SceneOpenGL virtual void paintBackground( QRegion region ); private: void initBuffer(); - bool findConfig( const int* attrs, GLXFBConfig& config, VisualID visual = None ); + bool findConfig( const int* attrs, GLXFBConfig* config, VisualID visual = None ); typedef GLuint Texture; GC gcroot; Drawable buffer; - GLXFBConfig fbcroot; - static bool root_db; + GLXFBConfig fbcbuffer; + static bool db; static GLXFBConfig fbcdrawable; - static GLXDrawable glxroot; - static GLXContext ctxroot; + static GLXDrawable glxbuffer; + static GLXContext ctxbuffer; static GLXContext ctxdrawable; static bool tfp_mode; static bool copy_buffer_hack; diff --git a/utils.cpp b/utils.cpp index 90dfa66ecb..78244bf1c7 100644 --- a/utils.cpp +++ b/utils.cpp @@ -43,12 +43,13 @@ namespace KWinInternal #ifndef KCMRULES -bool Extensions::has_shape = 0; +bool Extensions::has_shape = false; int Extensions::shape_event_base = 0; -bool Extensions::has_damage = 0; +bool Extensions::has_damage = false; int Extensions::damage_event_base = 0; -bool Extensions::has_composite = 0; -bool Extensions::has_fixes = 0; +bool Extensions::has_composite = false; +bool Extensions::has_composite_overlay = false; +bool Extensions::has_fixes = false; void Extensions::init() { @@ -63,14 +64,14 @@ void Extensions::init() has_composite = XCompositeQueryExtension( display(), &dummy, &dummy ); if( has_composite ) { - int major = 0; - int minor = 2; + int major, minor; XCompositeQueryVersion( display(), &major, &minor ); - if( major == 0 && minor < 2 ) - has_composite = false; + has_composite = ( major > 0 || minor >= 2 ); + has_composite_overlay = ( major > 0 || minor >= 3 ); } #else has_composite = false; + has_composite_overlay = false; #endif #ifdef HAVE_XFIXES has_fixes = XFixesQueryExtension( display(), &dummy, &dummy ); diff --git a/utils.h b/utils.h index 0aa6117f50..5f09639a33 100644 --- a/utils.h +++ b/utils.h @@ -16,12 +16,18 @@ License. See the file "COPYING" for the exact licensing terms. #include #include + #ifdef HAVE_XCOMPOSITE #include +#if XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR >= 3 +#define HAVE_XCOMPOSITE_OVERLAY #endif +#endif + #ifdef HAVE_XDAMAGE #include #endif + #ifdef HAVE_XFIXES #include #endif @@ -148,6 +154,7 @@ class Extensions static bool damageAvailable() { return has_damage; } static int damageNotifyEvent(); static bool compositeAvailable() { return has_composite; } + static bool compositeOverlayAvailable() { return has_composite && has_composite_overlay; } static bool fixesAvailable() { return has_fixes; } static bool hasShape( Window w ); private: @@ -156,6 +163,7 @@ class Extensions static bool has_damage; static int damage_event_base; static bool has_composite; + static bool has_composite_overlay; static bool has_fixes; }; diff --git a/workspace.cpp b/workspace.cpp index 9342c7dae0..24a075d936 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,9 @@ 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 ), + overlay( None ) { new KWinAdaptor( "org.kde.kwin", "/KWin", QDBusConnection::sessionBus(), this ); @@ -166,10 +171,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 +325,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 +363,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 +430,7 @@ void Workspace::init() Workspace::~Workspace() { + finishCompositing(); blockStackingUpdates( true ); // TODO grabXServer(); // use stacking_order, so that kwin --replace keeps stacking order @@ -429,6 +442,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 +489,28 @@ 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 ) + { + if( w == overlay ) + return NULL; + 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 +553,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 +577,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 +616,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 @@ -593,13 +651,7 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change ) focus_chain[ i ].prepend( c ); } else if( !focus_chain[ i ].contains( c )) - { // add it after the active one - if( active_client != NULL && active_client != c - && !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client ) - focus_chain[ i ].insert( focus_chain[ i ].size() - 1, c ); - else - focus_chain[ i ].append( c ); // otherwise add as the first one - } + focus_chain[ i ].prepend( c ); // otherwise add as the last one } } else //now only on desktop, remove it anywhere else @@ -619,13 +671,7 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change ) focus_chain[ i ].prepend( c ); } else if( !focus_chain[ i ].contains( c )) - { // add it after the active one - if( active_client != NULL && active_client != c - && !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client ) - focus_chain[ i ].insert( focus_chain[ i ].size() - 1, c ); - else - focus_chain[ i ].append( c ); // otherwise add as the first one - } + focus_chain[ i ].prepend( c ); } else focus_chain[ i ].removeAll( c ); @@ -642,13 +688,7 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change ) global_focus_chain.prepend( c ); } else if( !global_focus_chain.contains( c )) - { // add it after the active one - if( active_client != NULL && active_client != c - && !global_focus_chain.isEmpty() && global_focus_chain.last() == active_client ) - global_focus_chain.insert( global_focus_chain.size() - 1, c ); - else - global_focus_chain.append( c ); // otherwise add as the first one - } + global_focus_chain.prepend( c ); } void Workspace::updateCurrentTopMenu() @@ -882,7 +922,7 @@ void Workspace::slotSettingsChanged(int category) /*! Reread settings */ -KWIN_PROCEDURE( CheckBorderSizesProcedure, cl->checkBorderSizes() ); +KWIN_PROCEDURE( CheckBorderSizesProcedure, Client, cl->checkBorderSizes() ); void Workspace::slotReconfigure() { @@ -939,6 +979,11 @@ void Workspace::slotReconfigure() updateTopMenuGeometry(); updateCurrentTopMenu(); } + + if( options->useTranslucency ) + setupCompositing(); + else + finishCompositing(); loadWindowRules(); for( ClientList::Iterator it = clients.begin(); @@ -1640,7 +1685,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; diff --git a/workspace.h b/workspace.h index 761c3a5d43..23b5822d01 100644 --- a/workspace.h +++ b/workspace.h @@ -18,6 +18,7 @@ License. See the file "COPYING" for the exact licensing terms. #include #include #include +#include #include "utils.h" #include "kdecoration.h" @@ -77,7 +78,7 @@ class Workspace : public QObject, public KDecorationDefines virtual ~Workspace(); static Workspace * self() { return _self; } - + bool workspaceEvent( XEvent * ); KDecoration* createDecoration( KDecorationBridge* bridge ); @@ -87,6 +88,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; @@ -242,6 +246,9 @@ class Workspace : public QObject, public KDecorationDefines void removeGroup( Group* group, allowed_t ); Group* findClientLeaderGroup( const Client* c ) const; + // only called from Unmanaged::release() + void removeUnmanaged( Unmanaged*, allowed_t ); + bool checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data ); void focusToNull(); // SELI public? @@ -276,6 +283,17 @@ class Workspace : public QObject, public KDecorationDefines void requestDelayFocus( Client* ); void toggleTopDockShadows(bool on); + + void addDamage( const QRect& r ); + void addDamage( int x, int y, int w, int h ); + void addDamageFull(); + // creates XComposite overlay window, cal 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(); @@ -406,11 +424,10 @@ class Workspace : public QObject, public KDecorationDefines void cleanupTemporaryRules(); void writeWindowRules(); void slotBlockShortcuts(int data); - // kompmgr void setPopupClientOpacity(int v); void resetClientOpacity(); void setTransButtonText(int value); - // end + void performCompositing(); protected: bool keyPressMouseEmulation( XKeyEvent& ev ); @@ -458,6 +475,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 ); @@ -499,6 +518,9 @@ class Workspace : public QObject, public KDecorationDefines void closeActivePopup(); void updateClientArea( bool force ); + + void setupCompositing(); + void finishCompositing(); SystemTrayWindowList systemTrayWins; @@ -535,10 +557,11 @@ class Workspace : public QObject, public KDecorationDefines ClientList clients; ClientList desktops; + UnmanagedList unmanaged; - 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; @@ -654,8 +677,10 @@ class Workspace : public QObject, public KDecorationDefines Window null_focus_window; bool forced_global_mouse_grab; friend class StackingUpdatesBlocker; - - //kompmgr + QTimer compositeTimer; + QTime lastCompositePaint; + QRegion damage_region; + Window overlay; // XComposite overlay window QSlider *transSlider; QPushButton *transButton; }; @@ -800,6 +825,11 @@ inline bool Workspace::globalShortcutsDisabled() const return global_shortcuts_disabled || global_shortcuts_disabled_for_client; } +inline Window Workspace::overlayWindow() + { + return overlay; + } + template< typename T > inline Client* Workspace::findClient( T predicate ) { @@ -827,7 +857,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 ));