From 6a66250620a86661981e46e589446c031fefc96f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Sun, 3 Dec 2006 13:29:14 +0000 Subject: [PATCH] Better synchronization of refresh rate and vsyncing, patch by Philip Falkner. svn path=/branches/work/kwin_composite/; revision=610110 --- composite.cpp | 13 +++++- scene.cpp | 3 +- scene.h | 2 + scene_opengl.cpp | 10 ++--- workspace.cpp | 111 ++++++++++++++++++++++++++++++++++------------- workspace.h | 1 + 6 files changed, 102 insertions(+), 38 deletions(-) diff --git a/composite.cpp b/composite.cpp index a7cf3a8efb..e0c6d40af6 100644 --- a/composite.cpp +++ b/composite.cpp @@ -107,7 +107,8 @@ void Workspace::setupCompositing() else if( rate > 1000 ) rate = 1000; kDebug( 1212 ) << "Refresh rate " << rate << "Hz" << endl; - compositeTimer.start( 1000 / rate ); + compositeRate = 1000 / rate; + compositeTimer.start( compositeRate ); lastCompositePaint.start(); XCompositeRedirectSubwindows( display(), rootWindow(), CompositeRedirectManual ); if( dynamic_cast< SceneOpenGL* >( scene )) @@ -228,6 +229,16 @@ void Workspace::performCompositing() // clear all damage, so that post-pass can add damage for the next repaint damage_region = QRegion(); scene->paint( damage, windows ); + if( scene->waitSyncAvailable() && options->glVSync ) + { // if we're using vsync, then time the next paint pass to + // before the next available sync + int paintTime = ( lastCompositePaint.elapsed() % compositeRate ) + + ( compositeRate / 2 ); + if( paintTime >= compositeRate ) + compositeTimer.start( paintTime ); + else if( paintTime < compositeRate ) + compositeTimer.start( compositeRate - paintTime ); + } lastCompositePaint.start(); } diff --git a/scene.cpp b/scene.cpp index 285ffb6d10..6dc3ef113d 100644 --- a/scene.cpp +++ b/scene.cpp @@ -84,7 +84,8 @@ namespace KWinInternal Scene* scene; Scene::Scene( Workspace* ws ) - : wspace( ws ) + : wspace( ws ), + has_waitSync( false ) { } diff --git a/scene.h b/scene.h index adb39744fd..558c308cb0 100644 --- a/scene.h +++ b/scene.h @@ -62,6 +62,7 @@ class Scene }; // there's nothing to paint (adjust time_diff later) void idle(); + bool waitSyncAvailable() { return has_waitSync; } protected: // shared implementation, starts painting the screen void paintScreen( int* mask, QRegion* region ); @@ -97,6 +98,7 @@ class Scene int time_diff; QTime last_time; Workspace* wspace; + bool has_waitSync; }; // The base class for windows representations in composite backends diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 4bc082c620..f39cf7c21d 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -175,6 +175,7 @@ SceneOpenGL::SceneOpenGL( Workspace* ws ) initGL(); if( db ) glDrawBuffer( GL_BACK ); + has_waitSync = glXGetVideoSync ? true : false; // Check whether certain features are supported supports_saturation = ((hasGLExtension("GL_ARB_texture_env_crossbar") @@ -456,13 +457,10 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels ) // wait for vblank signal before painting void SceneOpenGL::waitSync() { // NOTE that vsync has no effect with indirect rendering - bool vsync = options->glVSync; - unsigned int sync; - - if( !vsync ) - return; - if( glXGetVideoSync ) + if( waitSyncAvailable() && options->glVSync ) { + unsigned int sync; + glFlush(); glXGetVideoSync( &sync ); glXWaitVideoSync( 2, ( sync + 1 ) % 2, &sync ); diff --git a/workspace.cpp b/workspace.cpp index 3113ceca17..d867ec6e08 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 @@ -93,6 +96,7 @@ Workspace::Workspace( bool restore ) popupinfo (0), popup (0), advanced_popup (0), + trans_popup (0), desk_popup (0), desk_popup_index (0), keys (0), @@ -122,7 +126,13 @@ 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 ), + cm_selection( NULL ), + compositeRate( 0 ), + damage_region( None ), + overlay( None ), + transSlider( NULL ), + transButton( NULL ) { new KWinAdaptor( "org.kde.kwin", "/KWin", QDBusConnection::sessionBus(), this ); @@ -166,10 +176,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 +330,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 +368,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 +435,7 @@ void Workspace::init() Workspace::~Workspace() { + finishCompositing(); blockStackingUpdates( true ); // TODO grabXServer(); // use stacking_order, so that kwin --replace keeps stacking order @@ -429,6 +447,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 +494,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 +558,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 */ @@ -524,7 +573,7 @@ void Workspace::removeClient( Client* c, allowed_t ) if( client_keys_client == c ) setupWindowShortcutDone( false ); - if( !c->shortcut().isEmpty()) + if( !c->shortcut().isNull()) c->setShortcut( QString() ); // remove from client_keys if( c->isDialog()) @@ -533,6 +582,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 +621,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 +656,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 +676,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 +693,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 +927,7 @@ void Workspace::slotSettingsChanged(int category) /*! Reread settings */ -KWIN_PROCEDURE( CheckBorderSizesProcedure, cl->checkBorderSizes() ); +KWIN_PROCEDURE( CheckBorderSizesProcedure, Client, cl->checkBorderSizes() ); void Workspace::slotReconfigure() { @@ -939,6 +984,11 @@ void Workspace::slotReconfigure() updateTopMenuGeometry(); updateCurrentTopMenu(); } + + if( options->useTranslucency ) + setupCompositing(); + else + finishCompositing(); loadWindowRules(); for( ClientList::Iterator it = clients.begin(); @@ -1640,7 +1690,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; @@ -1993,7 +2043,8 @@ void Workspace::createBorderWindows() XSetWindowAttributes attributes; unsigned long valuemask; attributes.override_redirect = True; - attributes.event_mask = ( EnterWindowMask | LeaveWindowMask ); + attributes.event_mask = (EnterWindowMask | LeaveWindowMask | + VisibilityChangeMask); valuemask= (CWOverrideRedirect | CWEventMask | CWCursor ); attributes.cursor = XCreateFontCursor(display(), XC_sb_up_arrow); @@ -2352,7 +2403,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().primary().toString()); + .arg( action->globalShortcut().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 " @@ -2365,7 +2416,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().primary().toString()); + .arg( action->globalShortcut().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 e5e91e354a..8ff7512fca 100644 --- a/workspace.h +++ b/workspace.h @@ -682,6 +682,7 @@ class Workspace : public QObject, public KDecorationDefines KSelectionOwner* cm_selection; QTimer compositeTimer; QTime lastCompositePaint; + int compositeRate; QRegion damage_region; Window overlay; // XComposite overlay window QSlider *transSlider;