Commit 0c5c3258 authored by John Stowers's avatar John Stowers

Support shell extension management in 3.0 and 3.2

parent fe96fec9
......@@ -15,3 +15,4 @@
# You should have received a copy of the GNU General Public License
# along with gnome-tweak-tool. If not, see <http://www.gnu.org/licenses/>.
VERBOSE = False
......@@ -17,14 +17,18 @@
import os.path
import json
import logging
from gi.repository import Gio
from gi.repository import GLib
import gtweak.utils
from gtweak.gsettings import GSettingsSetting
class _ShellProxy:
def __init__(self):
d = Gio.bus_get_sync(Gio.BusType.SESSION, None)
self._proxy = Gio.DBusProxy.new_sync(
self.proxy = Gio.DBusProxy.new_sync(
d, 0, None,
'org.gnome.Shell',
'/org/gnome/Shell',
......@@ -32,11 +36,15 @@ class _ShellProxy:
None)
def execute_js(self, js):
result, output = self._proxy.Eval('(s)', js)
result, output = self.proxy.Eval('(s)', js)
if not result:
raise Exception(output)
return output
@property
def version(self):
return json.loads(self.execute_js('const Config = imports.misc.config; Config.PACKAGE_VERSION'))
class GnomeShell:
EXTENSION_STATE = {
......@@ -53,8 +61,9 @@ class GnomeShell:
DATA_DIR = os.path.join(GLib.get_user_data_dir(), "gnome-shell")
def __init__(self):
self._proxy = _ShellProxy()
def __init__(self, shellproxy, shellsettings):
self._proxy = shellproxy
self._settings = shellsettings
def restart(self):
self._proxy.execute_js('global.reexec_self();')
......@@ -62,17 +71,69 @@ class GnomeShell:
def reload_theme(self):
self._proxy.execute_js('const Main = imports.ui.main; Main.loadTheme();')
@property
def version(self):
return self._proxy.version
class GnomeShell30(GnomeShell):
EXTENSION_DISABLED_KEY = "disabled-extensions"
EXTENSION_NEED_RESTART = True
def __init__(self, *args, **kwargs):
GnomeShell.__init__(self, *args, **kwargs)
def list_extensions(self):
out = self._proxy.execute_js('const ExtensionSystem = imports.ui.extensionSystem; ExtensionSystem.extensionMeta')
return json.loads(out)
@property
def version(self):
return json.loads(self._proxy.execute_js('const Config = imports.misc.config; Config.PACKAGE_VERSION'))
def extension_is_active(self, state, uuid):
return state == GnomeShell.EXTENSION_STATE["ENABLED"] and \
not self._settings.setting_is_in_list(self.EXTENSION_DISABLED_KEY, uuid)
def enable_extension(self, uuid):
self._settings.setting_remove_from_list(self.EXTENSION_DISABLED_KEY, uuid)
def disable_extension(self, uuid):
self._settings.setting_add_to_list(self.EXTENSION_DISABLED_KEY, uuid)
class GnomeShell32(GnomeShell):
EXTENSION_ENABLED_KEY = "enabled-extensions"
EXTENSION_NEED_RESTART = False
def extension_is_active(self, state, uuid):
return state == GnomeShell.EXTENSION_STATE["ENABLED"] and \
self._settings.setting_is_in_list(self.EXTENSION_ENABLED_KEY, uuid)
def enable_extension(self, uuid):
self._settings.setting_add_to_list(self.EXTENSION_ENABLED_KEY, uuid)
def disable_extension(self, uuid):
self._settings.setting_remove_from_list(self.EXTENSION_ENABLED_KEY, uuid)
@gtweak.utils.singleton
class GnomeShellFactory:
def __init__(self):
proxy = _ShellProxy()
settings = GSettingsSetting("org.gnome.shell")
v = map(int,proxy.version.split("."))
if v >= [3,1,4]:
self.shell = GnomeShell32(proxy, settings)
else:
self.shell = GnomeShell30(proxy, settings)
logging.debug("Shell version: %s", str(v))
def get_shell(self):
return self.shell
if __name__ == "__main__":
s = GnomeShell()
gtweak.GSETTINGS_SCHEMA_DIR = "/usr/share/glib-2.0/schemas/"
s = GnomeShellFactory().get_shell()
print "Shell Version: %s" % s.version
print s.list_extensions()
print s == GnomeShellFactory().get_shell()
......@@ -8,27 +8,20 @@ from gi.repository import Gtk
from gi.repository import GLib
from gtweak.utils import extract_zip_file
from gtweak.gsettings import GSettingsSetting
from gtweak.gshellwrapper import GnomeShell
from gtweak.gshellwrapper import GnomeShell, GnomeShellFactory
from gtweak.tweakmodel import Tweak, TweakGroup
from gtweak.widgets import ZipFileChooserButton, build_label_beside_widget, build_horizontal_sizegroup
class _ShellExtensionTweak(Tweak):
EXTENSION_ENABLED_KEY = "enabled-extensions"
def __init__(self, shell, ext, settings, **options):
def __init__(self, shell, ext, **options):
Tweak.__init__(self, ext["name"], ext.get("description",""), **options)
self._shell = shell
self._settings = settings
state = ext.get("state")
sw = Gtk.Switch()
state = ext.get("state")
sw.set_active(
state == GnomeShell.EXTENSION_STATE["ENABLED"] and \
self._settings.setting_is_in_list(self.EXTENSION_ENABLED_KEY, ext["uuid"])
)
sw.set_active(self._shell.extension_is_active(state, ext["uuid"]))
sw.connect('notify::active', self._on_extension_toggled, ext["uuid"])
warning = None
......@@ -53,9 +46,15 @@ class _ShellExtensionTweak(Tweak):
def _on_extension_toggled(self, sw, active, uuid):
if not sw.get_active():
self._settings.setting_remove_from_list(self.EXTENSION_ENABLED_KEY, uuid)
self._shell.disable_extension(uuid)
else:
self._settings.setting_add_to_list(self.EXTENSION_ENABLED_KEY, uuid)
self._shell.enable_extension(uuid)
if self._shell.EXTENSION_NEED_RESTART:
self.notify_action_required(
_("The shell must be restarted for changes to take effect"),
_("Restart"),
self._shell.restart)
class _ShellExtensionInstallerTweak(Tweak):
......@@ -143,25 +142,24 @@ class ShellExtensionTweakGroup(TweakGroup):
#check the shell is running
try:
shell = GnomeShell()
shell = GnomeShellFactory().get_shell()
#add the extension installer
extension_tweaks.append(
_ShellExtensionInstallerTweak(shell, size_group=sg))
try:
settings = GSettingsSetting("org.gnome.shell")
#add a tweak for each installed extension
for extension in shell.list_extensions().values():
try:
extension_tweaks.append(
_ShellExtensionTweak(shell, extension, settings, size_group=sg))
_ShellExtensionTweak(shell, extension, size_group=sg))
except:
logging.warning("Invalid extension", exc_info=True)
except:
logging.warning("Error listing extensions", exc_info=True)
except:
logging.warning("Error detecting shell")
logging.warning("Error detecting shell", exc_info=True)
self.set_tweaks(*extension_tweaks)
......
......@@ -26,6 +26,19 @@ from gtweak.gconf import GConfSetting
from gi.repository import GLib
def singleton(cls):
"""
Singleton decorator that works with GObject derived types. The 'recommended'
python one - http://wiki.python.org/moin/PythonDecoratorLibrary#Singleton
does not (interacts badly with GObjectMeta
"""
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
def make_combo_list_with_default(opts, default, title=True, default_text=None):
"""
Turns a list of values into a list of value,name (where name is the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment