class TypingTweakGroup(Gtk.Box, TweakGroup): XKB_GSETTINGS_SCHEMA = "org.gnome.desktop.input-sources" XKB_GSETTINGS_NAME = "xkb-options" # These are configurable in gnome-control-center. grp_led is unsupported XKB_OPTIONS_BLACKLIST = {"lv3","Compose key","grp","grp_led"} def __init__(self): Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL, spacing=3) self._option_objects = [] ok = False try: self._kbdsettings = GSettingsSetting(self.XKB_GSETTINGS_SCHEMA) self._kbdsettings.connect("changed::"+self.XKB_GSETTINGS_NAME, self._on_changed) self._xkb_info = GnomeDesktop.XkbInfo() ok = True self.loaded = True except GSettingsMissingError: logging.info("Typing missing schema %s" % self.XKB_GSETTINGS_SCHEMA) self.loaded = False except AttributeError: logging.warning("Typing missing GnomeDesktop.gir with Xkb support") self.loaded = False finally: if ok: for opt in set(self._xkb_info.get_all_option_groups()) - self.XKB_OPTIONS_BLACKLIST: obj = _XkbOption(opt, self._kbdsettings, self._xkb_info) self._option_objects.append(obj) self.pack_start(obj, False, False, 0) TweakGroup.__init__(self, _("Typing"), *self._option_objects) def _on_changed(self, *args): for obj in self._option_objects: obj.reload()
class _GSettingsTweak(Tweak): def __init__(self, schema_name, key_name, **options): self.schema_name = schema_name self.key_name = key_name self.settings = GSettingsSetting(schema_name, **options) Tweak.__init__(self, self.settings.schema_get_summary(key_name), self.settings.schema_get_description(key_name), **options)
def __init__(self): Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL, spacing=3) self._option_objects = [] self._sg = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) ok = False try: self._kbdsettings = GSettingsSetting(self.XKB_GSETTINGS_SCHEMA) self._kbdsettings.connect("changed::"+self.XKB_GSETTINGS_NAME, self._on_changed) self._xkb_info = GnomeDesktop.XkbInfo() ok = True self.loaded = True except GSettingsMissingError: logging.info("Typing missing schema %s" % self.XKB_GSETTINGS_SCHEMA) self.loaded = False except AttributeError: logging.warning("Typing missing GnomeDesktop.gir with Xkb support") self.loaded = False finally: if ok: for opt in set(self._xkb_info.get_all_option_groups()) - self.XKB_OPTIONS_BLACKLIST: obj = _XkbOption(opt, self._kbdsettings, self._xkb_info) self._sg.add_widget(obj._combo) self._option_objects.append(obj) self.pack_start(obj, False, False, 0) TweakGroup.__init__(self, _("Typing"), *self._option_objects)
def __init__(self, **options): Tweak.__init__(self, "Shell theme", "Install custom or user themes for gnome-shell", **options) #check the shell is running and the usertheme extension is present error = "Unknown" try: self._shell = GnomeShell() except: 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: #check the correct gsettings key is present try: self._settings = GSettingsSetting(ThemeInstaller.THEME_GSETTINGS_SCHEMA) name = self._settings.get_value(ThemeInstaller.THEME_GSETTINGS_NAME) print "!!!!", name error = None except: error = "User Theme extension schema missing" else: error = "User Theme extension not enabled" except Exception, e: error = "Could not list shell extensions"
def __init__(self, **options): Tweak.__init__(self, "Shell theme", "Install custom or user themes for gnome-shell", **options) #check the shell is running and the usertheme extension is present error = _("Unknown error") try: self._shell = GnomeShellFactory().get_shell() except: logging.warning("Shell not running", exc_info=True) error = _("Shell not running") try: extensions = self._shell.list_extensions() 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(ShellThemeTweak.THEME_GSETTINGS_SCHEMA) name = self._settings.get_string(ShellThemeTweak.THEME_GSETTINGS_NAME) ext = extensions[ShellThemeTweak.THEME_EXT_NAME] logging.debug("Shell user-theme extension\n%s" % pprint.pformat(ext)) error = None except: logging.warning( "Could not find user-theme extension in %s" % ','.join(extensions.keys()), exc_info=True) error = _("Shell user-theme extension incorrectly installed") else: error = _("Shell user-theme extension not enabled") except Exception, e: logging.warning("Could not list shell extensions", exc_info=True) error = _("Could not list shell extensions")
def __init__(self, schema_name, key_name, **options): self.schema_name = schema_name self.key_name = key_name self.settings = GSettingsSetting(schema_name, **options) Tweak.__init__(self, options.get("summary",self.settings.schema_get_summary(key_name)), options.get("description",self.settings.schema_get_description(key_name)), **options)
def __init__(self, **options): Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL) Tweak.__init__(self, _("Shell theme"), _("Install custom or user themes for gnome-shell"), **options) #check the shell is running and the usertheme extension is present error = _("Unknown error") self._shell = _shell if self._shell is None: logging.warning("Shell not running", exc_info=True) error = _("Shell not running") else: try: extensions = self._shell.list_extensions() if ShellThemeTweak.THEME_EXT_NAME in extensions and extensions[ShellThemeTweak.THEME_EXT_NAME]["state"] == 1: #check the correct gsettings key is present try: if os.path.exists(ShellThemeTweak.THEME_GSETTINGS_DIR): self._settings = GSettingsSetting(ShellThemeTweak.THEME_GSETTINGS_SCHEMA, schema_dir=ShellThemeTweak.THEME_GSETTINGS_DIR) else: self._settings = GSettingsSetting(ShellThemeTweak.THEME_GSETTINGS_SCHEMA) name = self._settings.get_string(ShellThemeTweak.THEME_GSETTINGS_NAME) ext = extensions[ShellThemeTweak.THEME_EXT_NAME] logging.debug("Shell user-theme extension\n%s" % pprint.pformat(ext)) error = None except: logging.warning( "Could not find user-theme extension in %s" % ','.join(extensions.keys()), exc_info=True) error = _("Shell user-theme extension incorrectly installed") else: error = _("Shell user-theme extension not enabled") except Exception, e: logging.warning("Could not list shell extensions", exc_info=True) error = _("Could not list shell extensions")
class ThemeInstaller(Tweak): THEME_EXT_NAME = "*****@*****.**" THEME_GSETTINGS_SCHEMA = "org.gnome.shell.extensions.user-theme" THEME_GSETTINGS_NAME = "name" THEME_DIR = os.path.join(GLib.get_home_dir(), ".themes") def __init__(self, **options): Tweak.__init__(self, "Shell theme", "Install custom or user themes for gnome-shell", **options) #check the shell is running and the usertheme extension is present error = "Unknown" try: self._shell = GnomeShell() except: 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: #check the correct gsettings key is present try: self._settings = GSettingsSetting(ThemeInstaller.THEME_GSETTINGS_SCHEMA) name = self._settings.get_value(ThemeInstaller.THEME_GSETTINGS_NAME) print "!!!!", name error = None except: error = "User Theme extension schema missing" else: error = "User Theme extension not enabled" except Exception, e: error = "Could not list shell extensions" if error: info = Gtk.InfoBar() info.props.message_type = Gtk.MessageType.INFO info.get_content_area().add(Gtk.Label(error)) self.widget = build_label_beside_widget(self.name, info) 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) chooser = _ThemeZipChooser() chooser.connect("file-set", self._on_file_set) hb.pack_start(chooser, False, False, 0) self.widget = build_label_beside_widget(self.name, hb) self.widget_for_size_group = chooser
def adjust_schema_for_overrides(originalSchema, key, options): if (_shell is None): return originalSchema if (_shell.mode == 'classic'): overridesSchema = "org.gnome.shell.extensions.classic-overrides" overridesFile = None else: overridesSchema = "org.gnome.shell.overrides" overridesFile = "org.gnome.shell.gschema.xml" try: if (key in GSettingsSetting( overridesSchema, schema_filename=overridesFile).list_keys()): options['schema_filename'] = overridesFile return overridesSchema except GSettingsMissingError, e: logging.info("GSetting missing %s" % (e.message))
def __init__(self, name, schema_name, key_name, **options): schema_name = adjust_schema_for_overrides(schema_name, key_name, options) self.schema_name = schema_name self.key_name = key_name self._extra_info = None if 'uid' not in options: options['uid'] = key_name try: self.settings = GSettingsSetting(schema_name, **options) Tweak.__init__( self, name, options.get("description", self.settings.schema_get_description(key_name)), **options) except GSettingsMissingError, e: self.settings = GSettingsFakeSetting() Tweak.__init__(self, "", "") self.loaded = False logging.info("GSetting missing %s" % (e.message))
def __init__(self): try: proxy = _ShellProxy() settings = GSettingsSetting("org.gnome.shell") v = map(int, proxy.version.split(".")) if v >= [3, 5, 0]: self.shell = GnomeShell36(proxy, settings) elif v >= [3, 3, 2]: self.shell = GnomeShell34(proxy, settings) elif v >= [3, 1, 4]: self.shell = GnomeShell32(proxy, settings) else: logging.warn("Shell version not supported") self.shell = None logging.debug("Shell version: %s", str(v)) except: self.shell = None logging.warn("Shell not installed or running")
def __init__(self, **options): Tweak.__init__(self, "Dynamic workspaces", "Disable gnome-shell dynamic workspace management, use static workspaces", **options) settings = GSettingsSetting(self.NUM_WORKSPACES_SCHEMA, **options) adj = Gtk.Adjustment(1, 1, 99, 1) sb = Gtk.SpinButton(adjustment=adj, digits=0) settings.bind(self.NUM_WORKSPACES_KEY, adj, "value", Gio.SettingsBindFlags.DEFAULT) settings = GSettingsSetting(self.DYNAMIC_SCHEMA, **options) sw = Gtk.Switch() settings.bind(self.DYNAMIC_KEY, sw, "active", Gio.SettingsBindFlags.DEFAULT) #sw.bind_property ("active", sb, "sensitive", GObject.BindingFlags.SYNC_CREATE) sb.set_sensitive(not settings[self.DYNAMIC_KEY]) sw.connect('notify::active', lambda _sw,_param,_sb: _sb.set_sensitive(not _sw.get_active()), sb) hb = Gtk.HBox(spacing = 4) hb.pack_start(sw, False, False, 0) hb.pack_start(sb, True, True, 0) self.widget = build_label_beside_widget(self.name, hb) self.widget_for_size_group = hb
class ShellThemeTweak(Gtk.Box, Tweak): THEME_EXT_NAME = "*****@*****.**" THEME_GSETTINGS_SCHEMA = "org.gnome.shell.extensions.user-theme" THEME_GSETTINGS_NAME = "name" THEME_GSETTINGS_DIR = os.path.join(GLib.get_user_data_dir(), "gnome-shell", "extensions", THEME_EXT_NAME, "schemas") LEGACY_THEME_DIR = os.path.join(GLib.get_home_dir(), ".themes") THEME_DIR = os.path.join(GLib.get_user_data_dir(), "themes") def __init__(self, **options): Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL) Tweak.__init__(self, _("Shell theme"), _("Install custom or user themes for gnome-shell"), **options) #check the shell is running and the usertheme extension is present error = _("Unknown error") self._shell = _shell if self._shell is None: logging.warning("Shell not running", exc_info=True) error = _("Shell not running") else: try: extensions = self._shell.list_extensions() if ShellThemeTweak.THEME_EXT_NAME in extensions and extensions[ShellThemeTweak.THEME_EXT_NAME]["state"] == 1: #check the correct gsettings key is present try: if os.path.exists(ShellThemeTweak.THEME_GSETTINGS_DIR): self._settings = GSettingsSetting(ShellThemeTweak.THEME_GSETTINGS_SCHEMA, schema_dir=ShellThemeTweak.THEME_GSETTINGS_DIR) else: self._settings = GSettingsSetting(ShellThemeTweak.THEME_GSETTINGS_SCHEMA) name = self._settings.get_string(ShellThemeTweak.THEME_GSETTINGS_NAME) ext = extensions[ShellThemeTweak.THEME_EXT_NAME] logging.debug("Shell user-theme extension\n%s" % pprint.pformat(ext)) error = None except: logging.warning( "Could not find user-theme extension in %s" % ','.join(extensions.keys()), exc_info=True) error = _("Shell user-theme extension incorrectly installed") else: error = _("Shell user-theme extension not enabled") except Exception, e: logging.warning("Could not list shell extensions", exc_info=True) error = _("Could not list shell extensions") if error: cb = build_combo_box_text(None) build_label_beside_widget(self.name, cb, warning=error, hbox=self) self.widget_for_size_group = cb else: #include both system, and user themes #note: the default theme lives in /system/data/dir/gnome-shell/theme # and not themes/, so add it manually later dirs = [os.path.join(d, "themes") for d in GLib.get_system_data_dirs()] dirs += [ShellThemeTweak.THEME_DIR] dirs += [ShellThemeTweak.LEGACY_THEME_DIR] valid = walk_directories(dirs, lambda d: os.path.exists(os.path.join(d, "gnome-shell")) and \ os.path.exists(os.path.join(d, "gnome-shell", "gnome-shell.css"))) #the default value to reset the shell is an empty string valid.extend( ("",) ) #build a combo box with all the valid theme options #manually add Adwaita to represent the default cb = build_combo_box_text( self._settings.get_string(ShellThemeTweak.THEME_GSETTINGS_NAME), *make_combo_list_with_default( valid, "", default_text=_("<i>Default</i>"))) cb.connect('changed', self._on_combo_changed) self._combo = cb #a filechooser to install new themes chooser = FileChooserButton( _("Select a theme"), True, ["application/zip"]) chooser.connect("file-set", self._on_file_set) build_label_beside_widget(self.name, chooser, cb, hbox=self) self.widget_for_size_group = cb
class ShellThemeTweak(Gtk.Box, Tweak): THEME_EXT_NAME = "*****@*****.**" THEME_GSETTINGS_SCHEMA = "org.gnome.shell.extensions.user-theme" THEME_GSETTINGS_NAME = "name" THEME_GSETTINGS_DIR = os.path.join(GLib.get_user_data_dir(), "gnome-shell", "extensions", THEME_EXT_NAME, "schemas") LEGACY_THEME_DIR = os.path.join(GLib.get_home_dir(), ".themes") THEME_DIR = os.path.join(GLib.get_user_data_dir(), "themes") def __init__(self, **options): Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL) Tweak.__init__(self, _("Shell"), _("Install custom or user themes for gnome-shell"), **options) #check the shell is running and the usertheme extension is present error = _("Unknown error") self._shell = _shell if self._shell is None: logging.warning("Shell not running", exc_info=True) error = _("Shell not running") else: try: extensions = self._shell.list_extensions() if ShellThemeTweak.THEME_EXT_NAME in extensions and extensions[ ShellThemeTweak.THEME_EXT_NAME]["state"] == 1: #check the correct gsettings key is present try: if os.path.exists(ShellThemeTweak.THEME_GSETTINGS_DIR): self._settings = GSettingsSetting( ShellThemeTweak.THEME_GSETTINGS_SCHEMA, schema_dir=ShellThemeTweak.THEME_GSETTINGS_DIR) else: self._settings = GSettingsSetting( ShellThemeTweak.THEME_GSETTINGS_SCHEMA) name = self._settings.get_string( ShellThemeTweak.THEME_GSETTINGS_NAME) ext = extensions[ShellThemeTweak.THEME_EXT_NAME] logging.debug("Shell user-theme extension\n%s" % pprint.pformat(ext)) error = None except: logging.warning( "Could not find user-theme extension in %s" % ','.join(list(extensions.keys())), exc_info=True) error = _( "Shell user-theme extension incorrectly installed") else: error = _("Shell user-theme extension not enabled") except Exception as e: logging.warning("Could not list shell extensions", exc_info=True) error = _("Could not list shell extensions") if error: cb = build_combo_box_text(None) build_label_beside_widget(self.name, cb, warning=error, hbox=self) self.widget_for_size_group = cb else: #include both system, and user themes #note: the default theme lives in /system/data/dir/gnome-shell/theme # and not themes/, so add it manually later dirs = [ os.path.join(d, "themes") for d in GLib.get_system_data_dirs() ] dirs += [ShellThemeTweak.THEME_DIR] dirs += [ShellThemeTweak.LEGACY_THEME_DIR] valid = walk_directories(dirs, lambda d: os.path.exists(os.path.join(d, "gnome-shell")) and \ os.path.exists(os.path.join(d, "gnome-shell", "gnome-shell.css"))) #the default value to reset the shell is an empty string valid.extend(("", )) valid = set(valid) #build a combo box with all the valid theme options #manually add Adwaita to represent the default cb = build_combo_box_text( self._settings.get_string( ShellThemeTweak.THEME_GSETTINGS_NAME), *make_combo_list_with_default( valid, "", default_text=_("<i>Default</i>"))) cb.connect('changed', self._on_combo_changed) self._combo = cb #a filechooser to install new themes chooser = FileChooserButton(_("Select a theme"), True, ["application/zip"]) chooser.connect("file-set", self._on_file_set) build_label_beside_widget(self.name, chooser, cb, hbox=self) self.widget_for_size_group = cb def _on_file_set(self, chooser): f = chooser.get_filename() with zipfile.ZipFile(f, 'r') as z: try: fragment = () theme_name = None for n in z.namelist(): if n.endswith("gnome-shell.css"): fragment = n.split("/")[0:-1] if n.endswith("gnome-shell/theme.json"): logging.info("New style theme detected (theme.json)") #new style theme - extract the name from the json file tmp = tempfile.mkdtemp() z.extract(n, tmp) with open(os.path.join(tmp, n)) as f: try: theme_name = json.load( f)["shell-theme"]["name"] except: logging.warning("Invalid theme format", exc_info=True) if not fragment: raise Exception("Could not find gnome-shell.css") if not theme_name: logging.info( "Old style theme detected (missing theme.json)") #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) ok, updated = extract_zip_file( z, theme_members_path, os.path.join(ShellThemeTweak.THEME_DIR, theme_name, "gnome-shell")) if ok: if updated: self.notify_information( _("%s theme updated successfully") % theme_name) else: self.notify_information( _("%s theme installed successfully") % theme_name) #I suppose I could rely on updated as indicating whether to add the theme #name to the combo, but just check to see if it is already there model = self._combo.get_model() if theme_name not in [r[0] for r in model]: model.append((theme_name, theme_name)) else: self.notify_information(_("Error installing theme")) except: #does not look like a valid theme self.notify_information(_("Invalid theme")) logging.warning("Error parsing theme zip", exc_info=True) #set button back to default state chooser.unselect_all() def _on_combo_changed(self, combo): val = combo.get_model().get_value(combo.get_active_iter(), 0) self._settings.set_string(ShellThemeTweak.THEME_GSETTINGS_NAME, val)
def set_theme(desk_env, t_type, theme): if desk_env not in SUPPORTED_DESKENVS: raise Exception('Invalid desktop environment!') elif not theme: logger.error('{}\'s {} theme not set '.format(correct_name_case(desk_env), correct_name_case(t_type))) return if t_type in ['gtk', 'icons']: from gi.repository import Gio if desk_env == 'cinnamon': gsettings_string = 'org.cinnamon.desktop.interface' else: gsettings_string = 'org.gnome.desktop.interface' gsettings = Gio.Settings.new(gsettings_string) # Safety fallback, shouldn't happen else: gsettings = None if t_type == 'gtk': # Easy peasy # For GNOME and Cinnamon gsettings['gtk-theme'] = theme # For XFCE if desk_env == 'xfce': from subprocess import run, CalledProcessError try: # noinspection SpellCheckingInspection run(['xfconf-query', '-c', 'xsettings', '-p', '/Net/ThemeName', '-s', theme]) except CalledProcessError: logger.error('Could not apply GTK theme') return # Switching GTK themes in KDE is a little bit more complicated than the others... # For KDE elif desk_env == 'kde': from subprocess import run import configparser import fileinput import sys from automathemely.autoth_tools.utils import get_bin # Set GTK3 theme # This would usually be done with kwriteconfig but since there is no way to notify GTK3 apps that the # theme has changed in KDE like with GTK2 anyway we might as well do it this way parser = configparser.ConfigParser(strict=False) # Prevent changing the key's case parser.optionxform = lambda option: option parser.read(PATH_CONSTANTS['kde-gtk-config']['gtk3']) parser['Settings']['gtk-theme-name'] = theme with open(PATH_CONSTANTS['kde-gtk-config']['gtk3'], 'w') as f: parser.write(f, space_around_delimiters=False) # Search for gtk2 config file in theme dir in PATH_CONSTANTS dirs # As if it wasn't messy enough already... match = walk_filter_dirs(PATH_CONSTANTS['general-themes'], lambda parent_dir, t: Path(parent_dir) .joinpath(t).glob('gtk-2.*/gtkrc') and t.lower() != 'default', return_parent=True) if not match: logger.warning('The selected GTK theme does not contain a GTK2 theme, so some applications may ' 'look odd') else: # If there are several themes with the same name in different directories, only get the first one # to match according to the dirs hierarchy in PATH_CONSTANTS theme_parent = match[0][1] if not Path(PATH_CONSTANTS['kde-gtk-config']['gtk2']).is_file(): logger.warning('GTK2 config file not found, set a theme from System Settings at least once and ' 'try again') # Write GTK2 config else: line_replaced, previous_is_autogen_comment = False, False for line in fileinput.input(PATH_CONSTANTS['kde-gtk-config']['gtk2'], inplace=True): if line.startswith('# Configs for GTK2 programs'): previous_is_autogen_comment = True sys.stdout.write(line) # Even in kde-config-gtk they don't seem to agree if this may not actually be needed, but # just in case here it is elif line.startswith('include'): print('include "{}"'.format(str(Path(theme_parent).joinpath(theme, 'gtk-2.0', 'gtkrc')))) # This is the one that matters elif line.startswith('gtk-theme-name='): print('gtk-theme-name="{}"'.format(theme)) line_replaced = True else: if previous_is_autogen_comment and not line.startswith('# Edited by AutomaThemely'): print('# Edited by AutomaThemely') previous_is_autogen_comment = False sys.stdout.write(line) if not line_replaced: logger.warning('GTK2 config file is invalid, set a theme from System Settings at least ' 'once and try again') else: # Send signal to GTK2 apps to refresh their themes run([get_bin('kde-refresh-gtk2')]) elif t_type == 'icons': # For GNOME and Cinnamon gsettings['icon-theme'] = theme # For XFCE if desk_env == 'xfce': from subprocess import run, CalledProcessError try: # noinspection SpellCheckingInspection run(['xfconf-query', '-c', 'xsettings', '-p', '/Net/IconThemeName', '-s', theme]) except CalledProcessError: logger.error('Could not apply icons theme') return elif t_type == 'shell': # This is WAY out of my level, I'll just let the professionals handle this one... try: import gtweak except ImportError: logger.error('GNOME Tweaks not installed') return from gtweak.gshellwrapper import GnomeShellFactory from gtweak.defs import GSETTINGS_SCHEMA_DIR, LOCALE_DIR # This could probably be implemented in house but since we're already importing from gtweak I guess it'll stay # this way for now from gtweak.gsettings import GSettingsSetting gtweak.GSETTINGS_SCHEMA_DIR = GSETTINGS_SCHEMA_DIR gtweak.LOCALE_DIR = LOCALE_DIR shell = GnomeShellFactory().get_shell() shell_theme_name = '*****@*****.**' shell_theme_schema = 'org.gnome.shell.extensions.user-theme' shell_theme_schema_dir = Path(PATH_CONSTANTS['shell-user-extensions']).joinpath(shell_theme_name, 'schemas') if not shell: logger.error('GNOME Shell not running') return else: # noinspection PyBroadException try: shell_extensions = shell.list_extensions() except Exception: logger.error('GNOME Shell extensions could not be loaded') return else: # noinspection PyBroadException try: if shell_theme_name in shell_extensions and shell_extensions[shell_theme_name]['state'] == 1: # If shell user-theme was installed locally e. g. through extensions.gnome.org if Path(shell_theme_schema_dir).is_dir(): user_shell_settings = GSettingsSetting(shell_theme_schema, schema_dir=str(shell_theme_schema_dir)) # If it was installed as a system extension else: user_shell_settings = GSettingsSetting(shell_theme_schema) else: logger.error('GNOME Shell user theme extension not enabled') return except Exception: logger.error('Could not load GNOME Shell user theme extension') return else: # To set the default theme you have to input an empty string, but since that won't work with the # Setting Manager's ComboBoxes we set it by this placeholder name if theme == 'default': theme = '' # Set the GNOME Shell theme user_shell_settings.set_string('name', theme) elif t_type == 'lookandfeel': from subprocess import run, CalledProcessError try: # noinspection SpellCheckingInspection run(['lookandfeeltool', '-a', '{}'.format(theme)], check=True) except CalledProcessError: logger.error('Could not apply Look and Feel theme') return elif t_type == 'desktop': from gi.repository import Gio cinnamon_settings = Gio.Settings.new('org.cinnamon.theme') cinnamon_settings['name'] = theme
def __init__(self, **options): Gtk.Box.__init__(self) Tweak.__init__(self, _("Hinting"), _("Antialiasing")) try: self.settings = GSettingsSetting("org.gnome.desktop.interface") except: self.settings = None logging.warn( "org.gnome.desktop.interface not installed or running") if not self.settings: return self.set_spacing(12) self.props.margin_top = 12 label = Gtk.Label(_("Hinting")) label.props.yalign = 0.0 label.padding = 10 self.pack_start(label, False, False, 0) hint_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) self.pack_start(hint_box, True, True, 0) self.btn_full = Gtk.RadioButton.new_from_widget(None) self.btn_full.set_label(_("Full")) self.btn_full.set_active(self.settings["font-hinting"] == "full") self.btn_full.connect("toggled", self.on_hint_button_toggled) hint_box.pack_start(self.btn_full, False, False, 0) self.btn_med = Gtk.RadioButton.new_from_widget(self.btn_full) self.btn_med.set_label(_("Medium")) self.btn_med.set_active(self.settings["font-hinting"] == "medium") self.btn_med.connect("toggled", self.on_hint_button_toggled) hint_box.pack_start(self.btn_med, False, False, 0) self.btn_slight = Gtk.RadioButton.new_from_widget(self.btn_full) self.btn_slight.set_label(_("Slight")) self.btn_slight.set_active(self.settings["font-hinting"] == "slight") self.btn_slight.connect("toggled", self.on_hint_button_toggled) hint_box.pack_start(self.btn_slight, False, False, 0) self.btn_hnone = Gtk.RadioButton.new_from_widget(self.btn_full) self.btn_hnone.set_label(_("None")) self.btn_hnone.set_active(self.settings["font-hinting"] == "none") self.btn_hnone.connect("toggled", self.on_hint_button_toggled) hint_box.pack_start(self.btn_hnone, False, False, 0) label = Gtk.Label(_("Antialiasing")) label.props.yalign = 0.0 self.pack_start(label, False, False, 0) aa_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) self.pack_start(aa_box, False, False, 0) self.btn_rgba = Gtk.RadioButton.new_from_widget(None) self.btn_rgba.set_label(_("Subpixel (for LCD screens)")) self.btn_rgba.set_active(self.settings["font-antialiasing"] == "rgba") self.btn_rgba.connect("toggled", self.on_aa_button_toggled) aa_box.pack_start(self.btn_rgba, False, False, 0) self.btn_gray = Gtk.RadioButton.new_from_widget(self.btn_rgba) self.btn_gray.set_label(_("Standard (grayscale)")) self.btn_gray.set_active( self.settings["font-antialiasing"] == "grayscale") self.btn_gray.connect("toggled", self.on_aa_button_toggled) aa_box.pack_start(self.btn_gray, False, False, 0) self.btn_anone = Gtk.RadioButton.new_from_widget(self.btn_rgba) self.btn_anone.set_label(_("None")) self.btn_anone.set_active(self.settings["font-antialiasing"] == "none") self.btn_anone.connect("toggled", self.on_aa_button_toggled) aa_box.pack_start(self.btn_anone, False, False, 0)
class ShellThemeTweak(Gtk.Box, Tweak): THEME_EXT_NAME = "*****@*****.**" THEME_GSETTINGS_SCHEMA = "org.gnome.shell.extensions.user-theme" THEME_GSETTINGS_NAME = "name" THEME_GSETTINGS_DIR = os.path.join(GLib.get_user_data_dir(), "gnome-shell", "extensions", THEME_EXT_NAME, "schemas") LEGACY_THEME_DIR = os.path.join(GLib.get_home_dir(), ".themes") THEME_DIR = os.path.join(GLib.get_user_data_dir(), "themes") def __init__(self, **options): Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL) Tweak.__init__(self, _("Shell theme"), _("Install custom or user themes for gnome-shell"), **options) #check the shell is running and the usertheme extension is present error = _("Unknown error") self._shell = _shell if self._shell is None: logging.warning("Shell not running", exc_info=True) error = _("Shell not running") else: try: extensions = self._shell.list_extensions() if ShellThemeTweak.THEME_EXT_NAME in extensions and extensions[ ShellThemeTweak.THEME_EXT_NAME]["state"] == 1: #check the correct gsettings key is present try: if os.path.exists(ShellThemeTweak.THEME_GSETTINGS_DIR): self._settings = GSettingsSetting( ShellThemeTweak.THEME_GSETTINGS_SCHEMA, schema_dir=ShellThemeTweak.THEME_GSETTINGS_DIR) else: self._settings = GSettingsSetting( ShellThemeTweak.THEME_GSETTINGS_SCHEMA) name = self._settings.get_string( ShellThemeTweak.THEME_GSETTINGS_NAME) ext = extensions[ShellThemeTweak.THEME_EXT_NAME] logging.debug("Shell user-theme extension\n%s" % pprint.pformat(ext)) error = None except: logging.warning( "Could not find user-theme extension in %s" % ','.join(extensions.keys()), exc_info=True) error = _( "Shell user-theme extension incorrectly installed") else: error = _("Shell user-theme extension not enabled") except Exception, e: logging.warning("Could not list shell extensions", exc_info=True) error = _("Could not list shell extensions") if error: cb = build_combo_box_text(None) build_label_beside_widget(self.name, cb, warning=error, hbox=self) self.widget_for_size_group = cb else: #include both system, and user themes #note: the default theme lives in /system/data/dir/gnome-shell/theme # and not themes/, so add it manually later dirs = [ os.path.join(d, "themes") for d in GLib.get_system_data_dirs() ] dirs += [ShellThemeTweak.THEME_DIR] dirs += [ShellThemeTweak.LEGACY_THEME_DIR] valid = walk_directories(dirs, lambda d: os.path.exists(os.path.join(d, "gnome-shell")) and \ os.path.exists(os.path.join(d, "gnome-shell", "gnome-shell.css"))) #the default value to reset the shell is an empty string valid.extend(("", )) #build a combo box with all the valid theme options #manually add Adwaita to represent the default cb = build_combo_box_text( self._settings.get_string( ShellThemeTweak.THEME_GSETTINGS_NAME), *make_combo_list_with_default( valid, "", default_text=_("<i>Default</i>"))) cb.connect('changed', self._on_combo_changed) self._combo = cb #a filechooser to install new themes chooser = FileChooserButton(_("Select a theme"), True, ["application/zip"]) chooser.connect("file-set", self._on_file_set) build_label_beside_widget(self.name, chooser, cb, hbox=self) self.widget_for_size_group = cb
class XSettingsOverrides: VARIANT_TYPES = { 'Gtk/ShellShowsAppMenu': GLib.Variant.new_int32, 'Gtk/EnablePrimaryPaste': GLib.Variant.new_int32, 'Gdk/WindowScalingFactor': GLib.Variant.new_int32, } def __init__(self): # Ensure we don't error out try: self._settings = GSettingsSetting( schema='org.gnome.settings-daemon.plugins.xsettings') except: self._settings = None logging.warn( "org.gnome.settings-daemon.plugins.xsettings not installed or running" ) if self._settings: self._variant = self._settings.get_value("overrides") def _dup_variant_as_dict(self): items = {} for k in list(self._variant.keys()): try: # variant override doesnt support .items() v = self._variant[k] items[k] = self.VARIANT_TYPES[k](v) except KeyError: pass return items def _dup_variant(self): return GLib.Variant('a{sv}', self._dup_variant_as_dict()) def _set_override(self, name, v): items = self._dup_variant_as_dict() items[name] = self.VARIANT_TYPES[name](v) n = GLib.Variant('a{sv}', items) self._settings.set_value('overrides', n) self._variant = self._settings.get_value("overrides") def _get_override(self, name, default): try: return self._variant[name] except KeyError: return default # while I could store meta type information in the VARIANT_TYPES # dict, its easiest to do default value handling and missing value # checks in dedicated functions def set_shell_shows_app_menu(self, v): self._set_override('Gtk/ShellShowsAppMenu', int(v)) def get_shell_shows_app_menu(self): return self._get_override('Gtk/ShellShowsAppMenu', True) def set_enable_primary_paste(self, v): self._set_override('Gtk/EnablePrimaryPaste', int(v)) def get_enable_primary_paste(self): return self._get_override('Gtk/EnablePrimaryPaste', True) def set_window_scaling_factor(self, v): self._set_override('Gdk/WindowScalingFactor', int(v)) def get_window_scaling_factor(self): return self._get_override('Gdk/WindowScalingFactor', 1)