Show detailed information why an effect cannot be loaded

Effects can specify their minimum requirements in their
desktop file:
* OpenGL
* OpenGL 2 (GLSL required)
* Shaders (either ARB or OpenGL 2)

The configuration module uses this information in combination
with which backend KWin is currently using. So if e.g. OpenGL
is used and an effect requires OpenGL 2 a detailed error
message can be showed that OpenGL 2 is required.

BUG: 209213
FIXED-IN: 4.9.0
REVIEW: 104847
This commit is contained in:
Martin Gräßlin 2012-05-04 11:13:24 +02:00
parent c9c4e020e2
commit d14cf2da92
20 changed files with 195 additions and 24 deletions

View file

@ -556,6 +556,28 @@ bool Workspace::openGLIsBroken() const
return CompositingPrefs::openGlIsBroken();
}
QString Workspace::compositingType()
{
// the returned strings are considered as identifiers and may not be translated
if (!effects) {
return "none";
}
if (effects->compositingType() == XRenderCompositing) {
return "xrender";
} else if (effects->compositingType() == OpenGLCompositing) {
#ifdef KWIN_HAVE_OPENGLES
return "gles";
#else
if (ShaderManager::instance()->isValid()) {
return "gl2";
} else {
return "gl1";
}
#endif
}
return "none";
}
//****************************************
// Toplevel
//****************************************

View file

@ -165,4 +165,5 @@ X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=75
X-KWin-Requires-OpenGL=true
X-KWin-Requires-Shaders=true

View file

@ -149,3 +149,4 @@ X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50
X-KWin-Requires-OpenGL=true

View file

@ -163,3 +163,4 @@ X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50
X-KWin-Requires-OpenGL=true

View file

@ -143,3 +143,4 @@ X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50
X-KWin-Requires-OpenGL=true

View file

@ -162,3 +162,4 @@ X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=70
X-KWin-Requires-OpenGL2=true

View file

@ -145,3 +145,4 @@ X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50
X-KWin-Requires-OpenGL=true

View file

@ -130,3 +130,4 @@ X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50
X-KWin-Requires-OpenGL=true

View file

@ -162,3 +162,4 @@ X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins
X-KWin-Requires-OpenGL2=true

View file

@ -88,3 +88,12 @@ Comment[zh_TW]=KWin 效果
[PropertyDef::X-KDE-Ordering]
Type=int
[PropertyDef::X-KWin-Requires-OpenGL]
Type=bool
[PropertyDef::X-KWin-Requires-OpenGL2]
Type=bool
[PropertyDef::X-KWin-Requires-Shaders]
Type=bool

View file

@ -155,3 +155,4 @@ X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins
X-KWin-Requires-OpenGL2=true

View file

@ -155,3 +155,4 @@ X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50
X-KWin-Requires-OpenGL=true

View file

@ -144,3 +144,4 @@ X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=60
X-KWin-Requires-OpenGL=true

View file

@ -118,3 +118,4 @@ X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-EnabledByDefault=true
X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=90
X-KWin-Requires-OpenGL=true

View file

@ -156,3 +156,4 @@ X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=45
X-KWin-Requires-OpenGL=true

View file

@ -79,6 +79,8 @@ KWinCompositingConfig::KWinCompositingConfig(QWidget *parent, const QVariantList
: 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))
{
KGlobal::locale()->insertCatalog("kwin_effects");
ui.setupUi(this);
@ -86,6 +88,9 @@ 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);
// For future use
(void) I18N_NOOP("Use GLSL shaders");
@ -124,6 +129,7 @@ KWinCompositingConfig::KWinCompositingConfig(QWidget *parent, const QVariantList
connect(ui.glVSync, SIGNAL(toggled(bool)), this, SLOT(changed()));
connect(ui.glShaders, SIGNAL(toggled(bool)), this, SLOT(changed()));
connect(m_showDetailedErrors, SIGNAL(triggered(bool)), SLOT(showDetailedEffectLoadingInformation()));
// Open the temporary config file
// Temporary conf file is used to synchronize effect checkboxes with effect
@ -584,14 +590,15 @@ void KWinCompositingConfig::checkLoadedEffects()
{
// check for effects not supported by Backend or hardware
// such effects are enabled but not returned by DBus method loadedEffects
QDBusMessage message = QDBusMessage::createMethodCall("org.kde.kwin", "/KWin", "org.kde.KWin", "loadedEffects");
QDBusMessage reply = QDBusConnection::sessionBus().call(message);
OrgKdeKWinInterface kwin("org.kde.kwin", "/KWin", QDBusConnection::sessionBus());
KConfigGroup effectConfig = KConfigGroup(mKWinConfig, "Compositing");
bool enabledAfter = effectConfig.readEntry("Enabled", true);
if (reply.type() == QDBusMessage::ReplyMessage && enabledAfter && !getenv("KDE_FAILSAFE")) {
QDBusPendingReply< QStringList > reply = kwin.loadedEffects();
if (!reply.isError() && enabledAfter && !getenv("KDE_FAILSAFE")) {
effectConfig = KConfigGroup(mKWinConfig, "Plugins");
QStringList loadedEffects = reply.arguments()[0].toStringList();
QStringList loadedEffects = reply.value();
QStringList effects = effectConfig.keyList();
QStringList disabledEffects = QStringList();
foreach (QString effect, effects) { // krazy:exclude=foreach
@ -602,25 +609,108 @@ void KWinCompositingConfig::checkLoadedEffects()
}
}
if (!disabledEffects.isEmpty()) {
KServiceTypeTrader* trader = KServiceTypeTrader::self();
KService::List services;
QString message = i18n("The following desktop effects could not be activated:");
message.append("<ul>");
foreach (const QString & effect, disabledEffects) {
services = trader->query("KWin/Effect", "[X-KDE-PluginInfo-Name] == '" + effect + '\'');
message.append("<li>");
if (!services.isEmpty())
message.append(services.first()->name());
else
message.append(effect);
message.append("</li>");
}
message.append("</ul>");
KNotification::event("effectsnotsupported", message, QPixmap(), NULL, KNotification::CloseOnTimeout, KComponentData("kwin"));
m_showDetailedErrors->setData(disabledEffects);
ui.messageBox->setText(i18ncp("Error Message shown when a desktop effect could not be loaded",
"A desktop effect could not be loaded.",
"%1 desktop effects could not be loaded", disabledEffects.count()));
ui.messageBox->animatedShow();
}
}
}
void KWinCompositingConfig::showDetailedEffectLoadingInformation()
{
QStringList disabledEffects = m_showDetailedErrors->data().toStringList();
OrgKdeKWinInterface kwin("org.kde.kwin", "/KWin", QDBusConnection::sessionBus());
QDBusPendingReply< QString > pendingCompositingType = kwin.compositingType();
QString compositingType = pendingCompositingType.isError() ? "none" : pendingCompositingType.value();
KServiceTypeTrader* trader = KServiceTypeTrader::self();
KService::List services;
const KLocalizedString unknownReason = ki18nc("Effect with given name could not be activated due to unknown reason",
"%1 Effect failed to load due to unknown reason.");
const KLocalizedString requiresShaders = ki18nc("Effect with given name could not be activated as it requires hardware shaders",
"%1 Effect requires hardware support.");
const KLocalizedString requiresOpenGL = ki18nc("Effect with given name could not be activated as it requires OpenGL",
"%1 Effect requires OpenGL.");
const KLocalizedString requiresOpenGL2 = ki18nc("Effect with given name could not be activated as it requires OpenGL 2",
"%1 effect requires OpenGL 2.");
KDialog *dialog = new KDialog(this);
dialog->setWindowTitle(i18nc("Window title", "List of Effects which could not be loaded"));
dialog->setButtons(KDialog::Ok);
QWidget *mainWidget = new QWidget(dialog);
dialog->setMainWidget(mainWidget);
QVBoxLayout *vboxLayout = new QVBoxLayout(mainWidget);
mainWidget->setLayout(vboxLayout);
KTitleWidget *titleWidget = new KTitleWidget(mainWidget);
titleWidget->setText(i18n("For technical reasons it is not possible to determine all possible error causes."),
KTitleWidget::InfoMessage);
QLabel *label = new QLabel(mainWidget);
label->setOpenExternalLinks(true);
vboxLayout->addWidget(titleWidget);
vboxLayout->addWidget(label);
if (compositingType != "none") {
QString text;
if (disabledEffects.count() > 1) {
text = "<ul>";
}
foreach (const QString & effect, disabledEffects) {
QString message;
services = trader->query("KWin/Effect", "[X-KDE-PluginInfo-Name] == '" + effect + '\'');
if (!services.isEmpty()) {
KService::Ptr service = services.first();
if (compositingType == "xrender") {
// XRender compositing
QVariant openGL = service->property("X-KWin-Requires-OpenGL");
QVariant openGL2 = service->property("X-KWin-Requires-OpenGL2");
if ((openGL.isValid() && openGL.toBool()) ||
(openGL2.isValid() && openGL2.toBool())) {
// effect requires OpenGL
message = requiresOpenGL.subs(service->name()).toString();
} else {
// effect does not require OpenGL, unknown reason
message = unknownReason.subs(service->name()).toString();
}
} else if (compositingType == "gl1") {
// OpenGL 1 compositing
QVariant openGL2 = service->property("X-KWin-Requires-OpenGL2");
QVariant shaders = service->property("X-KWin-Requires-Shaders");
if (openGL2.isValid() && openGL2.toBool()) {
// effect requires OpenGL 2
message = requiresOpenGL2.subs(service->name()).toString();
} else if (shaders.isValid() && shaders.toBool()) {
// effect requires hardware shaders
message = requiresShaders.subs(service->name()).toString();
} else {
// unknown reason
message = unknownReason.subs(service->name()).toString();
}
} else {
// OpenGL 2 compositing - unknown reason
message = unknownReason.subs(service->name()).toString();
}
} else {
message = unknownReason.subs(effect).toString();
}
if (disabledEffects.count() > 1) {
text.append("<li>");
text.append(message);
text.append("</li>");
} else {
text = message;
}
}
if (disabledEffects.count() > 1) {
text.append("</ul>");
}
label->setText(text);
} else {
// compositing is not active - no effect can be active
label->setText(i18nc("Error Message shown when Compositing is not active after tried activation",
"Desktop Effect system is not running."));
}
dialog->show();
}
void KWinCompositingConfig::configChanged(bool reinitCompositing)
{
// Send signal to kwin

View file

@ -81,6 +81,7 @@ private slots:
void toogleSmoothScaleUi(int compositingType);
void toggleEffectShortcutChanged(const QKeySequence &seq);
void updateStatusUI(bool compositingIsPossible);
void showDetailedEffectLoadingInformation();
private:
bool effectEnabled(const QString& effect, const KConfigGroup& cfg) const;
@ -94,6 +95,7 @@ private:
bool m_showConfirmDialog;
KActionCollection* m_actionCollection;
QString originalGraphicsSystem;
QAction *m_showDetailedErrors;
};
} // namespace

