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();