class Scene(quickstart.scenes.BaseScene): """ Shortcuts preferences. """ events = {"toggled": ("enable_launcher", )} def convert_exit_action_from_dconf(self, value): """ Converts the exit action from dconf. """ value = self.settings.get_enum("last-exit-action") if not self.settings.get_boolean("lock-last-exit-action"): # Not locked, this is the "Last action" item return 0 else: return value def convert_exit_action_from_ui(self, value): """ Converts the exit action from the UI. """ if value == 0: # Not locked, unset lock-last-exit-action self.settings.set_boolean("lock-last-exit-action", False) return self.settings.get_string("last-exit-action") else: self.settings.set_boolean("lock-last-exit-action", True) return ALLOWED_ACTIONS[value - 1] def on_enable_launcher_toggled(self, checkbutton): """ Fired when the "Enable launcher" checkbutton has been toggled. """ self.objects.enable_launcher_notice.set_visible( not self.objects.enable_launcher_notice.get_visible()) def prepare_scene(self): """ Scene set-up. """ self.scene_container = self.objects.main self.settings = Settings("org.semplicelinux.vera") self.desktop_settings = Settings("org.semplicelinux.vera.desktop") # Set-up actions combobox renderer = Gtk.CellRendererText() self.objects.last_exit_action.pack_start(renderer, True) self.objects.last_exit_action.add_attribute(renderer, "text", 0) self.settings.bind_with_convert("last-exit-action", self.objects.last_exit_action, "active", self.convert_exit_action_from_dconf, self.convert_exit_action_from_ui) # Confirmation window self.settings.bind("hide-exit-window", self.objects.hide_exit_window, "active") # Ninja shortcut self.settings.bind("ninja-shortcut", self.objects.ninja_shortcut, "active") # Ninja container self.objects.ninja_shortcut.bind_property("active", self.objects.ninja_container, "sensitive") # Desktop launcher self.desktop_settings.bind("show-launcher", self.objects.enable_launcher, "active")
class Scene(quickstart.scenes.BaseScene): """ Desktop preferences. """ events = { "item-activated": ("wallpapers", ), "response": ("add_background_window", "about_background_dialog"), "update_preview": ("add_background_window", ), "toggled": ("select_entire_directories", ), "clicked": ("add_background", "remove_background", "about_button"), } wallpapers = {} infos = configparser.ConfigParser() properties = Properties() def new_rgba_from_string(self, string): """ Given a string, return a parsed Gdk.RGBA. """ rgba = Gdk.RGBA() rgba.parse(string) return rgba def get_selection(self): """ Returns the TreeIter of the current selection. """ item = self.objects.wallpapers.get_selected_items()[0] return self.objects.wallpaper_list.get_iter(item) def set_selection(self, path): """ Sets the selected wallpaper given its path (not TreePath, the path of the wallpaper). """ if path in self.wallpapers: self.objects.wallpapers.select_path( self.objects.wallpaper_list.get_path(self.wallpapers[path])) # Show/Hide the About button if os.path.basename( self.objects.wallpaper_list.get_value( self.get_selection(), 0)) in self.infos: GObject.idle_add(self.objects.about_button.show) else: GObject.idle_add(self.objects.about_button.hide) else: # The wallpaper is not in our list, so we need to add it now... if os.path.exists(path): self.add_wallpaper_to_list(path) return self.set_selection(path) # Restart def on_select_entire_directories_toggled(self, checkbutton): """ Fired when the user presses the "Select entire directories" CheckButton in the FileChooser. """ self.objects.add_background_window.set_action( Gtk.FileChooserAction.OPEN if not checkbutton.get_active() else Gtk .FileChooserAction.SELECT_FOLDER) def on_add_background_window_update_preview(self, window): """ Fired when the preview of the window should be updated. """ filename = window.get_preview_filename() if not os.path.isfile(filename): window.set_preview_widget_active(False) return else: window.set_preview_widget_active(True) try: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( window.get_preview_filename(), 150, 200, True) self.objects.preview.set_from_pixbuf(pixbuf) except: window.set_preview_widget_active(False) def on_add_background_window_response(self, window, response_id): """ Fired when the user presses an action button in the FileChooser shown when adding a new wallpaper/directory. """ if response_id == Gtk.ResponseType.ACCEPT: # Add background _queue_repopulation = False for wall in window.get_filenames(): if window.get_action() == Gtk.FileChooserAction.OPEN: # Single files, no directories, so append to "include" if wall in self.wallpapers: # Already there! continue include = self.settings.get_strv("background-include") exclude = self.settings.get_strv("background-exclude") if wall in exclude: # Already excluded, so we can simply remove it # from the list exclude.remove(wall) elif wall not in include: # Not excluded, append to the include list include.append(wall) self.add_wallpaper_to_list(wall) self.settings.set_strv("background-include", include) self.settings.set_strv("background-exclude", exclude) else: # Entire directories, append them to the search path background_search_paths = self.settings.get_strv( "background-search-paths") if wall in background_search_paths: # Already there! continue background_search_paths.append(wall) self.settings.set_strv("background-search-paths", background_search_paths) # Queue _queue_repopulation = True if _queue_repopulation: # Repopulate self.populate_wallpapers() window.hide() def on_about_background_dialog_response(self, window, response_id): """ Fired when the user closes the about background dialog. """ window.hide() def on_about_button_clicked(self, button): """ Fired when the about button has been clicked. """ # Populate itr = self.get_selection() wall = os.path.basename(self.objects.wallpaper_list.get_value(itr, 0)) self.objects.name.set_label(self.infos[wall]["Name"] if "Name" in self.infos[wall] else "") self.objects.description.set_label( self.infos[wall]["Description"] if "Description" in self.infos[wall] else "") self.objects.author.set_label(self.infos[wall]["Author"] if "Author" in self.infos[wall] else "") self.objects.license.set_label(self.infos[wall]["License"] if "License" in self.infos[wall] else "") if "LicenseLink" in self.infos[wall]: self.objects.license.set_sensitive(True) self.objects.license.set_uri(self.infos[wall]["LicenseLink"]) else: self.objects.license.set_sensitive(False) self.objects.license.set_uri("") if "Link" in self.infos[wall]: self.objects.name.set_sensitive(True) self.objects.name.set_uri(self.infos[wall]["Link"]) else: self.objects.name.set_sensitive(False) self.objects.name.set_uri("") self.objects.about_background_dialog.run() def on_add_background_clicked(self, button): """ Fired when the add background button has been clicked. """ self.objects.add_background_window.run() def on_remove_background_clicked(self, button): """ Fired when the remove background button has been clicked. """ itr = self.get_selection() wall = self.objects.wallpaper_list.get_value(itr, 0) # If wallpaper is in background-include, remove from there. # Otherwise, add an exclusion rule include = self.settings.get_strv("background-include") if wall in include: include.remove(wall) self.settings.set_strv("background-include", include) else: exclude = self.settings.get_strv("background-exclude") exclude.append(wall) self.settings.set_strv("background-exclude", exclude) new = self.objects.wallpaper_list.iter_next(itr) if not new: # Unable to set next (probably this was the last iter), so # use the previous new = self.objects.wallpaper_list.iter_previous(itr) # If new == None (again), probably this was the only one wallpaper. # We can't do anything, so we'll leave an inconsistent state if new: path = self.objects.wallpaper_list.get_path(new) self.objects.wallpapers.select_path(path) self.objects.wallpapers.emit("item_activated", path) self.objects.wallpaper_list.remove(itr) del self.wallpapers[wall] def on_wallpapers_item_activated(self, widget, path): """ Fired when the user changes the wallpaper. """ itr = self.objects.wallpaper_list.get_iter(path) wall = self.objects.wallpaper_list.get_value(itr, 0) # Show/Hide the About button if os.path.basename(wall) in self.infos: GObject.idle_add(self.objects.about_button.show) else: GObject.idle_add(self.objects.about_button.hide) current_wallpapers = self.properties.current_wallpapers if self.properties.current_selected_monitor == 0: # "All monitors", change only the first item in the array current_wallpapers[0] = wall else: # Single monitor, change the relevant item current_wallpapers[self.properties.current_selected_monitor - 1] = wall self.properties.set_property("current-wallpapers", current_wallpapers) def add_wallpaper_to_list(self, path, set=False): """ Appends the given wallpaper to the list. """ if Gio.File.new_for_path(path).query_info( Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, Gio.FileQueryInfoFlags.NONE).get_content_type( ) in SUPPORTED_MIMETYPES: try: itr = self.objects.wallpaper_list.append( (path, GdkPixbuf.Pixbuf.new_from_file_at_scale( path, 150, 200, True))) self.wallpapers[path] = itr if set: self.set_selection(path) except: pass def load_wallpaperpack(self, path): """ Loads the given wallpaperpack. """ try: self.infos.read(path) except: # FIXME: Implement true logging print("Unable to load wallpaperpack %s" % path) @quickstart.threads.thread def populate_wallpapers(self): """ Populates the wallpaper_list. """ # Clear things up self.wallpapers = {} self.objects.wallpaper_list.clear() excluded = self.settings.get_strv("background-exclude") include = self.settings.get_strv("background-include") default = self.settings.get_strv("image-path")[0] for directory in self.settings.get_strv("background-search-paths"): for root, dirs, files in os.walk(directory): for wall in files: path = os.path.join(root, wall) if not os.path.exists(path) or path in excluded: continue # .wallpaperpack file? if wall.endswith(".wallpaperpack"): # Load it self.load_wallpaperpack(path) GObject.idle_add(self.add_wallpaper_to_list, path, (path == default)) # Add to the Included wallpapers for wallpaper in include: if not os.path.exists(wallpaper): continue GObject.idle_add(self.add_wallpaper_to_list, wallpaper, (path == default)) #GObject.idle_add(self.set_selection, self.settings.get_strv("image-path")[0]) GObject.idle_add(self.objects.wallpapers.set_sensitive, True) def on_current_selected_monitor_changed(self, properties, param): """ Fired when the current-selected-monitor property in Properties has been changed. """ if self.properties.current_selected_monitor == 0: # All monitors, use the first wallpaper everywhere self.properties.set_property( "current-wallpapers", [(self.properties.current_wallpapers[x] if x == 0 else "") for x in range(0, self.monitor_number)]) self.set_selection(self.properties.current_wallpapers[0]) else: # Single monitor, simply re-set selection self.set_selection(self.properties.current_wallpapers[ self.properties.current_selected_monitor - 1] if self.properties.current_wallpapers[ self.properties.current_selected_monitor - 1] != "" else self.properties.current_wallpapers[0]) def prepare_scene(self): """ Called when doing the scene setup. """ self.scene_container = self.objects.main self.objects.wallpapers.set_pixbuf_column(1) self.settings = Settings("org.semplicelinux.vera.desktop") self.openbox_settings = Settings("org.semplicelinux.vera.openbox") # Build monitor list self.monitor_number = Gdk.Screen.get_default().get_n_monitors() # Build monitor chooser self.monitor_model = Gtk.ListStore(str) self.objects.monitor_chooser.set_model(self.monitor_model) renderer = Gtk.CellRendererText() self.objects.monitor_chooser.pack_start(renderer, True) self.objects.monitor_chooser.add_attribute(renderer, "text", 0) # Current wallpaper self.settings.bind_with_convert( "image-path", self.properties, "current-wallpapers", lambda x: [(x[y] if y < len(x) else "") for y in range(0, self.monitor_number)], lambda x: x) # Populate monitor model self.monitor_model.insert_with_valuesv( -1, [0], [_("All monitors")]) # "All monitors" for monitor in range(1, self.monitor_number + 1): self.monitor_model.insert_with_valuesv( -1, [0], [_("Monitor %d") % (monitor)]) self.objects.monitor_chooser.set_active(0) self.objects.monitor_chooser.bind_property( "active", self.properties, "current-selected-monitor", GObject.BindingFlags.SYNC_CREATE) self.properties.connect("notify::current-selected-monitor", self.on_current_selected_monitor_changed) if self.properties.current_wallpapers.count( "") == self.monitor_number - 1: # Probably we are in an "All monitors" situation # We do not use set_active() to avoid trigger an useless write action # to dconf. self.set_selection(self.properties.current_wallpapers[0]) else: # Single monitor, default to Monitor 1 self.objects.monitor_chooser.set_active(1) # Show it if we should if self.monitor_number > 1: self.objects.monitor_chooser.show() # Background color self.settings.bind_with_convert("background-color", self.objects.background_color, "rgba", lambda x: self.new_rgba_from_string(x), lambda x: x.to_string()) # Background mode renderer = Gtk.CellRendererText() self.objects.background_mode.pack_start(renderer, True) self.objects.background_mode.add_attribute(renderer, "text", 1) self.settings.bind("background-mode", self.objects.background_mode, "active_id") # Background random enabled? self.settings.bind("background-random-enabled", self.objects.background_random_enabled, "active") # Background random timeout self.settings.bind("background-random-timeout", self.objects.background_random_timeout, "value") # Ensure the random timeout spinbutton is insensitive if # the checkbutton is not active self.objects.background_random_enabled.bind_property( "active", self.objects.background_random_timeout_spin, "sensitive", GObject.BindingFlags.SYNC_CREATE) # Virtual desktops self.openbox_settings.bind("desktops-number", self.objects.virtual_desktops_spin, "value") # Prepare the "Add background" dialog... self.objects.add_background_window.add_buttons(_("_Cancel"), Gtk.ResponseType.CANCEL, _("_Open"), Gtk.ResponseType.ACCEPT) self.objects.all_files.set_name(_("All Files")) self.objects.image_filter.set_name(_("Images")) self.objects.add_background_window.add_filter( self.objects.image_filter) self.objects.add_background_window.add_filter(self.objects.all_files) # Prepare the "About background" dialog... self.objects.about_background_dialog.add_buttons( _("_Close"), Gtk.ResponseType.CLOSE) self.objects.main.show_all() # Ensure the user doesn't change wallpaper while we are builing the list GObject.idle_add(self.objects.wallpapers.set_sensitive, False) self.populate_wallpapers()
class Scene(quickstart.scenes.BaseScene): """ Shortcuts preferences. """ events = { "toggled" : ("enable_launcher",) } def convert_exit_action_from_dconf(self, value): """ Converts the exit action from dconf. """ value = self.settings.get_enum("last-exit-action") if not self.settings.get_boolean("lock-last-exit-action"): # Not locked, this is the "Last action" item return 0 else: return value def convert_exit_action_from_ui(self, value): """ Converts the exit action from the UI. """ if value == 0: # Not locked, unset lock-last-exit-action self.settings.set_boolean("lock-last-exit-action", False) return self.settings.get_string("last-exit-action") else: self.settings.set_boolean("lock-last-exit-action", True) return ALLOWED_ACTIONS[value-1] def on_enable_launcher_toggled(self, checkbutton): """ Fired when the "Enable launcher" checkbutton has been toggled. """ self.objects.enable_launcher_notice.set_visible( not self.objects.enable_launcher_notice.get_visible() ) def prepare_scene(self): """ Scene set-up. """ self.scene_container = self.objects.main self.settings = Settings("org.semplicelinux.vera") self.desktop_settings = Settings("org.semplicelinux.vera.desktop") # Set-up actions combobox renderer = Gtk.CellRendererText() self.objects.last_exit_action.pack_start(renderer, True) self.objects.last_exit_action.add_attribute(renderer, "text", 0) self.settings.bind_with_convert( "last-exit-action", self.objects.last_exit_action, "active", self.convert_exit_action_from_dconf, self.convert_exit_action_from_ui ) # Confirmation window self.settings.bind( "hide-exit-window", self.objects.hide_exit_window, "active" ) # Ninja shortcut self.settings.bind( "ninja-shortcut", self.objects.ninja_shortcut, "active" ) # Ninja container self.objects.ninja_shortcut.bind_property( "active", self.objects.ninja_container, "sensitive" ) # Desktop launcher self.desktop_settings.bind( "show-launcher", self.objects.enable_launcher, "active" )
class GtkThemeFrame(CommonFrame): """ This is the Frame with controls to change the GTK+ theme. """ SEARCH_PATH = ("/usr/share/themes", os.path.expanduser("~/.themes")) @property def available_themes(self): """ Returns the available themes, searching in SEARCH_PATH. """ themes = [] for directory in self.SEARCH_PATH: if not os.path.exists(directory): continue for theme in os.listdir(directory): path = os.path.join(directory, theme) if theme not in themes and ( os.path.isdir(path) and os.path.exists(os.path.join(path, "gtk-3.0"))): themes.append(theme) themes.sort() return themes @quickstart.threads.on_idle def populate_themes(self): """ Populates the theme list. """ self.themes = {} count = -1 for theme in self.available_themes: count += 1 self.combobox.append_text(theme) # Add to self.themes self.themes[theme] = count # Bind self.settings.bind_with_convert( "theme-name", self.combobox, "active", lambda x: self.themes[x] if x in self.themes else -1, lambda x: self.combobox.get_active_text()) def new_rgba_from_string(self, string): """ Given a string, return a parsed Gdk.RGBA. """ rgba = Gdk.RGBA() rgba.parse(string) return rgba def __init__(self, settings): """ Initializes the frame. """ super().__init__(name=_("Widgets")) # Settings self.settings = settings self.desktopsettings = Settings("org.semplicelinux.vera.desktop") # Container self.main_container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) # Combobox self.combobox_container = Gtk.Box( orientation=Gtk.Orientation.HORIZONTAL) self.combobox = Gtk.ComboBoxText() self.combobox_label = Gtk.Label(_("Theme")) self.combobox_label.set_alignment(0, 0.50) self.combobox_container.pack_start(self.combobox_label, True, True, 0) self.combobox_container.pack_start(self.combobox, False, False, 0) # Populate it and bind self.populate_themes() # Images in buttons self.button_images = Gtk.CheckButton(_("Show images in buttons")) self.settings.bind("button-images", self.button_images, "active") # Images in menus self.menu_images = Gtk.CheckButton(_("Show images in menus")) self.settings.bind("menu-images", self.menu_images, "active") # Vera color self.vera_color_enabled = Gtk.CheckButton( _("Use custom color for selected items (when supported)")) self.desktopsettings.bind("vera-color-enabled", self.vera_color_enabled, "active") # Vera color selection self.vera_color_selection = Gtk.Box( orientation=Gtk.Orientation.VERTICAL) self.vera_color_selection.set_margin_start(20) self.vera_color_enabled.bind_property("active", self.vera_color_selection, "sensitive", GObject.BindingFlags.SYNC_CREATE) self.vera_color_from_wallpaper = Gtk.RadioButton.new_with_label_from_widget( None, _("Pick color from the current wallpaper")) self.vera_color_manual_container = Gtk.Box( orientation=Gtk.Orientation.HORIZONTAL) self.vera_color_manual_color = Gtk.ColorButton() self.desktopsettings.bind_with_convert( "vera-color", self.vera_color_manual_color, "rgba", lambda x: self.new_rgba_from_string(x), lambda x: x.to_string()) self.vera_color_manual_color.set_sensitive(True) self.vera_color_manual = Gtk.RadioButton.new_with_label_from_widget( self.vera_color_from_wallpaper, _("Use this color")) self.vera_color_manual.bind_property("active", self.vera_color_manual_color, "sensitive", GObject.BindingFlags.SYNC_CREATE) self.desktopsettings.bind("vera-color-lock", self.vera_color_manual, "active") self.vera_color_manual_container.pack_start(self.vera_color_manual, True, True, 0) self.vera_color_manual_container.pack_start( self.vera_color_manual_color, False, False, 0) self.vera_color_selection.pack_start(self.vera_color_from_wallpaper, False, False, 0) self.vera_color_selection.pack_start(self.vera_color_manual_container, False, False, 2) self.main_container.pack_start(self.combobox_container, False, False, 0) self.main_container.pack_start(self.button_images, False, False, 2) self.main_container.pack_start(self.menu_images, False, False, 2) self.main_container.pack_start(self.vera_color_enabled, False, False, 2) self.main_container.pack_start(self.vera_color_selection, False, False, 2) self.get_alignment().add(self.main_container)
class GtkThemeFrame(CommonFrame): """ This is the Frame with controls to change the GTK+ theme. """ SEARCH_PATH = ("/usr/share/themes", os.path.expanduser("~/.themes")) @property def available_themes(self): """ Returns the available themes, searching in SEARCH_PATH. """ themes = [] for directory in self.SEARCH_PATH: if not os.path.exists(directory): continue for theme in os.listdir(directory): path = os.path.join(directory, theme) if theme not in themes and ( os.path.isdir(path) and os.path.exists(os.path.join(path, "gtk-3.0")) ): themes.append(theme) themes.sort() return themes @quickstart.threads.on_idle def populate_themes(self): """ Populates the theme list. """ self.themes = {} count = -1 for theme in self.available_themes: count += 1 self.combobox.append_text(theme) # Add to self.themes self.themes[theme] = count # Bind self.settings.bind_with_convert( "theme-name", self.combobox, "active", lambda x: self.themes[x] if x in self.themes else -1, lambda x: self.combobox.get_active_text() ) def new_rgba_from_string(self, string): """ Given a string, return a parsed Gdk.RGBA. """ rgba = Gdk.RGBA() rgba.parse(string) return rgba def __init__(self, settings): """ Initializes the frame. """ super().__init__(name=_("Widgets")) # Settings self.settings = settings self.desktopsettings = Settings("org.semplicelinux.vera.desktop") # Container self.main_container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) # Combobox self.combobox_container = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self.combobox = Gtk.ComboBoxText() self.combobox_label = Gtk.Label(_("Theme")) self.combobox_label.set_alignment(0, 0.50) self.combobox_container.pack_start(self.combobox_label, True, True, 0) self.combobox_container.pack_start(self.combobox, False, False, 0) # Populate it and bind self.populate_themes() # Images in buttons self.button_images = Gtk.CheckButton(_("Show images in buttons")) self.settings.bind( "button-images", self.button_images, "active" ) # Images in menus self.menu_images = Gtk.CheckButton(_("Show images in menus")) self.settings.bind( "menu-images", self.menu_images, "active" ) # Vera color self.vera_color_enabled = Gtk.CheckButton(_("Use custom color for selected items (when supported)")) self.desktopsettings.bind( "vera-color-enabled", self.vera_color_enabled, "active" ) # Vera color selection self.vera_color_selection = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.vera_color_selection.set_margin_start(20) self.vera_color_enabled.bind_property( "active", self.vera_color_selection, "sensitive", GObject.BindingFlags.SYNC_CREATE ) self.vera_color_from_wallpaper = Gtk.RadioButton.new_with_label_from_widget(None, _("Pick color from the current wallpaper")) self.vera_color_manual_container = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self.vera_color_manual_color = Gtk.ColorButton() self.desktopsettings.bind_with_convert( "vera-color", self.vera_color_manual_color, "rgba", lambda x: self.new_rgba_from_string(x), lambda x: x.to_string() ) self.vera_color_manual_color.set_sensitive(True) self.vera_color_manual = Gtk.RadioButton.new_with_label_from_widget(self.vera_color_from_wallpaper, _("Use this color")) self.vera_color_manual.bind_property( "active", self.vera_color_manual_color, "sensitive", GObject.BindingFlags.SYNC_CREATE ) self.desktopsettings.bind( "vera-color-lock", self.vera_color_manual, "active" ) self.vera_color_manual_container.pack_start(self.vera_color_manual, True, True, 0) self.vera_color_manual_container.pack_start(self.vera_color_manual_color, False, False, 0) self.vera_color_selection.pack_start(self.vera_color_from_wallpaper, False, False, 0) self.vera_color_selection.pack_start(self.vera_color_manual_container, False, False, 2) self.main_container.pack_start(self.combobox_container, False, False, 0) self.main_container.pack_start(self.button_images, False, False, 2) self.main_container.pack_start(self.menu_images, False, False, 2) self.main_container.pack_start(self.vera_color_enabled, False, False, 2) self.main_container.pack_start(self.vera_color_selection, False, False, 2) self.get_alignment().add(self.main_container)
class Scene(quickstart.scenes.BaseScene): """ Desktop preferences. """ events = { "item-activated": ("wallpapers",), "response": ("add_background_window", "about_background_dialog"), "update_preview" : ("add_background_window",), "toggled": ("select_entire_directories",), "clicked": ( "add_background", "remove_background", "about_button" ), } wallpapers = {} infos = configparser.ConfigParser() properties = Properties() def new_rgba_from_string(self, string): """ Given a string, return a parsed Gdk.RGBA. """ rgba = Gdk.RGBA() rgba.parse(string) return rgba def get_selection(self): """ Returns the TreeIter of the current selection. """ item = self.objects.wallpapers.get_selected_items()[0] return self.objects.wallpaper_list.get_iter(item) def set_selection(self, path): """ Sets the selected wallpaper given its path (not TreePath, the path of the wallpaper). """ if path in self.wallpapers: self.objects.wallpapers.select_path(self.objects.wallpaper_list.get_path(self.wallpapers[path])) # Show/Hide the About button if os.path.basename(self.objects.wallpaper_list.get_value(self.get_selection(), 0)) in self.infos: GObject.idle_add(self.objects.about_button.show) else: GObject.idle_add(self.objects.about_button.hide) else: # The wallpaper is not in our list, so we need to add it now... if os.path.exists(path): self.add_wallpaper_to_list(path) return self.set_selection(path) # Restart def on_select_entire_directories_toggled(self, checkbutton): """ Fired when the user presses the "Select entire directories" CheckButton in the FileChooser. """ self.objects.add_background_window.set_action( Gtk.FileChooserAction.OPEN if not checkbutton.get_active() else Gtk.FileChooserAction.SELECT_FOLDER ) def on_add_background_window_update_preview(self, window): """ Fired when the preview of the window should be updated. """ filename = window.get_preview_filename() if not os.path.isfile(filename): window.set_preview_widget_active(False) return else: window.set_preview_widget_active(True) try: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( window.get_preview_filename(), 150, 200, True ) self.objects.preview.set_from_pixbuf(pixbuf) except: window.set_preview_widget_active(False) def on_add_background_window_response(self, window, response_id): """ Fired when the user presses an action button in the FileChooser shown when adding a new wallpaper/directory. """ if response_id == Gtk.ResponseType.ACCEPT: # Add background _queue_repopulation = False for wall in window.get_filenames(): if window.get_action() == Gtk.FileChooserAction.OPEN: # Single files, no directories, so append to "include" if wall in self.wallpapers: # Already there! continue include = self.settings.get_strv("background-include") exclude = self.settings.get_strv("background-exclude") if wall in exclude: # Already excluded, so we can simply remove it # from the list exclude.remove(wall) elif wall not in include: # Not excluded, append to the include list include.append(wall) self.add_wallpaper_to_list(wall) self.settings.set_strv("background-include", include) self.settings.set_strv("background-exclude", exclude) else: # Entire directories, append them to the search path background_search_paths = self.settings.get_strv("background-search-paths") if wall in background_search_paths: # Already there! continue background_search_paths.append(wall) self.settings.set_strv("background-search-paths", background_search_paths) # Queue _queue_repopulation = True if _queue_repopulation: # Repopulate self.populate_wallpapers() window.hide() def on_about_background_dialog_response(self, window, response_id): """ Fired when the user closes the about background dialog. """ window.hide() def on_about_button_clicked(self, button): """ Fired when the about button has been clicked. """ # Populate itr = self.get_selection() wall = os.path.basename(self.objects.wallpaper_list.get_value(itr, 0)) self.objects.name.set_label( self.infos[wall]["Name"] if "Name" in self.infos[wall] else "" ) self.objects.description.set_label( self.infos[wall]["Description"] if "Description" in self.infos[wall] else "" ) self.objects.author.set_label( self.infos[wall]["Author"] if "Author" in self.infos[wall] else "" ) self.objects.license.set_label( self.infos[wall]["License"] if "License" in self.infos[wall] else "" ) if "LicenseLink" in self.infos[wall]: self.objects.license.set_sensitive(True) self.objects.license.set_uri(self.infos[wall]["LicenseLink"]) else: self.objects.license.set_sensitive(False) self.objects.license.set_uri("") if "Link" in self.infos[wall]: self.objects.name.set_sensitive(True) self.objects.name.set_uri(self.infos[wall]["Link"]) else: self.objects.name.set_sensitive(False) self.objects.name.set_uri("") self.objects.about_background_dialog.run() def on_add_background_clicked(self, button): """ Fired when the add background button has been clicked. """ self.objects.add_background_window.run() def on_remove_background_clicked(self, button): """ Fired when the remove background button has been clicked. """ itr = self.get_selection() wall = self.objects.wallpaper_list.get_value(itr, 0) # If wallpaper is in background-include, remove from there. # Otherwise, add an exclusion rule include = self.settings.get_strv("background-include") if wall in include: include.remove(wall) self.settings.set_strv("background-include", include) else: exclude = self.settings.get_strv("background-exclude") exclude.append(wall) self.settings.set_strv("background-exclude", exclude) new = self.objects.wallpaper_list.iter_next(itr) if not new: # Unable to set next (probably this was the last iter), so # use the previous new = self.objects.wallpaper_list.iter_previous(itr) # If new == None (again), probably this was the only one wallpaper. # We can't do anything, so we'll leave an inconsistent state if new: path = self.objects.wallpaper_list.get_path(new) self.objects.wallpapers.select_path(path) self.objects.wallpapers.emit("item_activated", path) self.objects.wallpaper_list.remove(itr) del self.wallpapers[wall] def on_wallpapers_item_activated(self, widget, path): """ Fired when the user changes the wallpaper. """ itr = self.objects.wallpaper_list.get_iter(path) wall = self.objects.wallpaper_list.get_value(itr, 0) # Show/Hide the About button if os.path.basename(wall) in self.infos: GObject.idle_add(self.objects.about_button.show) else: GObject.idle_add(self.objects.about_button.hide) current_wallpapers = self.properties.current_wallpapers if self.properties.current_selected_monitor == 0: # "All monitors", change only the first item in the array current_wallpapers[0] = wall else: # Single monitor, change the relevant item current_wallpapers[self.properties.current_selected_monitor-1] = wall self.properties.set_property("current-wallpapers", current_wallpapers) def add_wallpaper_to_list(self, path, set=False): """ Appends the given wallpaper to the list. """ if Gio.File.new_for_path(path).query_info( Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, Gio.FileQueryInfoFlags.NONE ).get_content_type() in SUPPORTED_MIMETYPES: try: itr = self.objects.wallpaper_list.append( ( path, GdkPixbuf.Pixbuf.new_from_file_at_scale( path, 150, 200, True ) ) ) self.wallpapers[path] = itr if set: self.set_selection(path) except: pass def load_wallpaperpack(self, path): """ Loads the given wallpaperpack. """ try: self.infos.read(path) except: # FIXME: Implement true logging print("Unable to load wallpaperpack %s" % path) @quickstart.threads.thread def populate_wallpapers(self): """ Populates the wallpaper_list. """ # Clear things up self.wallpapers = {} self.objects.wallpaper_list.clear() excluded = self.settings.get_strv("background-exclude") include = self.settings.get_strv("background-include") default = self.settings.get_strv("image-path")[0] for directory in self.settings.get_strv("background-search-paths"): for root, dirs, files in os.walk(directory): for wall in files: path = os.path.join(root, wall) if not os.path.exists(path) or path in excluded: continue # .wallpaperpack file? if wall.endswith(".wallpaperpack"): # Load it self.load_wallpaperpack(path) GObject.idle_add(self.add_wallpaper_to_list, path, (path == default)) # Add to the Included wallpapers for wallpaper in include: if not os.path.exists(wallpaper): continue GObject.idle_add(self.add_wallpaper_to_list, wallpaper, (path == default)) #GObject.idle_add(self.set_selection, self.settings.get_strv("image-path")[0]) GObject.idle_add(self.objects.wallpapers.set_sensitive, True) def on_current_selected_monitor_changed(self, properties, param): """ Fired when the current-selected-monitor property in Properties has been changed. """ if self.properties.current_selected_monitor == 0: # All monitors, use the first wallpaper everywhere self.properties.set_property( "current-wallpapers", [(self.properties.current_wallpapers[x] if x == 0 else "") for x in range(0, self.monitor_number)] ) self.set_selection(self.properties.current_wallpapers[0]) else: # Single monitor, simply re-set selection self.set_selection( self.properties.current_wallpapers[self.properties.current_selected_monitor-1] if self.properties.current_wallpapers[ self.properties.current_selected_monitor-1] != "" else self.properties.current_wallpapers[0] ) def prepare_scene(self): """ Called when doing the scene setup. """ self.scene_container = self.objects.main self.objects.wallpapers.set_pixbuf_column(1) self.settings = Settings("org.semplicelinux.vera.desktop") self.openbox_settings = Settings("org.semplicelinux.vera.openbox") # Build monitor list self.monitor_number = Gdk.Screen.get_default().get_n_monitors() # Build monitor chooser self.monitor_model = Gtk.ListStore(str) self.objects.monitor_chooser.set_model(self.monitor_model) renderer = Gtk.CellRendererText() self.objects.monitor_chooser.pack_start(renderer, True) self.objects.monitor_chooser.add_attribute(renderer, "text", 0) # Current wallpaper self.settings.bind_with_convert( "image-path", self.properties, "current-wallpapers", lambda x: [(x[y] if y < len(x) else "") for y in range(0, self.monitor_number)], lambda x: x ) # Populate monitor model self.monitor_model.insert_with_valuesv(-1, [0], [_("All monitors")]) # "All monitors" for monitor in range(1, self.monitor_number+1): self.monitor_model.insert_with_valuesv(-1, [0], [_("Monitor %d") % (monitor)]) self.objects.monitor_chooser.set_active(0) self.objects.monitor_chooser.bind_property( "active", self.properties, "current-selected-monitor", GObject.BindingFlags.SYNC_CREATE ) self.properties.connect("notify::current-selected-monitor", self.on_current_selected_monitor_changed) if self.properties.current_wallpapers.count("") == self.monitor_number-1: # Probably we are in an "All monitors" situation # We do not use set_active() to avoid trigger an useless write action # to dconf. self.set_selection(self.properties.current_wallpapers[0]) else: # Single monitor, default to Monitor 1 self.objects.monitor_chooser.set_active(1) # Show it if we should if self.monitor_number > 1: self.objects.monitor_chooser.show() # Background color self.settings.bind_with_convert( "background-color", self.objects.background_color, "rgba", lambda x: self.new_rgba_from_string(x), lambda x: x.to_string() ) # Background mode renderer = Gtk.CellRendererText() self.objects.background_mode.pack_start(renderer, True) self.objects.background_mode.add_attribute(renderer, "text", 1) self.settings.bind( "background-mode", self.objects.background_mode, "active_id" ) # Background random enabled? self.settings.bind( "background-random-enabled", self.objects.background_random_enabled, "active" ) # Background random timeout self.settings.bind( "background-random-timeout", self.objects.background_random_timeout, "value" ) # Ensure the random timeout spinbutton is insensitive if # the checkbutton is not active self.objects.background_random_enabled.bind_property( "active", self.objects.background_random_timeout_spin, "sensitive", GObject.BindingFlags.SYNC_CREATE ) # Virtual desktops self.openbox_settings.bind( "desktops-number", self.objects.virtual_desktops_spin, "value" ) # Prepare the "Add background" dialog... self.objects.add_background_window.add_buttons( _("_Cancel"), Gtk.ResponseType.CANCEL, _("_Open"), Gtk.ResponseType.ACCEPT ) self.objects.all_files.set_name(_("All Files")) self.objects.image_filter.set_name(_("Images")) self.objects.add_background_window.add_filter(self.objects.image_filter) self.objects.add_background_window.add_filter(self.objects.all_files) # Prepare the "About background" dialog... self.objects.about_background_dialog.add_buttons( _("_Close"), Gtk.ResponseType.CLOSE ) self.objects.main.show_all() # Ensure the user doesn't change wallpaper while we are builing the list GObject.idle_add(self.objects.wallpapers.set_sensitive, False) self.populate_wallpapers()