diff --git a/kcmkwin/kwincompositing/dbus.h b/kcmkwin/kwincompositing/dbus.h new file mode 100644 index 0000000000..05f5d23e8d --- /dev/null +++ b/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 + +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 . +*********************************************************************/ + +#ifndef MAIN_ADAPTOR_H +#define MAIN_ADAPTOR_H + +#include +#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/kcmkwin/kwincompositing/main.cpp b/kcmkwin/kwincompositing/main.cpp index 6e39479780..e802b4624c 100644 --- a/kcmkwin/kwincompositing/main.cpp +++ b/kcmkwin/kwincompositing/main.cpp @@ -19,6 +19,7 @@ along with this program. If not, see . *********************************************************************/ #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 = "
    "; @@ -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(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/kcmkwin/kwincompositing/main.h b/kcmkwin/kwincompositing/main.h index 35079c39a4..d806531776 100644 --- a/kcmkwin/kwincompositing/main.h +++ b/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/scene_opengl.cpp b/scene_opengl.cpp index b73e606817..eba3e9b8c3 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -52,11 +52,18 @@ along with this program. If not, see . #include #include +#include +#include +#include #include +#include #include #include #include +#include +#include + namespace KWin { @@ -107,6 +114,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(); @@ -389,8 +398,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, Q_ARG(Compositor::SuspendReason, Compositor::AllReasonSuspend)); + const QString message = i18n("

    OpenGL desktop effects not possible

    " + "Your system cannot perform OpenGL Desktop Effects at the " + "current resolution

    " + "You can try to select the XRender backend , but it " + "might be very slow for this resolution as well.
    " + "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.
    " + "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("

    OpenGL desktop effects might be unusable

    " + "OpenGL Desktop Effects at the current resolution are supported " + "but might be exceptionally slow.
    " + "Also large windows will turn entirely black.

    " + "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.
    " + "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/scene_opengl.h b/scene_opengl.h index 878c26f391..7df71e65c4 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -78,6 +78,8 @@ public Q_SLOTS: virtual void windowClosed(KWin::Toplevel* c, KWin::Deleted* deleted); protected: bool init_ok; +private: + bool viewportLimitsMatched(const QSize &size) const; private: QHash< Toplevel*, Window* > windows; bool debug;