diff --git a/kwin/kcmkwin/kwincompositing/dbus.h b/kwin/kcmkwin/kwincompositing/dbus.h
new file mode 100644
index 0000000..05f5d23
--- /dev/null
+++ b/kwin/kcmkwin/kwincompositing/dbus.h
@@ -0,0 +1,46 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2012 Thomas Lübking <thomas.luebking@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+
+#ifndef MAIN_ADAPTOR_H
+#define MAIN_ADAPTOR_H
+
+#include <QtDBus/QDBusAbstractAdaptor>
+#include "main.h"
+
+namespace KWin
+{
+class MainAdaptor : public QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "org.kde.kwinCompositingDialog")
+
+private:
+ KWinCompositingConfig *m_config;
+
+public:
+ MainAdaptor(KWinCompositingConfig *config) : QDBusAbstractAdaptor(config), m_config(config) { }
+
+public slots:
+ Q_NOREPLY void warn(QString message, QString details, QString dontAgainKey) {
+ m_config->warn(message, details, dontAgainKey);
+ }
+};
+}
+#endif
\ No newline at end of file
diff --git a/kwin/kcmkwin/kwincompositing/main.cpp b/kwin/kcmkwin/kwincompositing/main.cpp
index 6e39479..e802b46 100644
--- a/kwin/kcmkwin/kwincompositing/main.cpp
+++ b/kwin/kcmkwin/kwincompositing/main.cpp
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "main.h"
+#include "dbus.h"
#include "kwin_interface.h"
#include "kwinglobals.h"
@@ -76,13 +77,17 @@ ConfirmDialog::ConfirmDialog() :
}
-KWinCompositingConfig::KWinCompositingConfig(QWidget *parent, const QVariantList &)
+KWinCompositingConfig::KWinCompositingConfig(QWidget *parent, const QVariantList &args)
: KCModule(KWinCompositingConfigFactory::componentData(), parent)
, mKWinConfig(KSharedConfig::openConfig("kwinrc"))
, m_showConfirmDialog(false)
, m_showDetailedErrors(new QAction(i18nc("Action to open a dialog showing detailed information why an effect could not be loaded",
"Details"), this))
+ , m_dontShowAgain(new QAction(i18nc("Prevent warning from bein displayed again", "Don't show again!"), this))
{
+ QDBusConnection::sessionBus().registerService("org.kde.kwinCompositingDialog");
+ QDBusConnection::sessionBus().registerObject("/CompositorSettings", this);
+ new MainAdaptor(this);
KGlobal::locale()->insertCatalog("kwin_effects");
ui.setupUi(this);
layout()->setMargin(0);
@@ -90,9 +95,34 @@ KWinCompositingConfig::KWinCompositingConfig(QWidget *parent, const QVariantList
ui.tabWidget->setCurrentIndex(0);
ui.statusTitleWidget->hide();
ui.rearmGlSupport->hide();
- ui.messageBox->setVisible(false);
- ui.messageBox->addAction(m_showDetailedErrors);
ui.messageBox->setMessageType(KMessageWidget::Warning);
+ ui.messageBox->addAction(m_dontShowAgain);
+ foreach (QWidget *w, m_dontShowAgain->associatedWidgets())
+ w->setVisible(false);
+ ui.messageBox->addAction(m_showDetailedErrors);
+
+ bool showMessage = false;
+ QString message, details, dontAgainKey;
+ if (args.count() > 1) {
+ for (int i = 0; i < args.count() - 1; ++i) {
+ if (args.at(i).toString() == "warn") {
+ showMessage = true;
+ message = QString::fromLocal8Bit(QByteArray::fromBase64(args.at(i+1).toByteArray()));
+ } else if (args.at(i).toString() == "details") {
+ showMessage = true;
+ details = QString::fromLocal8Bit(QByteArray::fromBase64(args.at(i+1).toByteArray()));
+ } else if (args.at(i).toString() == "dontagain") {
+ showMessage = true;
+ dontAgainKey = args.at(i+1).toString();
+ }
+ }
+ }
+
+ if (showMessage) {
+ ui.messageBox->setVisible(showMessage); // first show, animation is broken on init
+ warn(message, details, dontAgainKey);
+ } else
+ ui.messageBox->setVisible(false);
ui.ghns->setIcon(KIcon("get-hot-new-stuff"));
// For future use
@@ -133,6 +163,7 @@ KWinCompositingConfig::KWinCompositingConfig(QWidget *parent, const QVariantList
connect(ui.glShaders, SIGNAL(toggled(bool)), this, SLOT(changed()));
connect(ui.glColorCorrection, SIGNAL(toggled(bool)), this, SLOT(changed()));
connect(m_showDetailedErrors, SIGNAL(triggered(bool)), SLOT(showDetailedEffectLoadingInformation()));
+ connect(m_dontShowAgain, SIGNAL(triggered(bool)), SLOT(blockFutureWarnings()));
connect(ui.ghns, SIGNAL(clicked(bool)), SLOT(slotGHNS()));
// Open the temporary config file
@@ -615,10 +646,15 @@ void KWinCompositingConfig::checkLoadedEffects()
}
if (!disabledEffects.isEmpty()) {
m_showDetailedErrors->setData(disabledEffects);
+ foreach (QWidget *w, m_showDetailedErrors->associatedWidgets())
+ w->setVisible(true);
ui.messageBox->setText(i18ncp("Error Message shown when a desktop effect could not be loaded",
"One desktop effect could not be loaded.",
"%1 desktop effects could not be loaded.", disabledEffects.count()));
ui.messageBox->animatedShow();
+ } else {
+ foreach (QWidget *w, m_showDetailedErrors->associatedWidgets())
+ w->setVisible(false);
}
}
}
@@ -653,7 +689,9 @@ void KWinCompositingConfig::showDetailedEffectLoadingInformation()
label->setOpenExternalLinks(true);
vboxLayout->addWidget(titleWidget);
vboxLayout->addWidget(label);
- if (compositingType != "none") {
+ if (!m_externErrorDetails.isNull()) {
+ label->setText(m_externErrorDetails);
+ } else if (compositingType != "none") {
QString text;
if (disabledEffects.count() > 1) {
text = "<ul>";
@@ -716,6 +754,31 @@ void KWinCompositingConfig::showDetailedEffectLoadingInformation()
dialog->show();
}
+void KWinCompositingConfig::warn(QString message, QString details, QString dontAgainKey)
+{
+ ui.messageBox->setText(message);
+ m_dontShowAgain->setData(dontAgainKey);
+ foreach (QWidget *w, m_dontShowAgain->associatedWidgets())
+ w->setVisible(!dontAgainKey.isEmpty());
+ m_externErrorDetails = details.isNull() ? "" : details;
+ foreach (QWidget *w, m_showDetailedErrors->associatedWidgets())
+ w->setVisible(!m_externErrorDetails.isEmpty());
+ ui.messageBox->animatedShow();
+}
+
+void KWinCompositingConfig::blockFutureWarnings() {
+ QString key;
+ if (QAction *act = qobject_cast<QAction*>(sender()))
+ key = act->data().toString();
+ if (key.isEmpty())
+ return;
+ QStringList l = key.split(':', QString::SkipEmptyParts);
+ KConfig cfg(l.count() > 1 ? l.at(0) : "kwin_dialogsrc");
+ KConfigGroup(&cfg, "Notification Messages").writeEntry(l.last(), false);
+ cfg.sync();
+ ui.messageBox->animatedHide();
+}
+
void KWinCompositingConfig::configChanged(bool reinitCompositing)
{
// Send signal to kwin
@@ -779,4 +842,5 @@ void KWinCompositingConfig::slotGHNS()
} // namespace
+#include "dbus.moc"
#include "main.moc"
diff --git a/kwin/kcmkwin/kwincompositing/main.h b/kwin/kcmkwin/kwincompositing/main.h
index 35079c3..d806531 100644
--- a/kwin/kcmkwin/kwincompositing/main.h
+++ b/kwin/kcmkwin/kwincompositing/main.h
@@ -74,6 +74,8 @@ public slots:
void configChanged(bool reinitCompositing);
void initEffectSelector();
+ void warn(QString message, QString details, QString dontAgainKey);
+
private slots:
void confirmReInit() { showConfirmDialog(true); }
void rearmGlSupport();
@@ -82,6 +84,7 @@ private slots:
void toggleEffectShortcutChanged(const QKeySequence &seq);
void updateStatusUI(bool compositingIsPossible);
void showDetailedEffectLoadingInformation();
+ void blockFutureWarnings();
void slotGHNS();
private:
@@ -97,6 +100,8 @@ private:
KActionCollection* m_actionCollection;
QString originalGraphicsSystem;
QAction *m_showDetailedErrors;
+ QAction *m_dontShowAgain;
+ QString m_externErrorDetails;
};
} // namespace
diff --git a/kwin/scene_opengl.cpp b/kwin/scene_opengl.cpp
index 6cf62c6..7df85ce 100644
--- a/kwin/scene_opengl.cpp
+++ b/kwin/scene_opengl.cpp
@@ -97,11 +97,18 @@ Sources and other compositing managers:
#include <X11/extensions/Xcomposite.h>
#include <qpainter.h>
+#include <QDBusConnection>
+#include <QDBusConnectionInterface>
+#include <QDBusInterface>
#include <QDesktopWidget>
+#include <QStringList>
#include <QVector2D>
#include <QVector4D>
#include <QMatrix4x4>
+#include <KLocale>
+#include <KProcess>
+
namespace KWin
{
@@ -152,6 +159,8 @@ SceneOpenGL::SceneOpenGL(Workspace* ws, OpenGLBackend *backend)
init_ok = false;
return;
}
+ if (!viewportLimitsMatched(QSize(displayWidth(), displayHeight())))
+ return;
// perform Scene specific checks
GLPlatform *glPlatform = GLPlatform::instance();
@@ -434,8 +443,75 @@ SceneOpenGL::Texture *SceneOpenGL::createTexture(const QPixmap &pix, GLenum targ
return new Texture(m_backend, pix, target);
}
+bool SceneOpenGL::viewportLimitsMatched(const QSize &size) const {
+ GLint limit[2];
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, limit);
+ if (limit[0] < size.width() || limit[1] < size.height()) {
+ QMetaObject::invokeMethod(Compositor::self(), "suspend",
+ Qt::QueuedConnection);
+ const QString message = i18n("<h1>OpenGL desktop effects not possible</h1>"
+ "Your system cannot perform OpenGL Desktop Effects at the "
+ "current resolution<br><br>"
+ "You can try to select the XRender backend , but it "
+ "might be very slow for this resolution as well.<br>"
+ "Alternatively, lower the combined resolution of all screens "
+ "to %1x%2 ", limit[0], limit[1]);
+ const QString details = i18n("The demanded resolution exceeds the GL_MAX_VIEWPORT_DIMS "
+ "limitation of your GPU and is therefore not compatible "
+ "with the OpenGL compositor.<br>"
+ "XRender does not know such limitation, but the performance "
+ "will usually be impacted by the hardware limitations that"
+ "restrict the OpenGL viewport size.");
+ const int oldTimeout = QDBusConnection::sessionBus().interface()->timeout();
+ QDBusConnection::sessionBus().interface()->setTimeout(500);
+ if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kwinCompositingDialog").value()) {
+ QDBusInterface dialog( "org.kde.kwinCompositingDialog", "/CompositorSettings", "org.kde.kwinCompositingDialog" );
+ dialog.asyncCall("warn", message, details, "");
+ } else {
+ const QString args = "warn " + message.toLocal8Bit().toBase64() + " details " + details.toLocal8Bit().toBase64();
+ KProcess::startDetached("kcmshell4", QStringList() << "kwincompositing" << "--args" << args);
+ }
+ QDBusConnection::sessionBus().interface()->setTimeout(oldTimeout);
+ return false;
+ }
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, limit);
+ if (limit[0] < size.width() || limit[0] < size.height()) {
+ KConfig cfg("kwin_dialogsrc");
+
+ if (!KConfigGroup(&cfg, "Notification Messages").readEntry("max_tex_warning", true))
+ return true;
+
+ const QString message = i18n("<h1>OpenGL desktop effects might be unusable</h1>"
+ "OpenGL Desktop Effects at the current resolution are supported "
+ "but might be exceptionally slow.<br>"
+ "Also large windows will turn entirely black.<br><br>"
+ "Consider to suspend compositing, switch to the XRender backend "
+ "or lower the resolution to %1x%1." , limit[0]);
+ const QString details = i18n("The demanded resolution exceeds the GL_MAX_TEXTURE_SIZE "
+ "limitation of your GPU, thus windows of that size cannot be "
+ "assigned to textures and will be entirely black.<br>"
+ "Also this limit will often be a performance level barrier despite "
+ "below GL_MAX_VIEWPORT_DIMS, because the driver might fall back to "
+ "software rendering in this case.");
+ const int oldTimeout = QDBusConnection::sessionBus().interface()->timeout();
+ QDBusConnection::sessionBus().interface()->setTimeout(500);
+ if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kwinCompositingDialog").value()) {
+ QDBusInterface dialog( "org.kde.kwinCompositingDialog", "/CompositorSettings", "org.kde.kwinCompositingDialog" );
+ dialog.asyncCall("warn", message, details, "kwin_dialogsrc:max_tex_warning");
+ } else {
+ const QString args = "warn " + message.toLocal8Bit().toBase64() + " details " +
+ details.toLocal8Bit().toBase64() + " dontagain kwin_dialogsrc:max_tex_warning";
+ KProcess::startDetached("kcmshell4", QStringList() << "kwincompositing" << "--args" << args);
+ }
+ QDBusConnection::sessionBus().interface()->setTimeout(oldTimeout);
+ }
+ return true;
+}
+
void SceneOpenGL::screenGeometryChanged(const QSize &size)
{
+ if (!viewportLimitsMatched(size))
+ return;
Scene::screenGeometryChanged(size);
glViewport(0,0, size.width(), size.height());
m_backend->screenGeometryChanged(size);
diff --git a/kwin/scene_opengl.h b/kwin/scene_opengl.h
index e6142c0..c10c611 100644
--- a/kwin/scene_opengl.h
+++ b/kwin/scene_opengl.h
@@ -79,6 +79,8 @@ public Q_SLOTS:
protected:
bool init_ok;
private:
+ bool viewportLimitsMatched(const QSize &size) const;
+private:
QHash< Toplevel*, Window* > windows;
bool debug;
OpenGLBackend *m_backend;