def __init__(self): TweakGroup.__init__(self, _("Shell Extensions")) extension_tweaks = [] sg = build_horizontal_sizegroup() #check the shell is running try: shell = GnomeShellFactory().get_shell() #add the extension installer extension_tweaks.append( _ShellExtensionInstallerTweak(shell, size_group=sg)) try: #add a tweak for each installed extension for extension in shell.list_extensions().values(): try: extension_tweaks.append( _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", exc_info=True) self.set_tweaks(*extension_tweaks)
def __init__(self): extension_tweaks = [] sg = build_horizontal_sizegroup() #check the shell is running try: shell = GnomeShellFactory().get_shell() if shell is None: raise Exception( "Shell not running or DBus service not available") version = tuple(shell.version.split(".")) ego = ExtensionsDotGnomeDotOrg(version) try: #add a tweak for each installed extension extensions = sorted(list(shell.list_extensions().values()), key=itemgetter("name")) for extension in extensions: try: extension_widget = _ShellExtensionTweak(shell, extension, size_group=sg) extension_tweaks.append(extension_widget) if extension.get("type") == GnomeShell.EXTENSION_TYPE[ "PER_USER"]: ego.connect("got-extension-info", self._got_info, extension, extension_widget) ego.query_extension_info(extension["uuid"]) except: logging.warning("Invalid extension", exc_info=True) except: logging.warning("Error listing extensions", exc_info=True) except: logging.warning("Error detecting shell", exc_info=True) ListBoxTweakGroup.__init__(self, _("Extensions"), *extension_tweaks, activatable=True) if shell is None: return # we're done self.props.valign = Gtk.Align.FILL self.titlebar_widget = Gtk.Switch(visible=True) shell._settings.bind("disable-user-extensions", self.titlebar_widget, "active", Gio.SettingsBindFlags.INVERT_BOOLEAN) self.set_header_func(self._list_header_func, None) self.connect("row-activated", self._on_row_activated, None) if not len(extension_tweaks): placeholder = _ExtensionsBlankState() self.set_placeholder(placeholder) self.tweaks.append(placeholder)
def __init__(self): extension_tweaks = [] sg = build_horizontal_sizegroup() #check the shell is running try: shell = GnomeShellFactory().get_shell() if shell is None: raise Exception( "Shell not running or DBus service not available") version = tuple(shell.version.split(".")) ego = ExtensionsDotGnomeDotOrg(version) try: #add a tweak for each installed extension extensions = sorted(shell.list_extensions().values(), key=itemgetter("name")) for extension in extensions: try: extension_widget = _ShellExtensionTweak(shell, extension, size_group=sg) extension_tweaks.append(extension_widget) if extension.get("type") == GnomeShell.EXTENSION_TYPE[ "PER_USER"]: ego.connect("got-extension-info", self._got_info, extension, extension_widget) ego.query_extension_info(extension["uuid"]) except: logging.warning("Invalid extension", exc_info=True) except: logging.warning("Error listing extensions", exc_info=True) except: logging.warning("Error detecting shell", exc_info=True) #add the extension installer extension_tweaks.append( _ShellExtensionInstallerTweak(shell, size_group=sg)) ListBoxTweakGroup.__init__(self, _("Extensions"), *extension_tweaks) self.set_header_func(self._list_header_func, None)
def __init__(self): extension_tweaks = [] sg = build_horizontal_sizegroup() #check the shell is running try: shell = GnomeShellFactory().get_shell() if shell is None: raise Exception("Shell not running or DBus service not available") version = tuple(shell.version.split(".")) ego = ExtensionsDotGnomeDotOrg(version) try: #add a tweak for each installed extension extensions = sorted(shell.list_extensions().values(), key=itemgetter("name")) for extension in extensions: try: extension_widget = _ShellExtensionTweak(shell, extension, size_group=sg) extension_tweaks.append(extension_widget) if extension.get("type") == GnomeShell.EXTENSION_TYPE["PER_USER"]: ego.connect("got-extension-info", self._got_info, extension, extension_widget) ego.query_extension_info(extension["uuid"]) except: logging.warning("Invalid extension", exc_info=True) except: logging.warning("Error listing extensions", exc_info=True) except: logging.warning("Error detecting shell", exc_info=True) #add the extension installer extension_tweaks.append( _ShellExtensionInstallerTweak(shell, size_group=sg)) ListBoxTweakGroup.__init__(self, _("Extensions"), *extension_tweaks) self.set_header_func(self._list_header_func, None)
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
class ShellThemeTweak(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") 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 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: 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) self.widget = build_label_beside_widget(self.name, cb, warning=error) 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] 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 = ZipFileChooserButton(_("Select a theme")) chooser.connect("file-set", self._on_file_set) self.widget = build_label_beside_widget(self.name, chooser, cb) self.widget_for_size_group = cb