summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Spilsbury <sam.spilsbury@canonical.com>2010-11-19 10:24:41 +0800
committerSam Spilsbury <sam.spilsbury@canonical.com>2010-11-19 10:24:41 +0800
commitc52f9ca19ce12c048d1013bcde581ac1af52370e (patch)
tree6b81e5bf44178308af4fafeb36b0666525d5b44a
downloadbailer-c52f9ca19ce12c048d1013bcde581ac1af52370e.tar.gz
bailer-c52f9ca19ce12c048d1013bcde581ac1af52370e.tar.bz2
Bailer plugin - handles fallback mechanism to bail out properly
-rw-r--r--CMakeLists.txt5
-rw-r--r--bailer.xml.in72
-rw-r--r--src/bailer.cpp253
-rw-r--r--src/bailer.h86
4 files changed, 416 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..1a5b7d7
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,5 @@
+find_package (Compiz REQUIRED)
+
+include (CompizPlugin)
+
+compiz_plugin (bailer)
diff --git a/bailer.xml.in b/bailer.xml.in
new file mode 100644
index 0000000..ac4f2b7
--- /dev/null
+++ b/bailer.xml.in
@@ -0,0 +1,72 @@
+<compiz>
+ <plugin name="bailer" useBcop="true">
+ <_short>Bailer</_short>
+ <_long>Take decisive action if something is affecting the experience</_long>
+ <category>Utility</category>
+ <options>
+ <option name="fatal_fallback_mode" type="int">
+ <_short>Fatal fallback mode</_short>
+ <_long>How best to handle a fatal fallback</_long>
+ <min>0</min>
+ <max>3</max>
+ <default>0</default>
+ <desc>
+ <value>0</value>
+ <_name>No action</_name>
+ </desc>
+ <desc>
+ <value>1</value>
+ <_name>Reduced functionality mode</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Detect session fallback</_name>
+ </desc>
+ <desc>
+ <value>3</value>
+ <_name>Execute custom fallback</_name>
+ </desc>
+ </option>
+ <option name="custom_fallback_window_manager" type="string">
+ <_short>Custom fallback window manager command</_short>
+ <_long>Command to execute when selecting to do a custom fallback</_long>
+ </option>
+ <option name="poor_performance_fallback" type="int">
+ <_short>Poor performance fallback</_short>
+ <_long>What do do when plugins indicate that performance is reading poor levels</_long>
+ <desc>
+ <value>0</value>
+ <_name>No action</_name>
+ </desc>
+ <desc>
+ <value>1</value>
+ <_name>Launch fatal fallback</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Unload a custom list of plugins</_name>
+ </desc>
+ <desc>
+ <value>3</value>
+ <_name>Reduced functionality mode</_name>
+ </desc>
+ <min>0</min>
+ <max>2</max>
+ <default>0</default>
+ </option>
+ <option name="bad_performance_threshold" type="int">
+ <_short>Bad performance threshold</_short>
+ <_long>How much bad performance to tolerate before taking decisive action</_long>
+ <min>0</min>
+ <max>300</max>
+ <default>50</default>
+ </option>
+ <option name="bad_plugins" type="list">
+ <_short>Bad Plugins</_short>
+ <_long>Plugins to unload in case the session is being impacted</_long>
+ <default></default>
+ <type>string</type>
+ </option>
+ </options>
+ </plugin>
+</compiz>
diff --git a/src/bailer.cpp b/src/bailer.cpp
new file mode 100644
index 0000000..2937514
--- /dev/null
+++ b/src/bailer.cpp
@@ -0,0 +1,253 @@
+/**
+ * Compiz bailer plugin
+ *
+ * bailer.cpp
+ *
+ * Copyright (c) 2010 Canonical Ltd
+ *
+ * This plugin should be thought of as a "manager" plugin for compiz
+ * it handles signals by various other plugins (eg handleCompizEvent)
+ * and then takes decisive action on those signals when appropriate
+ * based on the configuration.
+ *
+ * For example, it will handle signals from plugins that someone is
+ * doing something stupid and terminate the offending plugin,
+ * or handle signals that performance is poor, wait a little while
+ * and then take decisive action to restore the user experience.
+ *
+ * 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 3
+ * 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.
+ *
+ * AUTHORS: Didier Roche <didrocks@ubuntu.com>
+ * Sam Spilsbury <sam.spilsbury@canonical.com>
+ */
+
+#include "bailer.h"
+
+COMPIZ_PLUGIN_20090315 (bailer, BailerPluginVTable);
+
+static CompString reducedFunctionalityUnload[] = {"opengl", "composite"};
+static CompString noARBUnload[] = {"colorfilter", "blur", "bicubic", "water", "reflex"};
+static CompString noComplexUnload[] = {"blur", "water"};
+
+/*
+ * BailerScreen::detectFallbackWM ()
+ *
+ * Reads the session environment propeties and tries to detect
+ * which fallback window manager would be appropriate to launch here
+ *
+ * returns: a CompString with the fallback wm command
+ *
+ */
+CompString
+BailerScreen::detectFallbackWM ()
+{
+ if (getenv ("KDE_FULL_SESSION") != NULL)
+ return "kwin --replace";
+ else if (getenv ("GNOME_DESKTOP_SESSION_ID") != NULL)
+ return "metacity --replace";
+ else if (access ("/usr/bin/xfwm4", F_OK) == 0)
+ return "xfwm4 --replace";
+
+ return "";
+}
+
+/*
+ * BailerScreen::ensureDesktopServices
+ *
+ * Because compiz might be providing the panel shell or whatever
+ * (eg, Ubuntu's Unity plugin), we need to ensure that our desktop
+ * services come back when compiz goes away.
+ *
+ */
+void
+BailerScreen::ensureDesktopServices ()
+{
+ if (getenv ("GNOME_DESKTOP_SESSION_ID") != NULL)
+ screen->runCommand ("killall gnome-panel && gnome-panel");
+}
+
+/*
+ * BailerScreen::doUnload
+ *
+ * Unload given plugins at the top of the main loop
+ *
+ */
+bool
+BailerScreen::doUnload (std::vector <CompString> plugins)
+{
+ foreach (CompString &plugin, plugins)
+ {
+ CompPlugin *p = CompPlugin::find (plugin.c_str ());
+
+ if (p)
+ (*loaderUnloadPlugin) (p);
+ }
+
+ return false;
+}
+
+/*
+ * BailerScreen::unloadPlugins
+ *
+ * Add plugins to the unload timer so that we don't unload stuff
+ * during wrapped function calls
+ *
+ */
+void
+BailerScreen::unloadPlugins (CompString *plugins)
+{
+ std::vector <CompString> pv (plugins, plugins + sizeof (plugins) / sizeof (*plugins));
+
+ mSafeUnloadTimer.stop ();
+ mSafeUnloadTimer.setCallback (boost::bind (&BailerScreen::doUnload, this, pv));
+ mSafeUnloadTimer.start ();
+}
+
+void
+BailerScreen::unloadPlugins (std::vector <CompString> plugins)
+{
+ mSafeUnloadTimer.stop ();
+ mSafeUnloadTimer.setCallback (boost::bind (&BailerScreen::doUnload, this, plugins));
+ mSafeUnloadTimer.start ();
+}
+
+
+/*
+ * BailerScreen::doFallback ()
+ *
+ * Do the actual fallback if a plugin asks for it
+ *
+ */
+void
+BailerScreen::doFatalFallback ()
+{
+ switch (optionGetFatalFallbackMode ())
+ {
+ case BailerOptions::FatalFallbackModeReducedFunctionalityMode:
+ unloadPlugins (reducedFunctionalityUnload); break;
+ case BailerOptions::FatalFallbackModeDetectSessionFallback:
+ ensureDesktopServices ();
+ screen->runCommand (detectFallbackWM ().c_str ());
+ exit (EXIT_FAILURE);
+ break;
+ case BailerOptions::FatalFallbackModeExecuteCustomFallback:
+ ensureDesktopServices ();
+ screen->runCommand (optionGetCustomFallbackWindowManager ().c_str ());
+ exit (EXIT_FAILURE);
+ case BailerOptions::FatalFallbackModeNoAction:
+ default:
+ break;
+ }
+}
+
+/*
+ * BailerScreen::doPerformanceFallback
+ *
+ * Not as bad as a fatal fallback, but try to recover from bad
+ * performance if a plugin thinks we are not doing so well.
+ *
+ */
+void
+BailerScreen::doPerformanceFallback ()
+{
+ switch (optionGetPoorPerformanceFallback ())
+ {
+ case BailerScreen::PoorPerformanceFallbackLaunchFatalFallback:
+ doFatalFallback ();
+ break;
+ case BailerScreen::PoorPerformanceFallbackUnloadACustomListOfPlugins:
+ {
+ CompOption::Value::Vector vv = optionGetBadPlugins ();
+ std::vector <CompString> pv;
+
+ foreach (CompOption::Value &v, vv)
+ pv.push_back (v.s ());
+
+ unloadPlugins (pv);
+
+ break;
+ }
+ case BailerScreen::PoorPerformanceFallbackReducedFunctionalityMode:
+ unloadPlugins (reducedFunctionalityUnload); break;
+ case BailerScreen::PoorPerformanceFallbackNoAction:
+ default:
+ break;
+ }
+}
+
+/*
+ * BailerScreen::changeSessionType
+ *
+ * Unloads and loads plugins depending on what kind of session we wanted
+ *
+ */
+void
+BailerScreen::changeSessionType (SessionType type)
+{
+ switch (type)
+ {
+ case SessionType2D:
+ unloadPlugins (reducedFunctionalityUnload);
+ break;
+ case SessionType3DNoARB:
+ unloadPlugins (noARBUnload);
+ break;
+ case SessionType3DNoComplex:
+ unloadPlugins (noComplexUnload);
+ break;
+ case SessionType3DFull:
+ default:
+ break;
+ }
+}
+
+/*
+ * BailerScreen::handleCompizEvent
+ *
+ * Checks the compiz event screen if some plugin is screaming for help
+ *
+ */
+void
+BailerScreen::handleCompizEvent (const char *plugin, const char *event,
+ CompOption::Vector &options)
+{
+ if (strcmp (plugin, "composite") == 0)
+ {
+ if (strcmp (event, "poor_performance") == 0)
+ {
+ mPoorPerformanceCount++;
+ if (mPoorPerformanceCount > optionGetBadPerformanceThreshold ())
+ doPerformanceFallback ();
+ }
+ }
+
+ if (strcmp (event, "fatal_fallback") == 0)
+ doFatalFallback ();
+
+
+ screen->handleCompizEvent (plugin, event, options);
+}
+
+BailerScreen::BailerScreen (CompScreen *s) :
+ PluginClassHandler <BailerScreen, CompScreen> (s),
+ mPoorPerformanceCount (0)
+{
+ ScreenInterface::setHandler (s);
+}
+
+bool
+BailerPluginVTable::init ()
+{
+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
+ return false;
+
+ return true;
+}
diff --git a/src/bailer.h b/src/bailer.h
new file mode 100644
index 0000000..b5ead6a
--- /dev/null
+++ b/src/bailer.h
@@ -0,0 +1,86 @@
+/**
+ * Compiz bailer plugin
+ *
+ * bailer.h
+ *
+ * Copyright (c) 2010 Canonical Ltd
+ *
+ * This plugin should be thought of as a "manager" plugin for compiz
+ * it handles signals by various other plugins (eg handleCompizEvent)
+ * and then takes decisive action on those signals when appropriate
+ * based on the configuration.
+ *
+ * For example, it will handle signals from plugins that someone is
+ * doing something stupid and terminate the offending plugin,
+ * or handle signals that performance is poor, wait a little while
+ * and then take decisive action to restore the user experience.
+ *
+ * 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 3
+ * 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.
+ *
+ * AUTHORS: Didier Roche <didrocks@ubuntu.com>
+ * Sam Spilsbury <sam.spilsbury@canonical.com>
+ */
+
+#include <core/core.h>
+#include <core/pluginclasshandler.h>
+#include <core/timer.h>
+
+#include "bailer_options.h"
+
+class BailerScreen :
+ public PluginClassHandler <BailerScreen, CompScreen>,
+ public ScreenInterface,
+ public BailerOptions
+{
+ public:
+
+ BailerScreen (CompScreen *);
+
+ void
+ handleCompizEvent (const char *, const char *,
+ CompOption::Vector &options);
+
+ private:
+
+ typedef enum
+ {
+ SessionType2D = 0,
+ SessionType3DNoARB,
+ SessionType3DNoComplex,
+ SessionType3DFull
+ } SessionType;
+
+ int mPoorPerformanceCount;
+ CompTimer mSafeUnloadTimer;
+
+ CompString detectFallbackWM ();
+ void ensureDesktopServices ();
+
+ void doFatalFallback ();
+ void doPerformanceFallback ();
+
+ void changeSessionType (SessionType);
+
+ void unloadPlugins (CompString *);
+ void unloadPlugins (std::vector <CompString> );
+ bool doUnload (std::vector <CompString>);
+};
+
+#define BAILER_SCREEN(s) \
+ BailerScreen *bs = BailerScreen::get (s);
+
+class BailerPluginVTable :
+ public CompPlugin::VTableForScreen <BailerScreen>
+{
+ public:
+
+ bool init ();
+};