Commit be8cdbb1 authored by John Stowers's avatar John Stowers

Greatly improve shell theme functionality

parent 82da273b
......@@ -3,6 +3,8 @@
desktop icons (bug 648087)
* Improved robustness for missing theme/icon
directories (bug 648735)
* Fix shell theme installation for themes found in the wild
* Improve shell theme selection
3.0.2
* Really tweak window theme - both the fallback and the
......
......@@ -54,6 +54,9 @@ class GnomeShell:
out = self._proxy.execute_js('const ExtensionSystem = imports.ui.extensionSystem; ExtensionSystem.extensionMeta')
return json.loads(out)
def get_version(self):
return json.loads(self._proxy.execute_js('const Config = imports.misc.config; Config.PACKAGE_VERSION'))
if __name__ == "__main__":
s = GnomeShell()
print s.list_extensions()
......@@ -19,14 +19,16 @@ import os.path
import shutil
import zipfile
import tempfile
import logging
from gi.repository import Gtk
from gi.repository import GLib
from gtweak.utils import walk_directories
from gtweak.gsettings import GSettingsSetting
from gtweak.gshellwrapper import GnomeShell
from gtweak.tweakmodel import Tweak, TweakGroup
from gtweak.widgets import GConfComboTweak, GSettingsComboEnumTweak, GSettingsSwitchTweak, build_label_beside_widget, build_horizontal_sizegroup
from gtweak.widgets import GConfComboTweak, GSettingsComboEnumTweak, GSettingsSwitchTweak, build_label_beside_widget, build_horizontal_sizegroup, build_combo_box_text
class ShowWindowButtons(GConfComboTweak):
def __init__(self, **options):
......@@ -50,7 +52,7 @@ class _ThemeZipChooser(Gtk.FileChooserButton):
#self.set_width_chars(15)
self.set_local_only(True)
class ThemeInstaller(Tweak):
class ShellThemeTweak(Tweak):
THEME_EXT_NAME = "user-theme@gnome-shell-extensions.gnome.org"
THEME_GSETTINGS_SCHEMA = "org.gnome.shell.extensions.user-theme"
......@@ -68,11 +70,16 @@ class ThemeInstaller(Tweak):
error = "Shell not running"
try:
extensions = self._shell.list_extensions()
if ThemeInstaller.THEME_EXT_NAME in extensions and extensions[ThemeInstaller.THEME_EXT_NAME]["state"] == 1:
if ShellThemeTweak.THEME_EXT_NAME in extensions and extensions[ShellThemeTweak.THEME_EXT_NAME]["state"] == 1:
#check the correct gsettings key is present
try:
self._settings = GSettingsSetting(ThemeInstaller.THEME_GSETTINGS_SCHEMA)
name = self._settings.get_value(ThemeInstaller.THEME_GSETTINGS_NAME)
self._settings = GSettingsSetting(ShellThemeTweak.THEME_GSETTINGS_SCHEMA)
name = self._settings.get_value(ShellThemeTweak.THEME_GSETTINGS_NAME)
#assume the usertheme version is that version of the shell which
#it most supports (this is a poor assumption)
self._usertheme_extension_version = max(extensions[ShellThemeTweak.THEME_EXT_NAME]["shell-version"])
error = None
except:
error = "User Theme extension schema missing"
......@@ -90,9 +97,21 @@ class ThemeInstaller(Tweak):
self.widget_for_size_group = info
else:
hb = Gtk.HBox()
b = Gtk.Button.new_from_stock(Gtk.STOCK_REVERT_TO_SAVED)
b.connect("clicked", self._on_revert)
hb.pack_start(b, False, False, 5)
#build a combo box with all the valid theme options
valid = walk_directories( (ShellThemeTweak.THEME_DIR,), lambda d:
os.path.exists(os.path.join(d, "gnome-shell")) and \
os.path.exists(os.path.join(d, "gnome-shell", "gnome-shell.css")))
#manually add Adwiata to represent the default
#valid.append( ("Adwiata", "") )
cb = build_combo_box_text(
self._settings.get_string(ShellThemeTweak.THEME_GSETTINGS_NAME),
("", "Adwiata"),
*[(v,v) for v in valid])
cb.connect('changed', self._on_combo_changed)
hb.pack_start(cb, False, False, 5)
self.combo = cb
chooser = _ThemeZipChooser()
chooser.connect("file-set", self._on_file_set)
......@@ -101,54 +120,74 @@ class ThemeInstaller(Tweak):
self.widget = build_label_beside_widget(self.name, hb)
self.widget_for_size_group = chooser
def _extract_theme_zip(self, z, theme_name):
def _extract_theme_zip(self, z, theme_name, theme_members_path):
tmp = tempfile.mkdtemp()
dest = os.path.join(ThemeInstaller.THEME_DIR, theme_name, "gnome-shell")
dest = os.path.join(ShellThemeTweak.THEME_DIR, theme_name, "gnome-shell")
logging.info("Extracting theme %s to %s" % (theme_name, tmp))
try:
if os.path.exists(dest):
shutil.rmtree(dest)
z.extractall(tmp)
shutil.copytree(os.path.join(tmp, "theme"), dest)
self._settings.set_value(ThemeInstaller.THEME_GSETTINGS_NAME, theme_name)
shutil.copytree(os.path.join(tmp, theme_members_path), dest)
return theme_name
except OSError:
self.notify_error("Error installing theme")
def _shell_reload_theme(self):
#reloading the theme works OK, however there are some problems with reloading images.
#https://bugzilla.gnome.org/show_bug.cgi?id=644125
#however, smashing the whole shell just to change themes is pretty extreme. So we
#just let the user-theme extension pick up the change by itself
#
#self._shell.reload_theme()
#self.notify_action_required(
# "The shell must be restarted to apply the theme",
# "Restart",
# lambda: self._shell.restart())
pass
return None
def _on_file_set(self, chooser):
f = chooser.get_filename()
with zipfile.ZipFile(f, 'r') as z:
try:
#check this looks like a valid theme
info = z.getinfo('theme/gnome-shell.css')
#the theme name is the filename, for the moment
self._extract_theme_zip(
z,
os.path.splitext(os.path.basename(f))[0])
self._shell_reload_theme()
except KeyError:
fragment = ()
for n in z.namelist():
if n.endswith("gnome-shell.css"):
fragment = n.split("/")[0:-1]
break
if not fragment:
raise Exception("Could not find gnome-shell.css")
#old style themes name was taken from the zip name
if fragment[0] == "theme" and len(fragment) == 1:
theme_name = os.path.basename(f)
else:
theme_name = fragment[0]
theme_members_path = "/".join(fragment)
installed_name = self._extract_theme_zip(
z,
theme_name,
theme_members_path)
if installed_name:
print self.combo.get_model().append( (installed_name, installed_name) )
except:
#does not look like a valid theme
self.notify_error("Invalid theme file")
#set button back to default state
chooser.unselect_all()
def _on_revert(self, btn):
self._settings.set_value(ThemeInstaller.THEME_GSETTINGS_NAME, "")
self._shell_reload_theme()
def _on_combo_changed(self, combo):
val = combo.get_model().get_value(combo.get_active_iter(), 0)
self._settings.set_value(ShellThemeTweak.THEME_GSETTINGS_NAME, val)
#reloading the theme is not really necessary, the user-theme should pick
#pick up the change.
#
#however there are some problems with reloading images.
#https://bugzilla.gnome.org/show_bug.cgi?id=644125
#
#resetting to the default theme is also fucked
#https://bugzilla.gnome.org/show_bug.cgi?id=647386
if not val:
if self._usertheme_extension_version < "3.0.2":
self.notify_action_required(
"The shell must be restarted to apply the theme",
"Restart",
lambda: self._shell.restart())
sg = build_horizontal_sizegroup()
......@@ -158,7 +197,7 @@ TWEAK_GROUPS = (
GSettingsSwitchTweak("org.gnome.shell.clock", "show-date", schema_filename="org.gnome.shell.gschema.xml"),
GSettingsSwitchTweak("org.gnome.shell.calendar", "show-weekdate", schema_filename="org.gnome.shell.gschema.xml"),
ShowWindowButtons(size_group=sg),
ThemeInstaller(size_group=sg),
ShellThemeTweak(size_group=sg),
GSettingsComboEnumTweak("org.gnome.settings-daemon.plugins.power", "lid-close-battery-action", size_group=sg),
GSettingsComboEnumTweak("org.gnome.settings-daemon.plugins.power", "lid-close-ac-action", size_group=sg)),
)
......@@ -31,6 +31,10 @@ def build_label_beside_widget(txt, widget, hbox=None):
return hbox
def build_combo_box_text(selected, *values):
"""
builds a GtkComboBox and model containing the supplied values.
@values: a list of 2-tuples (value, name)
"""
store = Gtk.ListStore(str, str)
selected_iter = None
......
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