View file

@ -6,15 +6,25 @@
<rect>
<x>0</x>
<y>0</y>
<width>552</width>
<height>483</height>
<width>557</width>
<height>530</height>
</rect>
</property>
<layout class="QVBoxLayout">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="KMessageWidget" name="messageBox">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>2</number>
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@ -859,6 +869,12 @@ On legacy hardware disabling Shaders can improve the performance.</string>
<header>kpluginselector.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>KMessageWidget</class>
<extends>QFrame</extends>
<header>kmessagewidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>tabWidget</tabstop>

View file

@ -95,5 +95,15 @@
<method name="openGLIsBroken">
<arg type="b" direction="out"/>
</method>
<method name="compositingType">
<!--
none: No Compositing
xrender: XRender
gl1: OpenGL 1
gl2: OpenGL 2
gles: OpenGL ES 2
-->
<arg type="s" direction="out"/>
</method>
</interface>
</node>

View file

@ -455,6 +455,15 @@ public:
bool compositingPossible() const;
QString compositingNotPossibleReason() const;
bool openGLIsBroken() const;
/**
* Returns the currently used Compositor (Scene):
* @li @c none No Compositing
* @li @c xrender XRender
* @li @c gl1 OpenGL 1
* @li @c gl2 OpenGL 2
* @li @c gles OpenGL ES 2
**/
QString compositingType();
void setCurrentScreen(int new_screen);