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
icc-effect-5.14.5
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(); 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 // Toplevel
//**************************************** //****************************************

View File

@ -165,4 +165,5 @@ X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true X-KDE-PluginInfo-EnabledByDefault=true
X-KDE-Library=kwin4_effect_builtins X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=75 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-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50 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-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50 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-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50 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-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=70 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-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50 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-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50 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-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins 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] [PropertyDef::X-KDE-Ordering]
Type=int 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-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins 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-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=50 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-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=60 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-PluginInfo-EnabledByDefault=true
X-KDE-Library=kwin4_effect_builtins X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=90 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-PluginInfo-EnabledByDefault=false
X-KDE-Library=kwin4_effect_builtins X-KDE-Library=kwin4_effect_builtins
X-KDE-Ordering=45 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) : KCModule(KWinCompositingConfigFactory::componentData(), parent)
, mKWinConfig(KSharedConfig::openConfig("kwinrc")) , mKWinConfig(KSharedConfig::openConfig("kwinrc"))
, m_showConfirmDialog(false) , 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"); KGlobal::locale()->insertCatalog("kwin_effects");
ui.setupUi(this); ui.setupUi(this);
@ -86,6 +88,9 @@ KWinCompositingConfig::KWinCompositingConfig(QWidget *parent, const QVariantList
ui.tabWidget->setCurrentIndex(0); ui.tabWidget->setCurrentIndex(0);
ui.statusTitleWidget->hide(); ui.statusTitleWidget->hide();
ui.rearmGlSupport->hide(); ui.rearmGlSupport->hide();
ui.messageBox->setVisible(false);
ui.messageBox->addAction(m_showDetailedErrors);
ui.messageBox->setMessageType(KMessageWidget::Warning);
// For future use // For future use
(void) I18N_NOOP("Use GLSL shaders"); (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.glVSync, SIGNAL(toggled(bool)), this, SLOT(changed()));
connect(ui.glShaders, 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 // Open the temporary config file
// Temporary conf file is used to synchronize effect checkboxes with effect // 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 // check for effects not supported by Backend or hardware
// such effects are enabled but not returned by DBus method loadedEffects // such effects are enabled but not returned by DBus method loadedEffects
QDBusMessage message = QDBusMessage::createMethodCall("org.kde.kwin", "/KWin", "org.kde.KWin", "loadedEffects"); OrgKdeKWinInterface kwin("org.kde.kwin", "/KWin", QDBusConnection::sessionBus());
QDBusMessage reply = QDBusConnection::sessionBus().call(message);
KConfigGroup effectConfig = KConfigGroup(mKWinConfig, "Compositing"); KConfigGroup effectConfig = KConfigGroup(mKWinConfig, "Compositing");
bool enabledAfter = effectConfig.readEntry("Enabled", true); 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"); effectConfig = KConfigGroup(mKWinConfig, "Plugins");
QStringList loadedEffects = reply.arguments()[0].toStringList(); QStringList loadedEffects = reply.value();
QStringList effects = effectConfig.keyList(); QStringList effects = effectConfig.keyList();
QStringList disabledEffects = QStringList(); QStringList disabledEffects = QStringList();
foreach (QString effect, effects) { // krazy:exclude=foreach foreach (QString effect, effects) { // krazy:exclude=foreach
@ -602,25 +609,108 @@ void KWinCompositingConfig::checkLoadedEffects()
} }
} }
if (!disabledEffects.isEmpty()) { if (!disabledEffects.isEmpty()) {
KServiceTypeTrader* trader = KServiceTypeTrader::self(); m_showDetailedErrors->setData(disabledEffects);
KService::List services; ui.messageBox->setText(i18ncp("Error Message shown when a desktop effect could not be loaded",
QString message = i18n("The following desktop effects could not be activated:"); "A desktop effect could not be loaded.",
message.append("<ul>"); "%1 desktop effects could not be loaded", disabledEffects.count()));
foreach (const QString & effect, disabledEffects) { ui.messageBox->animatedShow();
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"));
} }
} }
} }
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) void KWinCompositingConfig::configChanged(bool reinitCompositing)
{ {
// Send signal to kwin // Send signal to kwin

View File

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

View File

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

View File

@ -95,5 +95,15 @@
<method name="openGLIsBroken"> <method name="openGLIsBroken">
<arg type="b" direction="out"/> <arg type="b" direction="out"/>
</method> </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> </interface>
</node> </node>

View File

@ -455,6 +455,15 @@ public:
bool compositingPossible() const; bool compositingPossible() const;
QString compositingNotPossibleReason() const; QString compositingNotPossibleReason() const;
bool openGLIsBroken() 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); void setCurrentScreen(int new_screen);