diff --git a/composite.cpp b/composite.cpp index e964950281..e8cdadd757 100644 --- a/composite.cpp +++ b/composite.cpp @@ -52,10 +52,14 @@ along with this program. If not, see . #include "scene_xrender.h" #include "scene_opengl.h" #include "compositingprefs.h" +#include "notifications.h" #include #include +#include +#include +#include #include #include @@ -193,6 +197,7 @@ void Workspace::setupCompositing() nextPaintReference = QTime::currentTime().addMSecs( -compositeRate ); compositeTimer.setSingleShot( true ); checkCompositeTimer(); + composite_paint_times.clear(); XCompositeRedirectSubwindows( display(), rootWindow(), CompositeRedirectManual ); new EffectsHandlerImpl( scene->compositingType() ); // sets also the 'effects' pointer addRepaintFull(); @@ -269,7 +274,17 @@ void Workspace::lostCMSelection() // for the shortcut void Workspace::slotToggleCompositing() { - compositingSuspended = !compositingSuspended; + suspendCompositing( !compositingSuspended ); + } + +void Workspace::suspendCompositing() + { + suspendCompositing( true ); + } + +void Workspace::suspendCompositing( bool suspend ) + { + compositingSuspended = suspend; finishCompositing(); setupCompositing(); // will do nothing if suspended } @@ -365,6 +380,7 @@ void Workspace::performCompositing() QRegion repaints = repaints_region; // clear all repaints, so that post-pass can add repaints for the next repaint repaints_region = QRegion(); + QTime t = QTime::currentTime(); scene->paint( repaints, windows ); if( scene->waitSyncAvailable()) { @@ -381,6 +397,7 @@ void Workspace::performCompositing() // checkCompositeTime() would restart it again somewhen later, called from functions that // would again add something pending. checkCompositeTimer(); + checkCompositePaintTime( t.elapsed()); lastCompositePaint.start(); #endif } @@ -428,6 +445,35 @@ bool Workspace::createOverlay() #endif } +void Workspace::checkCompositePaintTime( int msec ) + { + if( options->disableCompositingChecks ) + return; + composite_paint_times.enqueue( msec ); + if( composite_paint_times.count() > 3 ) + composite_paint_times.dequeue(); + if( composite_paint_times.count() < 3 ) + return; + // If last 3 paints were way too slow, disable and warn. + // 1 second seems reasonable, it's not that difficult to get relatively high times + // with high system load. + const int MAX_TIME = 1000; + if( composite_paint_times[ 0 ] > MAX_TIME && composite_paint_times[ 1 ] > MAX_TIME + && composite_paint_times[ 2 ] > MAX_TIME ) + { + kDebug( 1212 ) << "Too long paint times, suspending"; + QTimer::singleShot( 0, this, SLOT( suspendCompositing())); + QString shortcut = i18n( "Empty" ); + if( KAction* action = qobject_cast( keys->action("Suspend Compositing"))) + shortcut = action->globalShortcut().primary().toString(); + QString message = i18n( "Compositing was too slow and has been suspended.\n" + "If this was only a temporary problem, you can resume using the '%1' shortcut.\n" + "You can also disable functionality checks in advanced compositing settings.", shortcut ); + Notify::raise( Notify::CompositingSlow, message ); + compositeTimer.start( 1000 ); // so that it doesn't trigger sooner than suspendCompositing() + } + } + void Workspace::setupOverlay( Window w ) { assert( overlay != None ); diff --git a/kwin.notifyrc b/kwin.notifyrc index c77ee8e5a3..b763aa374c 100644 --- a/kwin.notifyrc +++ b/kwin.notifyrc @@ -5485,3 +5485,7 @@ Comment[x-test]=xxA window on an inactive virtual desktop demands attentionxx Comment[zh_CN]=未激活的虚拟桌面上的窗口请求注意 Comment[zh_TW]=在其他虛擬桌面上的視窗要求注意 +[Event/compositingslow] +Name=Compositing Performance Is Slow +Comment=The compositing performance was too slow and compositing has been suspended +Action=Popup diff --git a/notifications.cpp b/notifications.cpp index 149df1880c..a45e85d9c7 100644 --- a/notifications.cpp +++ b/notifications.cpp @@ -27,9 +27,16 @@ along with this program. If not, see . namespace KWin { -QString Notify::eventToName( Event e ) +static bool forgetIt = false; +QList< Notify::EventData > Notify::pending_events; + +bool Notify::raise( Event e, const QString& message, Client* c ) { + if ( forgetIt ) + return false; // no connection was possible, don't try each time + QString event; + KNotification::NotificationFlags flags = KNotification::CloseOnTimeout; switch ( e ) { case Activate: @@ -92,6 +99,10 @@ QString Notify::eventToName( Event e ) case DemandAttentionOther: event = "demandsattentionother"; break; + case CompositingSlow: + event = "compositingslow"; + flags = KNotification::Persistent; + break; default: if ((e > DesktopChange) && (e <= DesktopChange+20)) { @@ -99,18 +110,6 @@ QString Notify::eventToName( Event e ) } break; } - return event; - } - -static bool forgetIt = false; -QList< Notify::EventData > Notify::pending_events; - -bool Notify::raise( Event e, const QString& message, Client* c ) - { - if ( forgetIt ) - return false; // no connection was possible, don't try each time - - QString event = eventToName( e ); if ( event.isNull() ) return false; @@ -124,12 +123,13 @@ bool Notify::raise( Event e, const QString& message, Client* c ) data.event = event; data.message = message; data.window = c ? c->window() : 0; + data.flags = flags; pending_events.append( data ); return true; } - return KNotification::event( event, message /*, QPixmap() , c ? c->window() : 0*/ ); //FIXME get the widget ? + return KNotification::event( event, message, QPixmap(), NULL /* TODO c ? c->window() : 0*/, flags ); } void Notify::sendPendingEvents() @@ -139,7 +139,7 @@ void Notify::sendPendingEvents() EventData data = pending_events.first(); pending_events.pop_front(); if( !forgetIt ) - KNotification::event( data.event, data.message /* , QPixmap() , data.window */ ); + KNotification::event( data.event, data.message, QPixmap(), NULL /* TODO data.window*/, data.flags ); } } diff --git a/notifications.h b/notifications.h index 6fdf78cc0b..5d7c3b0c62 100644 --- a/notifications.h +++ b/notifications.h @@ -22,6 +22,7 @@ along with this program. If not, see . #ifndef KWIN_NOTIFICATIONS_H #define KWIN_NOTIFICATIONS_H +#include #include #include #include @@ -57,18 +58,19 @@ class Notify ResizeEnd, DemandAttentionCurrent, DemandAttentionOther, + CompositingSlow, DesktopChange = 100 }; static bool raise( Event, const QString& message = QString(), Client* c = NULL ); static void sendPendingEvents(); private: - static QString eventToName( Event ); struct EventData { QString event; QString message; long window; + KNotification::NotificationFlags flags; }; static QList< EventData > pending_events; }; diff --git a/workspace.h b/workspace.h index 9ee48985ea..906ad163c9 100644 --- a/workspace.h +++ b/workspace.h @@ -30,6 +30,7 @@ along with this program. If not, see . #include #include #include +#include #include "utils.h" #include "kdecoration.h" @@ -472,6 +473,8 @@ class Workspace : public QObject, public KDecorationDefines void slotToggleCompositing(); void updateClientArea(); + void suspendCompositing(); + void suspendCompositing( bool suspend ); private slots: void desktopPopupAboutToShow(); @@ -577,6 +580,7 @@ class Workspace : public QObject, public KDecorationDefines void finishCompositing(); bool windowRepaintsPending() const; void setCompositeTimer(); + void checkCompositePaintTime( int msec ); int current_desktop; int number_of_desktops; @@ -749,6 +753,7 @@ class Workspace : public QObject, public KDecorationDefines QPushButton *transButton; QTimer unredirectTimer; bool forceUnredirectCheck; + QQueue< int > composite_paint_times; private: friend bool performTransiencyCheck();