示例#1
0
class Module:
    name = "display"
    comment = _("Manage display settings")
    category = "hardware"

    def __init__(self, content_box):
        keywords = _("display, screen, monitor, layout, resolution, dual, lcd")
        self.sidePage = SidePage(_("Display"),
                                 "cs-display",
                                 keywords,
                                 content_box,
                                 module=self)
        self.display_c_widget = None

    def on_module_selected(self):
        if not self.loaded:
            print("Loading Display module")

            self.sidePage.stack = SettingsStack()
            self.sidePage.add_widget(self.sidePage.stack)

            page = SettingsPage()
            self.sidePage.stack.add_titled(page, "layout", _("Layout"))

            try:
                settings = page.add_section(_("Layout"))

                widget = SettingsWidget()
                widget.set_border_width(0)
                widget.set_margin_start(0)
                widget.set_margin_end(0)

                content = self.sidePage.content_box.c_manager.get_c_widget(
                    "display")
                widget.pack_start(content, True, True, 0)

                self.display_c_widget = content
                settings.add_row(widget)

            except Exception as detail:
                print(detail)

            page = SettingsPage()
            self.sidePage.stack.add_titled(page, "settings", _("Settings"))
            settings = page.add_section(_("Settings"))

            switch = GSettingsSwitch(
                _("Disable automatic screen rotation"),
                "org.cinnamon.settings-daemon.peripherals.touchscreen",
                "orientation-lock")
            switch.set_tooltip_text(
                _("Select this option to disable automatic screen rotation on hardware equipped with supported accelerometers."
                  ))
            settings.add_row(switch)

    def on_navigate_out_of_module(self):
        if self.display_c_widget:
            self.display_c_widget.hide()
示例#2
0
class Module:
    name = "display"
    comment = _("Manage display settings")
    category = "hardware"

    def __init__(self, content_box):
        keywords = _("display, screen, monitor, layout, resolution, dual, lcd")
        self.sidePage = SidePage(_("Display"),
                                 "cs-display",
                                 keywords,
                                 content_box,
                                 module=self)

    def on_module_selected(self):
        if not self.loaded:
            print("Loading Display module")

            self.sidePage.stack = SettingsStack()
            self.sidePage.add_widget(self.sidePage.stack)

            page = SettingsPage()
            self.sidePage.stack.add_titled(page, "layout", _("Layout"))

            try:
                settings = page.add_section(_("Layout"))
                widget = SettingsWidget()
                content = self.sidePage.content_box.c_manager.get_c_widget(
                    "display")
                widget.pack_start(content, True, True, 0)
                settings.add_row(widget)

            except Exception as detail:
                print(detail)

            page = SettingsPage()
            self.sidePage.stack.add_titled(page, "settings", _("Settings"))
            settings = page.add_section(_("Settings"))

            ui_scales = [[0, _("Auto")], [1, _("Normal")],
                         [2, _("Double (Hi-DPI)")]]
            combo = GSettingsComboBox(_("User interface scaling:"),
                                      "org.cinnamon.desktop.interface",
                                      "scaling-factor",
                                      ui_scales,
                                      valtype=int)
            settings.add_row(combo)

            switch = GSettingsSwitch(
                _("Disable automatic screen rotation"),
                "org.cinnamon.settings-daemon.peripherals.touchscreen",
                "orientation-lock")
            switch.set_tooltip_text(
                _("Select this option to disable automatic screen rotation on hardware equipped with supported accelerometers."
                  ))
            settings.add_row(switch)
示例#3
0
class Module:
    name = "online-accounts"
    comment = _("Connect to your online accounts")
    category = "prefs"

    def __init__(self, content_box):
        keywords = _("google, facebook, twitter, yahoo, web, online, chat, calendar, mail, contact, owncloud, kerberos, imap, smtp, pocket, readitlater, account")
        self.sidePage = SidePage(_("Online Accounts"), "cs-online-accounts", keywords, content_box, 560, module=self)

    def on_module_selected(self):
        if not self.loaded:
            print("Loading Online Account module")

            page = SettingsPage()
            self.sidePage.add_widget(page)

            image = Gtk.Image.new_from_icon_name("help-contents-symbolic", Gtk.IconSize.BUTTON)

            button = Gtk.Button(_("Information about GNOME Online Accounts"))
            button.set_image(image)
            button.set_always_show_image(True)
            button.connect("clicked", self.on_button_clicked)
            page.pack_start(button, False, True, 0)

            try:
                content = self.sidePage.content_box.c_manager.get_c_widget("online-accounts")
                content.set_no_show_all(True)
                page.pack_start(content, True, True, 0)
            except Exception as detail:
                print(detail)

            page.expand = True

    def on_button_clicked(self, button):
        gladefile = "/usr/share/cinnamon/cinnamon-settings/cinnamon-online-accounts-info.ui"
        self.builder = Gtk.Builder()
        self.builder.set_translation_domain('cinnamon')
        self.builder.add_from_file(gladefile)
        self.window = self.builder.get_object("main_window")
        self.window.set_title(_("Online Accounts"))
        self.window.set_icon_name("cs-online-accounts")
        self.window.show()
示例#4
0
class Module:
    name = "backgrounds"
    category = "appear"
    comment = _("Change your desktop's background")

    def __init__(self, content_box):
        keywords = _("background, picture, slideshow")
        self.sidePage = SidePage(_("Backgrounds"),
                                 "cs-backgrounds",
                                 keywords,
                                 content_box,
                                 module=self)

    def on_module_selected(self):
        if not self.loaded:
            print("Loading Backgrounds module")

            self.sidePage.stack = SettingsStack()
            self.sidePage.add_widget(self.sidePage.stack)

            self.shown_collection = None  # Which collection is displayed in the UI

            self._background_schema = Gio.Settings(
                schema="org.cinnamon.desktop.background")
            self._slideshow_schema = Gio.Settings(
                schema="org.cinnamon.desktop.background.slideshow")
            self._slideshow_schema.connect("changed::slideshow-enabled",
                                           self.on_slideshow_enabled_changed)
            self.add_folder_dialog = Gtk.FileChooserDialog(
                title=_("Add Folder"),
                action=Gtk.FileChooserAction.SELECT_FOLDER,
                buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                         Gtk.STOCK_OPEN, Gtk.ResponseType.OK))

            self.xdg_pictures_directory = os.path.expanduser("~/Pictures")
            xdg_config = os.path.expanduser("~/.config/user-dirs.dirs")
            if os.path.exists(xdg_config) and os.path.exists(
                    "/usr/bin/xdg-user-dir"):
                path = subprocess.check_output(["xdg-user-dir", "PICTURES"
                                                ]).decode("utf-8").rstrip("\n")
                if os.path.exists(path):
                    self.xdg_pictures_directory = path

            self.get_user_backgrounds()

            # Images

            mainbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 2)
            mainbox.expand = True
            mainbox.set_border_width(8)

            self.sidePage.stack.add_titled(mainbox, "images", _("Images"))

            left_vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
            right_vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)

            folder_scroller = Gtk.ScrolledWindow.new(None, None)
            folder_scroller.set_shadow_type(Gtk.ShadowType.IN)
            folder_scroller.set_policy(Gtk.PolicyType.AUTOMATIC,
                                       Gtk.PolicyType.AUTOMATIC)
            folder_scroller.set_property("min-content-width", 150)

            self.folder_tree = Gtk.TreeView.new()
            self.folder_tree.set_headers_visible(False)
            folder_scroller.add(self.folder_tree)

            button_toolbar = Gtk.Toolbar.new()
            button_toolbar.set_icon_size(1)
            Gtk.StyleContext.add_class(
                Gtk.Widget.get_style_context(button_toolbar), "inline-toolbar")
            self.add_folder_button = Gtk.ToolButton.new(None, None)
            self.add_folder_button.set_icon_name("list-add-symbolic")
            self.add_folder_button.set_tooltip_text(_("Add new folder"))
            self.add_folder_button.connect("clicked",
                                           lambda w: self.add_new_folder())
            self.remove_folder_button = Gtk.ToolButton.new(None, None)
            self.remove_folder_button.set_icon_name("list-remove-symbolic")
            self.remove_folder_button.set_tooltip_text(
                _("Remove selected folder"))
            self.remove_folder_button.connect("clicked",
                                              lambda w: self.remove_folder())
            button_toolbar.insert(self.add_folder_button, 0)
            button_toolbar.insert(self.remove_folder_button, 1)

            image_scroller = Gtk.ScrolledWindow.new(None, None)
            image_scroller.set_shadow_type(Gtk.ShadowType.IN)
            image_scroller.set_policy(Gtk.PolicyType.AUTOMATIC,
                                      Gtk.PolicyType.AUTOMATIC)

            self.icon_view = ThreadedIconView()
            image_scroller.add(self.icon_view)
            self.icon_view.connect("selection-changed",
                                   self.on_wallpaper_selection_changed)

            right_vbox.pack_start(image_scroller, True, True, 0)
            left_vbox.pack_start(folder_scroller, True, True, 0)
            left_vbox.pack_start(button_toolbar, False, False, 0)

            mainbox.pack_start(left_vbox, False, False, 2)
            mainbox.pack_start(right_vbox, True, True, 2)

            left_vbox.set_border_width(2)
            right_vbox.set_border_width(2)

            self.collection_store = Gtk.ListStore(
                bool,  # is separator
                str,  # Icon name
                str,  # Display name
                str,  # Path
                str)  # Type of collection
            cell = Gtk.CellRendererText()
            cell.set_alignment(0, 0)
            pb_cell = Gtk.CellRendererPixbuf()
            self.folder_column = Gtk.TreeViewColumn()
            self.folder_column.pack_start(pb_cell, False)
            self.folder_column.pack_start(cell, True)
            self.folder_column.add_attribute(pb_cell, "icon-name", 1)
            self.folder_column.add_attribute(cell, "text", 2)

            self.folder_column.set_alignment(0)

            self.folder_tree.append_column(self.folder_column)
            self.folder_tree.connect("cursor-changed",
                                     self.on_folder_source_changed)

            self.get_system_backgrounds()

            tree_separator = [True, None, None, None, None]
            self.collection_store.append(tree_separator)

            if len(self.user_backgrounds) > 0:
                for item in self.user_backgrounds:
                    self.collection_store.append(item)

            self.folder_tree.set_model(self.collection_store)
            self.folder_tree.set_row_separator_func(self.is_row_separator,
                                                    None)

            self.get_initial_path()

            # Settings

            page = SettingsPage()

            settings = page.add_section(_("Background Settings"))

            size_group = Gtk.SizeGroup.new(Gtk.SizeGroupMode.HORIZONTAL)

            self.sidePage.stack.add_titled(page, "settings", _("Settings"))

            widget = GSettingsSwitch(
                _("Play backgrounds as a slideshow"),
                "org.cinnamon.desktop.background.slideshow",
                "slideshow-enabled")
            settings.add_row(widget)

            widget = GSettingsSpinButton(
                _("Delay"), "org.cinnamon.desktop.background.slideshow",
                "delay", _("minutes"), 1, 1440)
            settings.add_reveal_row(
                widget, "org.cinnamon.desktop.background.slideshow",
                "slideshow-enabled")

            widget = GSettingsSwitch(
                _("Play images in random order"),
                "org.cinnamon.desktop.background.slideshow", "random-order")
            settings.add_reveal_row(
                widget, "org.cinnamon.desktop.background.slideshow",
                "slideshow-enabled")

            widget = GSettingsComboBox(_("Picture aspect"),
                                       "org.cinnamon.desktop.background",
                                       "picture-options",
                                       BACKGROUND_PICTURE_OPTIONS,
                                       size_group=size_group)
            settings.add_row(widget)

            widget = ColorsWidget(size_group)
            settings.add_row(widget)

    def is_row_separator(self, model, iter, data):
        return model.get_value(iter, 0)

    def on_slideshow_enabled_changed(self, settings, key):
        if self._slideshow_schema.get_boolean("slideshow-enabled"):
            self.icon_view.set_sensitive(False)
            self.icon_view.set_selection_mode(Gtk.SelectionMode.NONE)
        else:
            self.icon_view.set_sensitive(True)
            self.icon_view.set_selection_mode(Gtk.SelectionMode.SINGLE)

    def get_system_backgrounds(self):
        picture_list = []
        folder_list = []
        properties_dir = "/usr/share/cinnamon-background-properties"
        backgrounds = []
        if os.path.exists(properties_dir):
            for i in os.listdir(properties_dir):
                if i.endswith(".xml"):
                    xml_path = os.path.join(properties_dir, i)
                    display_name = i.replace(".xml", "").replace(
                        "-", " ").replace("_",
                                          " ").split(" ")[-1].capitalize()
                    icon = "preferences-desktop-wallpaper-symbolic"
                    order = 10
                    # Special case for Linux Mint. We don't want to use 'start-here' here as it wouldn't work depending on the theme.
                    # Also, other distros should get equal treatment. If they define cinnamon-backgrounds and use their own distro name, we should add support for it.
                    if display_name == "Retro":
                        icon = "document-open-recent-symbolic"
                        order = 20  # place retro bgs at the end
                    if display_name == "Linuxmint":
                        display_name = "Linux Mint"
                        icon = "linuxmint-logo-badge-symbolic"
                        order = 0
                    backgrounds.append([[
                        False, icon, display_name, xml_path,
                        BACKGROUND_COLLECTION_TYPE_XML
                    ], display_name, order])

        backgrounds.sort(key=lambda x: (x[2], x[1]))
        for background in backgrounds:
            self.collection_store.append(background[0])

    def get_user_backgrounds(self):
        self.user_backgrounds = []
        path = os.path.expanduser("~/.cinnamon/backgrounds/user-folders.lst")
        if os.path.exists(path):
            with open(path) as f:
                folders = f.readlines()
            for line in folders:
                folder_path = line.strip("\n")
                folder_name = folder_path.split("/")[-1]
                if folder_path == self.xdg_pictures_directory:
                    icon = "folder-pictures-symbolic"
                else:
                    icon = "folder-symbolic"
                self.user_backgrounds.append([
                    False, icon, folder_name, folder_path,
                    BACKGROUND_COLLECTION_TYPE_DIRECTORY
                ])
        else:
            # Add XDG PICTURE DIR
            self.user_backgrounds.append([
                False, "folder-pictures-symbolic",
                self.xdg_pictures_directory.split("/")[-1],
                self.xdg_pictures_directory,
                BACKGROUND_COLLECTION_TYPE_DIRECTORY
            ])
            self.update_folder_list()

    def format_source(self, type, path):
        # returns 'type://path'
        return ("%s://%s" % (type, path))

    def get_initial_path(self):
        try:
            image_source = self._slideshow_schema.get_string("image-source")
            tree_iter = self.collection_store.get_iter_first()
            collection = self.collection_store[tree_iter]
            collection_type = collection[STORE_TYPE]
            collection_path = collection[STORE_PATH]
            collection_source = self.format_source(collection_type,
                                                   collection_path)
            self.remove_folder_button.set_sensitive(True)

            if image_source != "" and "://" in image_source:
                while tree_iter != None:
                    if collection_source == image_source:
                        tree_path = self.collection_store.get_path(tree_iter)
                        self.folder_tree.set_cursor(tree_path)
                        if collection_type == BACKGROUND_COLLECTION_TYPE_XML:
                            self.remove_folder_button.set_sensitive(False)
                        self.update_icon_view(collection_path, collection_type)
                        return
                    tree_iter = self.collection_store.iter_next(tree_iter)
                    collection = self.collection_store[tree_iter]
                    collection_type = collection[STORE_TYPE]
                    collection_path = collection[STORE_PATH]
                    collection_source = self.format_source(
                        collection_type, collection_path)
            else:
                self._slideshow_schema.set_string("image-source",
                                                  collection_source)
                tree_path = self.collection_store.get_path(tree_iter)
                self.folder_tree.get_selection().select_path(tree_path)
                if collection_type == BACKGROUND_COLLECTION_TYPE_XML:
                    self.remove_folder_button.set_sensitive(False)
                self.update_icon_view(collection_path, collection_type)
        except Exception as detail:
            print(detail)

    def on_row_activated(self, tree, path, column):
        self.folder_tree.set_selection(path)

    def on_folder_source_changed(self, tree):
        self.remove_folder_button.set_sensitive(True)
        if tree.get_selection() is not None:
            folder_paths, iter = tree.get_selection().get_selected()
            if iter:
                collection_path = folder_paths[iter][STORE_PATH]
                collection_type = folder_paths[iter][STORE_TYPE]
                collection_source = self.format_source(collection_type,
                                                       collection_path)
                if os.path.exists(collection_path):
                    if collection_source != self._slideshow_schema.get_string(
                            "image-source"):
                        self._slideshow_schema.set_string(
                            "image-source", collection_source)
                    if collection_type == BACKGROUND_COLLECTION_TYPE_XML:
                        self.remove_folder_button.set_sensitive(False)
                    self.update_icon_view(collection_path, collection_type)

    def get_selected_wallpaper(self):
        selected_items = self.icon_view.get_selected_items()
        if len(selected_items) == 1:
            path = selected_items[0]
            iter = self.icon_view.get_model().get_iter(path)
            return self.icon_view.get_model().get(iter, 0)[0]
        return None

    def on_wallpaper_selection_changed(self, iconview):
        wallpaper = self.get_selected_wallpaper()
        if wallpaper:
            for key in wallpaper:
                if key == "filename":
                    self._background_schema.set_string(
                        "picture-uri", "file://" + wallpaper[key])
                elif key == "options":
                    self._background_schema.set_string("picture-options",
                                                       wallpaper[key])

    def add_new_folder(self):
        res = self.add_folder_dialog.run()
        if res == Gtk.ResponseType.OK:
            folder_path = self.add_folder_dialog.get_filename()
            folder_name = folder_path.split("/")[-1]
            # Make sure it's not already added..
            for background in self.user_backgrounds:
                if background[STORE_PATH] == folder_path:
                    self.add_folder_dialog.hide()
                    return
            if folder_path == self.xdg_pictures_directory:
                icon = "folder-pictures-symbolic"
            else:
                icon = "folder-symbolic"
            self.user_backgrounds.append([
                False, icon, folder_name, folder_path,
                BACKGROUND_COLLECTION_TYPE_DIRECTORY
            ])
            self.collection_store.append([
                False, icon, folder_name, folder_path,
                BACKGROUND_COLLECTION_TYPE_DIRECTORY
            ])
            self.update_folder_list()
        self.add_folder_dialog.hide()

    def remove_folder(self):
        if self.folder_tree.get_selection() is not None:
            self.icon_view.clear()
            folder_paths, iter = self.folder_tree.get_selection().get_selected(
            )
            if iter:
                path = folder_paths[iter][STORE_PATH]
                self.collection_store.remove(iter)
                for item in self.user_backgrounds:
                    if item[STORE_PATH] == path:
                        self.user_backgrounds.remove(item)
                        self.update_folder_list()
                        break

    def update_folder_list(self):
        path = os.path.expanduser("~/.cinnamon/backgrounds")
        if not os.path.exists(path):
            os.makedirs(path, mode=0o755, exist_ok=True)
        path = os.path.expanduser("~/.cinnamon/backgrounds/user-folders.lst")
        if len(self.user_backgrounds) == 0:
            file_data = ""
        else:
            first_path = self.user_backgrounds[0][STORE_PATH]
            file_data = first_path + "\n"
            for folder in self.user_backgrounds:
                if folder[STORE_PATH] == first_path:
                    continue
                else:
                    file_data += "%s\n" % folder[STORE_PATH]

        with open(path, "w") as f:
            f.write(file_data)

    def update_icon_view(self, path=None, type=None):
        if path != self.shown_collection:
            self.shown_collection = path
            picture_list = []
            if os.path.exists(path):
                if type == BACKGROUND_COLLECTION_TYPE_DIRECTORY:
                    files = os.listdir(path)
                    files.sort()
                    for i in files:
                        filename = os.path.join(path, i)
                        picture_list.append({"filename": filename})
                elif type == BACKGROUND_COLLECTION_TYPE_XML:
                    picture_list += self.parse_xml_backgrounds_list(path)

            self.icon_view.set_pictures_list(picture_list, path)
            if self._slideshow_schema.get_boolean("slideshow-enabled"):
                self.icon_view.set_sensitive(False)
            else:
                self.icon_view.set_sensitive(True)

    def splitLocaleCode(self, localeCode):
        try:
            loc = localeCode.partition("_")
            loc = (loc[0], loc[2])
        except:
            loc = ("en", "US")
        return loc

    def getLocalWallpaperName(self, names, loc):
        result = ""
        mainLocFound = False
        for wp in names:
            wpLoc = wp[0]
            wpName = wp[1]
            if wpLoc == ("", ""):
                if not mainLocFound:
                    result = wpName
            elif wpLoc[0] == loc[0]:
                if wpLoc[1] == loc[1]:
                    return wpName
                elif wpLoc[1] == "":
                    result = wpName
                    mainLocFound = True
        return result

    def parse_xml_backgrounds_list(self, filename):
        try:
            locAttrName = "{http://www.w3.org/XML/1998/namespace}lang"
            loc = self.splitLocaleCode(locale.getdefaultlocale()[0])
            res = []
            subLocaleFound = False
            f = open(filename)
            rootNode = ElementTree.fromstring(f.read())
            f.close()
            if rootNode.tag == "wallpapers":
                for wallpaperNode in rootNode:
                    if wallpaperNode.tag == "wallpaper" and wallpaperNode.get(
                            "deleted") != "true":
                        wallpaperData = {"metadataFile": filename}
                        names = []
                        for prop in wallpaperNode:
                            if type(prop.tag) == str:
                                if prop.tag != "name":
                                    wallpaperData[prop.tag] = prop.text
                                else:
                                    propAttr = prop.attrib
                                    wpName = prop.text
                                    locName = self.splitLocaleCode(
                                        propAttr.get(locAttrName)
                                    ) if locAttrName in propAttr else ("", "")
                                    names.append((locName, wpName))
                        wallpaperData["name"] = self.getLocalWallpaperName(
                            names, loc)

                        if "filename" in wallpaperData and wallpaperData[
                                "filename"] != "" and os.path.exists(
                                    wallpaperData["filename"]) and os.access(
                                        wallpaperData["filename"], os.R_OK):
                            if wallpaperData["name"] == "":
                                wallpaperData["name"] = os.path.basename(
                                    wallpaperData["filename"])
                            res.append(wallpaperData)
            return res
        except Exception as detail:
            print("Could not parse %s!" % filename)
            print(detail)
            return []
示例#5
0
文件: cs_sound.py 项目: t6/cinnamon
class Module:
    name = "sound"
    category = "hardware"
    comment = _("Manage sound settings")

    def __init__(self, content_box):
        keywords = _(
            "sound, media, music, speakers, audio, microphone, headphone")
        self.sidePage = SidePage(_("Sound"),
                                 "cs-sound",
                                 keywords,
                                 content_box,
                                 module=self)
        self.sound_settings = Gio.Settings(CINNAMON_DESKTOP_SOUNDS)

    def on_module_selected(self):
        if not self.loaded:
            print("Loading Sound module")

            self.outputDeviceList = Gtk.ListStore(
                str,  # name
                str,  # device
                bool,  # active
                int,  # id
                GdkPixbuf.Pixbuf)  # icon

            self.inputDeviceList = Gtk.ListStore(
                str,  # name
                str,  # device
                bool,  # active
                int,  # id
                GdkPixbuf.Pixbuf)  # icon

            self.appList = {}

            self.inializeController()
            self.buildLayout()

        self.checkAppState()
        self.checkInputState()

    def buildLayout(self):
        self.sidePage.stack = SettingsStack()
        self.sidePage.add_widget(self.sidePage.stack)

        ## Output page
        page = SettingsPage()
        self.sidePage.stack.add_titled(page, "output", _("Output"))

        self.outputSelector = self.buildDeviceSelect("output",
                                                     self.outputDeviceList)
        outputSection = page.add_section(_("Device"))
        outputSection.add_row(self.outputSelector)

        devSettings = page.add_section(_("Device settings"))

        # output profiles
        self.profile = ProfileSelector(self.controller)
        devSettings.add_row(self.profile)

        sizeGroup = Gtk.SizeGroup.new(Gtk.SizeGroupMode.HORIZONTAL)

        # ouput volume
        max_volume = self.sound_settings.get_int(MAXIMUM_VOLUME_KEY)
        self.outVolume = VolumeBar(self.controller.get_vol_max_norm(),
                                   max_volume,
                                   sizeGroup=sizeGroup)
        devSettings.add_row(self.outVolume)

        # balance
        self.balance = BalanceBar("balance", sizeGroup=sizeGroup)
        devSettings.add_row(self.balance)
        self.fade = BalanceBar("fade", sizeGroup=sizeGroup)
        devSettings.add_row(self.fade)
        self.woofer = BalanceBar("lfe",
                                 0,
                                 self.controller.get_vol_max_norm(),
                                 sizeGroup=sizeGroup)
        devSettings.add_row(self.woofer)

        ## Input page
        page = SettingsPage()
        self.sidePage.stack.add_titled(page, "input", _("Input"))

        self.inputStack = Gtk.Stack()
        page.pack_start(self.inputStack, True, True, 0)

        inputBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=15)
        self.inputSelector = self.buildDeviceSelect("input",
                                                    self.inputDeviceList)
        deviceSection = SettingsSection("Device")
        inputBox.pack_start(deviceSection, False, False, 0)
        deviceSection.add_row(self.inputSelector)

        devSettings = SettingsSection(_("Device settings"))
        inputBox.pack_start(devSettings, False, False, 0)

        sizeGroup = Gtk.SizeGroup.new(Gtk.SizeGroupMode.HORIZONTAL)

        # input volume
        self.inVolume = VolumeBar(self.controller.get_vol_max_norm(),
                                  max_volume,
                                  sizeGroup=sizeGroup)
        devSettings.add_row(self.inVolume)

        # input level
        self.inLevel = VolumeLevelBar(sizeGroup)
        devSettings.add_row(self.inLevel)
        self.inputStack.add_named(inputBox, "inputBox")

        noInputsMessage = Gtk.Box()
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
        image = Gtk.Image.new_from_icon_name("action-unavailable-symbolic",
                                             Gtk.IconSize.DIALOG)
        image.set_pixel_size(96)
        box.pack_start(image, False, False, 0)
        box.set_valign(Gtk.Align.CENTER)
        label = Gtk.Label(_("No inputs sources are currently available."))
        box.pack_start(label, False, False, 0)
        noInputsMessage.pack_start(box, True, True, 0)
        self.inputStack.add_named(noInputsMessage, "noInputsMessage")
        self.inputStack.show_all()

        ## Sounds page
        page = SettingsPage()
        self.sidePage.stack.add_titled(page, "sounds", _("Sounds"))

        soundsVolumeSection = page.add_section(_("Sounds Volume"))
        self.soundsVolume = VolumeBar(self.controller.get_vol_max_norm(), 100)
        soundsVolumeSection.add_row(self.soundsVolume)

        soundsSection = SoundBox(_("Sounds"))
        page.pack_start(soundsSection, True, True, 0)
        sizeGroup = Gtk.SizeGroup.new(Gtk.SizeGroupMode.HORIZONTAL)
        for effect in EFFECT_LIST:
            soundsSection.add_row(Effect(effect, sizeGroup))

        ## Applications page
        page = SettingsPage()
        self.sidePage.stack.add_titled(page, "applications", _("Applications"))

        self.appStack = Gtk.Stack()
        page.pack_start(self.appStack, True, True, 0)

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.appSettings = SoundBox(_("Applications"))
        box.pack_start(self.appSettings, True, True, 0)
        self.appStack.add_named(box, "appSettings")

        noAppsMessage = Gtk.Box()
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
        image = Gtk.Image.new_from_icon_name("action-unavailable-symbolic",
                                             Gtk.IconSize.DIALOG)
        image.set_pixel_size(96)
        box.pack_start(image, False, False, 0)
        box.set_valign(Gtk.Align.CENTER)
        label = Gtk.Label(
            _("No application is currently playing or recording audio."))
        box.pack_start(label, False, False, 0)
        noAppsMessage.pack_start(box, True, True, 0)
        self.appStack.add_named(noAppsMessage, "noAppsMessage")

        ## Settings page
        page = SettingsPage()
        self.sidePage.stack.add_titled(page, "settings", _("Settings"))

        amplificationSection = page.add_section(_("Amplification"))
        self.maxVolume = Slider(_("Maximum volume: %d") % max_volume + "%",
                                _("Reduced"),
                                _("Amplified"),
                                1,
                                150,
                                None,
                                step=1,
                                page=10,
                                value=max_volume,
                                gicon=None,
                                iconName=None)
        self.maxVolume.adjustment.connect("value-changed",
                                          self.onMaxVolumeChanged)
        self.maxVolume.setMark(100)
        amplificationSection.add_row(self.maxVolume)

    def onMaxVolumeChanged(self, adjustment):
        newValue = int(round(adjustment.get_value()))
        self.sound_settings.set_int(MAXIMUM_VOLUME_KEY, newValue)
        self.maxVolume.label.set_label(
            _("Maximum volume: %d") % newValue + "%")
        self.outVolume.adjustment.set_upper(newValue)
        self.outVolume.slider.clear_marks()
        if (newValue > 100):
            self.outVolume.setMark(100)

    def inializeController(self):
        self.controller = Cvc.MixerControl(name="cinnamon")
        self.controller.connect("state-changed", self.setChannelMap)
        self.controller.connect("output-added", self.deviceAdded, "output")
        self.controller.connect("input-added", self.deviceAdded, "input")
        self.controller.connect("output-removed", self.deviceRemoved, "output")
        self.controller.connect("input-removed", self.deviceRemoved, "input")
        self.controller.connect("active-output-update",
                                self.activeOutputUpdate)
        self.controller.connect("active-input-update", self.activeInputUpdate)
        self.controller.connect("default-sink-changed",
                                self.defaultSinkChanged)
        self.controller.connect("default-source-changed",
                                self.defaultSourceChanged)
        self.controller.connect("stream-added", self.streamAdded)
        self.controller.connect("stream-removed", self.streamRemoved)
        self.controller.open()

    def buildDeviceSelect(self, type, model):
        select = Gtk.IconView.new_with_model(model)
        select.set_margin(0)
        select.set_pixbuf_column(4)
        select.set_text_column(0)
        select.set_column_spacing(0)

        select.connect("selection-changed", self.setActiveDevice, type)

        return select

    def setActiveDevice(self, view, type):
        selected = view.get_selected_items()
        if len(selected) == 0:
            return

        model = view.get_model()
        newDeviceId = model.get_value(model.get_iter(selected[0]), 3)
        newDevice = getattr(self.controller,
                            "lookup_" + type + "_id")(newDeviceId)
        if newDevice != None and newDeviceId != getattr(self, type + "Id"):
            getattr(self.controller, "change_" + type)(newDevice)
            self.profile.setDevice(newDevice)

    def deviceAdded(self, c, id, type):
        device = getattr(self.controller, "lookup_" + type + "_id")(id)

        iconTheme = Gtk.IconTheme.get_default()
        gicon = device.get_gicon()
        iconName = device.get_icon_name()
        icon = None
        if gicon is not None:
            lookup = iconTheme.lookup_by_gicon(gicon, 32, 0)
            if lookup is not None:
                icon = lookup.load_icon()

        if icon is None:
            if (iconName is not None and "bluetooth" in iconName):
                icon = iconTheme.load_icon("bluetooth", 32, 0)
            else:
                icon = iconTheme.load_icon("audio-card", 32, 0)

        getattr(self, type + "DeviceList").append([
            device.get_description() + "\n" + device.get_origin(), "", False,
            id, icon
        ])

        if type == "input":
            self.checkInputState()

    def deviceRemoved(self, c, id, type):
        store = getattr(self, type + "DeviceList")
        for row in store:
            if row[3] == id:
                store.remove(row.iter)
                if type == "input":
                    self.checkInputState()
                return

    def checkInputState(self):
        if len(self.inputDeviceList) == 0:
            self.inputStack.set_visible_child_name("noInputsMessage")
        else:
            self.inputStack.set_visible_child_name("inputBox")

    def activeOutputUpdate(self, c, id):
        self.outputId = id
        device = self.controller.lookup_output_id(id)

        self.profile.setDevice(device)

        # select current device in device selector
        i = 0
        for row in self.outputDeviceList:
            if row[3] == id:
                self.outputSelector.select_path(
                    Gtk.TreePath.new_from_string(str(i)))
            i = i + 1

        self.setChannelMap()

    def activeInputUpdate(self, c, id):
        self.inputId = id

        # select current device in device selector
        i = 0
        for row in self.inputDeviceList:
            if row[3] == id:
                self.inputSelector.select_path(
                    Gtk.TreePath.new_from_string(str(i)))
            i = i + 1

    def defaultSinkChanged(self, c, id):
        defaultSink = self.controller.get_default_sink()
        if defaultSink == None:
            return
        self.outVolume.setStream(defaultSink)
        self.setChannelMap()

    def defaultSourceChanged(self, c, id):
        defaultSource = self.controller.get_default_source()
        if defaultSource == None:
            return
        self.inVolume.setStream(defaultSource)
        self.inLevel.setStream(defaultSource)

    def setChannelMap(self, a=None, b=None):
        if self.controller.get_state() == Cvc.MixerControlState.READY:
            channelMap = self.controller.get_default_sink().get_channel_map()
            self.balance.setChannelMap(channelMap)
            self.fade.setChannelMap(channelMap)
            self.woofer.setChannelMap(channelMap)

    def streamAdded(self, c, id):
        stream = self.controller.lookup_stream_id(id)

        if stream in self.controller.get_sink_inputs():
            name = stream.props.name

            # FIXME: We use to filter out by PA_PROP_APPLICATION_ID.  But
            # most streams report this as null now... why??
            if name in ("speech-dispatcher", "libcanberra"):
                # speech-dispatcher: orca/speechd/spd-say
                # libcanberra: cinnamon effects, test sounds
                return

            if id in self.appList.keys():
                # Don't add an input more than once
                return

            if name == None:
                name = _("Unknown")

            label = "%s: " % name

            self.appList[id] = VolumeBar(self.controller.get_vol_max_norm(),
                                         100, label, stream.get_gicon())
            self.appList[id].setStream(stream)
            self.appSettings.add_row(self.appList[id])
            self.appSettings.list_box.invalidate_headers()
            self.appSettings.show_all()
        elif stream == self.controller.get_event_sink_input():
            self.soundsVolume.setStream(stream)

        self.checkAppState()

    def streamRemoved(self, c, id):
        if id in self.appList:
            self.appList[id].get_parent().destroy()
            self.appSettings.list_box.invalidate_headers()
            del self.appList[id]
            self.checkAppState()

    def checkAppState(self):
        if len(self.appList) == 0:
            self.appStack.set_visible_child_name("noAppsMessage")
        else:
            self.appStack.set_visible_child_name("appSettings")
示例#6
0
class Module:
    name = "panel"
    category = "prefs"
    comment = _("Manage Cinnamon panel settings")

    def __init__(self, content_box):
        keywords = _("panel, height, bottom, top, autohide, size, layout")
        self.sidePage = SidePage(_("Panel"),
                                 "cs-panel",
                                 keywords,
                                 content_box,
                                 module=self)

    def on_module_selected(self):
        if not self.loaded:
            print("Loading Panel module")

            self.settings = Gio.Settings.new("org.cinnamon")

            try:
                if len(sys.argv) > 2 and sys.argv[1] == "panel":
                    self.panel_id = sys.argv[2]
                else:
                    self.panel_id = self.settings.get_strv(
                        "panels-enabled")[0].split(":")[0]
            except:
                self.panel_id = ""

            self.panels = []

            self.previous_button = Gtk.Button(_("Previous panel"))
            self.next_button = Gtk.Button(_("Next panel"))

            controller = SettingsWidget()
            controller.fill_row()
            controller.pack_start(self.previous_button, False, False, 0)
            controller.pack_end(self.next_button, False, False, 0)
            self.previous_button.connect("clicked", self.on_previous_panel)
            self.next_button.connect("clicked", self.on_next_panel)

            self.revealer = SettingsRevealer()

            page = SettingsPage()
            page.add(controller)
            page.set_margin_bottom(0)
            self.revealer.add(page)
            self.sidePage.add_widget(self.revealer)

            self.config_stack = Gtk.Stack()
            self.config_stack.set_transition_duration(150)
            self.revealer.add(self.config_stack)

            page = SettingsPage()
            self.sidePage.add_widget(page)
            section = page.add_section(_("General Panel Options"))

            buttons = SettingsWidget()
            self.add_panel_button = Gtk.Button(label=_("Add new panel"))

            buttons.pack_start(self.add_panel_button, False, False, 2)
            toggle_button = Gtk.ToggleButton(label=_("Panel edit mode"))

            self.settings.bind("panel-edit-mode", toggle_button, "active",
                               Gio.SettingsBindFlags.DEFAULT)
            buttons.pack_end(toggle_button, False, False, 2)
            section.add_row(buttons)

            section.add_row(
                GSettingsSwitch(
                    _("Allow the pointer to pass through the edges of panels"),
                    "org.cinnamon", "no-adjacent-panel-barriers"))

            self.add_panel_button.set_sensitive(False)

            self.settings.connect("changed::panels-enabled",
                                  self.on_panel_list_changed)

            self.proxy = None

            try:
                Gio.DBusProxy.new_for_bus(Gio.BusType.SESSION,
                                          Gio.DBusProxyFlags.NONE, None,
                                          "org.Cinnamon", "/org/Cinnamon",
                                          "org.Cinnamon", None,
                                          self._on_proxy_ready, None)
            except GLib.Error as e:
                print(e.message)
                self.proxy = None

        self.on_panel_list_changed()

    def _on_proxy_ready(self, object, result, data=None):
        self.proxy = Gio.DBusProxy.new_for_bus_finish(result)

        if not self.proxy.get_name_owner():
            self.proxy = None

        if self.proxy:
            self.revealer.connect("unmap", self.restore_panels)
            self.revealer.connect("destroy", self.restore_panels)

            self.add_panel_button.connect("clicked", self.on_add_panel)

            if self.panel_id is not None:
                self.proxy.highlightPanel('(ib)', int(self.panel_id), True)

    def on_add_panel(self, widget):
        if self.proxy:
            self.proxy.addPanelQuery()

    def on_previous_panel(self, widget):
        if self.panel_id and self.proxy:
            self.proxy.highlightPanel('(ib)', int(self.panel_id), False)

        current = self.panels.index(self.current_panel)

        if current - 1 >= 0:
            self.current_panel = self.panels[current - 1]
            self.panel_id = self.current_panel.panel_id
        else:
            self.current_panel = self.panels[len(self.panels) - 1]
            self.panel_id = self.current_panel.panel_id

        self.config_stack.set_transition_type(
            Gtk.StackTransitionType.SLIDE_RIGHT)

        if self.proxy:
            self.proxy.highlightPanel('(ib)', int(self.panel_id), True)

        self.config_stack.set_visible_child(self.current_panel)

    def on_next_panel(self, widget):
        if self.panel_id and self.proxy:
            self.proxy.highlightPanel('(ib)', int(self.panel_id), False)

        current = self.panels.index(self.current_panel)

        if current + 1 < len(self.panels):
            self.current_panel = self.panels[current + 1]
            self.panel_id = self.current_panel.panel_id
        else:
            self.current_panel = self.panels[0]
            self.panel_id = self.current_panel.panel_id

        self.config_stack.set_transition_type(
            Gtk.StackTransitionType.SLIDE_LEFT)

        if self.proxy:
            self.proxy.highlightPanel('(ib)', int(self.panel_id), True)

        self.config_stack.set_visible_child(self.current_panel)

    def on_panel_list_changed(self, *args):
        if len(self.panels) > 0:
            for panel in self.panels:
                panel.destroy()

        self.panels = []
        monitor_layout = []

        panels = self.settings.get_strv("panels-enabled")
        n_mons = Gdk.Screen.get_default().get_n_monitors()

        for i in range(n_mons):
            monitor_layout.append(Monitor())

        current_found = False
        for panel in panels:
            panel_id, monitor_id, position = panel.split(":")
            monitor_id = int(monitor_id)
            panel_page = PanelSettingsPage(panel_id, self.settings, position)
            self.config_stack.add_named(panel_page, panel_id)

            # we may already have a current panel id from the command line or if
            # if the panels-enabled key changed since everything was loaded
            if panel_id == self.panel_id:
                current_found = True
                self.current_panel = panel_page
                self.config_stack.set_visible_child(panel_page)

            # we don't currently show panels on monitors that aren't attached
            # if we decide to change this behavior, we should probably give some visual indication
            # that the panel is on a detached monitor
            if monitor_id < n_mons:
                if "top" in position:
                    monitor_layout[monitor_id].top = panel_page
                elif "bottom" in position:
                    monitor_layout[monitor_id].bottom = panel_page
                elif "left" in position:
                    monitor_layout[monitor_id].left = panel_page
                else:
                    monitor_layout[monitor_id].right = panel_page

        # Index the panels for the next/previous buttons
        for monitor in monitor_layout:
            for panel_page in (monitor.top, monitor.bottom, monitor.left,
                               monitor.right):
                if panel_page != -1:
                    self.panels.append(panel_page)

        # if there are no panels, there's no point in showing the stack
        if len(self.panels) == 0:
            self.next_button.hide()
            self.previous_button.hide()
            self.config_stack.hide()
            self.add_panel_button.set_sensitive(True)
            self.current_panel = None
            self.panel_id = None
            return

        self.config_stack.show()
        self.next_button.show()
        self.previous_button.show()

        # Disable the panel switch buttons if there's only one panel
        if len(self.panels) == 1:
            self.next_button.set_sensitive(False)
            self.previous_button.set_sensitive(False)
        else:
            self.next_button.set_sensitive(True)
            self.previous_button.set_sensitive(True)

        if not current_found:
            self.current_panel = self.panels[0]
            self.panel_id = self.current_panel.panel_id
            self.config_stack.set_visible_child(self.current_panel)

        self.revealer.set_reveal_child(len(self.panels) != 0)

        # If all panel positions are full, we want to disable the add button
        can_add = False
        for monitor in monitor_layout:
            if -1 in (monitor.top, monitor.bottom, monitor.left,
                      monitor.right):
                can_add = True
                break

        self.add_panel_button.set_sensitive(can_add)

        try:
            current_idx = self.panels.index(self.panel_id)
        except:
            current_idx = 0

        if self.proxy:
            self.proxy.highlightPanel('(ib)', int(self.panel_id), True)

    def restore_panels(self, widget):
        self.proxy.destroyDummyPanels()
        if self.panel_id:
            self.proxy.highlightPanel('(ib)', int(self.panel_id), False)
示例#7
0
class Module:
    name = "calendar"
    comment = _("Manage date and time settings")
    category = "prefs"

    def __init__(self, content_box):
        keywords = _("time, date, calendar, format, network, sync")
        self.sidePage = SidePage(_("Date & Time"),
                                 "cs-date-time",
                                 keywords,
                                 content_box,
                                 560,
                                 module=self)

    def on_module_selected(self):
        if not self.loaded:
            print("Loading Calendar module")

            page = SettingsPage()
            self.sidePage.add_widget(page)

            settings = page.add_section(_("Date and Time"))
            widget = SettingsWidget()
            self.tz_map = TimezoneMap.TimezoneMap.new()
            self.tz_map.set_size_request(-1, 205)
            widget.pack_start(self.tz_map, True, True, 0)
            settings.add_row(widget)

            self.tz_selector = TimeZoneSelector()
            settings.add_row(self.tz_selector)

            self.ntp_switch = Switch(_("Network time"))
            settings.add_row(self.ntp_switch)

            self.set_time_row = SettingsWidget()
            self.revealer = SettingsRevealer()
            settings.add_reveal_row(self.set_time_row, revealer=self.revealer)
            self.set_time_row.pack_start(
                Gtk.Label(_("Manually set date and time")), False, False, 0)
            self.date_chooser = DateChooserButton(True)
            self.time_chooser = TimeChooserButton(True)
            self.set_time_row.pack_end(self.time_chooser, False, False, 0)
            self.set_time_row.pack_end(self.date_chooser, False, False, 0)
            self.date_chooser.connect('date-changed', self.set_date_and_time)
            self.time_chooser.connect('time-changed', self.set_date_and_time)

            settings = page.add_section(_("Format"))
            settings.add_row(
                GSettingsSwitch(_("Use 24h clock"),
                                "org.cinnamon.desktop.interface",
                                "clock-use-24h"))
            settings.add_row(
                GSettingsSwitch(_("Display the date"),
                                "org.cinnamon.desktop.interface",
                                "clock-show-date"))
            settings.add_row(
                GSettingsSwitch(_("Display seconds"),
                                "org.cinnamon.desktop.interface",
                                "clock-show-seconds"))
            days = [[7, _("Use locale default")], [0, _("Sunday")],
                    [1, _("Monday")]]
            settings.add_row(
                GSettingsComboBox(_("First day of week"),
                                  "org.cinnamon.desktop.interface",
                                  "first-day-of-week",
                                  days,
                                  valtype=int))

            if os.path.exists('/usr/sbin/ntpd'):
                print('using csd backend')
                self.proxy_handler = CsdDBusProxyHandler(self._on_proxy_ready)
            else:
                print('using systemd backend')
                self.proxy_handler = SytemdDBusProxyHandler(
                    self._on_proxy_ready)

            self.sync_24h_to_gnome()

    def _on_proxy_ready(self):
        self.zone = self.proxy_handler.get_timezone()
        if self.zone is None:
            self.tz_map.set_sensitive(False)
            self.tz_selector.set_sensitive(False)
        else:
            self.tz_map.set_timezone(self.zone)
            self.tz_map.connect('location-changed',
                                self.on_map_location_changed)
            self.tz_selector.set_timezone(self.zone)
            self.tz_selector.connect('timezone-changed',
                                     self.on_selector_location_changed)
        can_use_ntp, is_using_ntp = self.proxy_handler.get_ntp()
        self.ntp_switch.set_sensitive(can_use_ntp)
        self.ntp_switch.content_widget.set_active(is_using_ntp)
        self.ntp_switch.content_widget.connect('notify::active',
                                               self.on_ntp_changed)
        self.revealer.set_reveal_child(not is_using_ntp)

    def sync_24h_to_gnome(self):
        # Firefox (and maybe other apps?) check gnome's 24h setting only. It'd be
        # messy to change it in firefox since our setting is a boolean and their's
        # is a string, so just update the gnome preference when the user changes ours.
        self.our_settings = Gio.Settings(
            schema_id="org.cinnamon.desktop.interface")
        self.gnome_settings = Gio.Settings(
            schema_id="org.gnome.desktop.interface")

        self.our_settings.connect("changed::clock-use-24h",
                                  self.update_gnome_24h)
        self.update_gnome_24h()

    def update_gnome_24h(self, settings=None, pspec=None):
        if self.our_settings.get_boolean("clock-use-24h"):
            self.gnome_settings.set_string("clock-format", "24h")
        else:
            self.gnome_settings.set_string("clock-format", "12h")

    def on_map_location_changed(self, *args):
        zone = self.tz_map.get_location().props.zone
        if zone == self.zone:
            return

        self.tz_selector.set_timezone(zone)
        self.set_timezone(zone)

    def on_selector_location_changed(self, *args):
        zone = self.tz_selector.get_timezone()
        if zone == self.zone:
            return

        self.set_timezone(zone)
        self.tz_map.set_timezone(zone)

    def set_timezone(self, zone):
        self.zone = zone
        self.proxy_handler.set_timezone(zone)

    def on_ntp_changed(self, *args):
        active = self.ntp_switch.content_widget.get_active()
        self.revealer.set_reveal_child(not active)
        self.proxy_handler.set_ntp(active)

    def set_date_and_time(self, *args):
        unaware = datetime.datetime.combine(self.date_chooser.get_date(),
                                            self.time_chooser.get_time())
        tz = pytz.timezone(self.zone)
        self.datetime = tz.localize(unaware)

        seconds = int((self.datetime - datetime.datetime(
            1970, 1, 1, tzinfo=datetime.timezone.utc)).total_seconds())
        self.proxy_handler.set_time(seconds)
示例#8
0
class Module:
    name = "power"
    category = "hardware"
    comment = _("Manage power settings")

    def __init__(self, content_box):
        keywords = _(
            "power, suspend, hibernate, laptop, desktop, brightness, screensaver"
        )
        self.sidePage = SidePage(_("Power Management"),
                                 "cs-power",
                                 keywords,
                                 content_box,
                                 -1,
                                 module=self)

    def on_module_selected(self):
        if self.loaded:
            # self.loaded = False
            return
        print("Loading Power module")

        self.up_client = UPowerGlib.Client.new()

        self.csd_power_proxy = Gio.DBusProxy.new_sync(
            Gio.bus_get_sync(Gio.BusType.SESSION, None),
            Gio.DBusProxyFlags.NONE, None, "org.cinnamon.SettingsDaemon.Power",
            "/org/cinnamon/SettingsDaemon/Power",
            "org.cinnamon.SettingsDaemon.Power", None)

        self.settings = Gio.Settings.new("org.cinnamon")

        device_types = [x[UP_TYPE] for x in self.csd_power_proxy.GetDevices()]

        self.has_battery = UPowerGlib.DeviceKind.BATTERY in device_types or UPowerGlib.DeviceKind.UPS in device_types
        self.has_lid = self.up_client.get_lid_is_present()

        self.sidePage.stack = SettingsStack()

        # Power

        power_page = SettingsPage()

        section = power_page.add_section(_("Power Options"))

        lid_options, button_power_options, critical_options, can_suspend, can_hybrid_sleep = get_available_options(
            self.up_client)

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)

        if self.has_battery:
            header = SettingsWidget()
            label_ac = Gtk.Label()
            label_ac.set_markup("<b>%s</b>" % _("On A/C power"))
            size_group.add_widget(label_ac)
            label_battery = Gtk.Label()
            label_battery.set_markup("<b>%s</b>" % _("On battery power"))
            size_group.add_widget(label_battery)
            header.pack_end(label_battery, False, False, 0)
            header.pack_end(label_ac, False, False, 0)

            section.add_row(header)

            section.add_row(
                GSettings2ComboBox(_("Turn off the screen when inactive for"),
                                   CSD_SCHEMA,
                                   "sleep-display-ac",
                                   "sleep-display-battery",
                                   SLEEP_DELAY_OPTIONS,
                                   valtype="int",
                                   size_group=size_group))

            section.add_row(
                GSettings2ComboBox(_("Suspend when inactive for"),
                                   CSD_SCHEMA,
                                   "sleep-inactive-ac-timeout",
                                   "sleep-inactive-battery-timeout",
                                   SLEEP_DELAY_OPTIONS,
                                   valtype="int",
                                   size_group=size_group))

            if self.has_lid:
                section.add_row(
                    GSettings2ComboBox(_("When the lid is closed"),
                                       CSD_SCHEMA,
                                       "lid-close-ac-action",
                                       "lid-close-battery-action",
                                       lid_options,
                                       size_group=size_group))

        else:
            section.add_row(
                GSettingsComboBox(_("Turn off the screen when inactive for"),
                                  CSD_SCHEMA,
                                  "sleep-display-ac",
                                  SLEEP_DELAY_OPTIONS,
                                  valtype=int,
                                  size_group=size_group))

            section.add_row(
                GSettingsComboBox(_("Suspend when inactive for"),
                                  CSD_SCHEMA,
                                  "sleep-inactive-ac-timeout",
                                  SLEEP_DELAY_OPTIONS,
                                  valtype=int,
                                  size_group=size_group))

            if self.has_lid:
                section.add_row(
                    GSettingsComboBox(_("When the lid is closed"),
                                      CSD_SCHEMA,
                                      "lid-close-ac-action",
                                      lid_options,
                                      size_group=size_group))

        section = power_page.add_section(_("Extra options"))

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)

        section.add_row(
            GSettingsComboBox(_("When the power button is pressed"),
                              CSD_SCHEMA,
                              "button-power",
                              button_power_options,
                              size_group=size_group))

        if self.has_lid:
            section.add_row(
                GSettingsSwitch(
                    _("Perform lid-closed action even with external monitors attached"
                      ), CSD_SCHEMA,
                    "lid-close-suspend-with-external-monitor"))

        if self.has_battery and UPowerGlib.MAJOR_VERSION == 0 and UPowerGlib.MINOR_VERSION <= 99:
            section.add_row(
                GSettingsComboBox(_("When the battery is critically low"),
                                  CSD_SCHEMA,
                                  "critical-battery-action",
                                  critical_options,
                                  size_group=size_group))

        if can_suspend and can_hybrid_sleep:
            switch = GSettingsSwitch(_("Enable Hybrid Sleep"), CSM_SCHEMA,
                                     "prefer-hybrid-sleep")
            switch.set_tooltip_text(_("Replaces Suspend with Hybrid Sleep"))
            section.add_row(switch)

        # Batteries

        self.battery_page = SettingsPage()
        self.show_battery_page = False
        self.battery_label_size_group = Gtk.SizeGroup(
            Gtk.SizeGroupMode.HORIZONTAL)

        self.build_battery_page()
        self.csd_power_proxy.connect("g-properties-changed",
                                     self.build_battery_page)

        proxy = Gio.DBusProxy.new_sync(
            Gio.bus_get_sync(Gio.BusType.SESSION, None),
            Gio.DBusProxyFlags.NONE, None, "org.cinnamon.SettingsDaemon.Power",
            "/org/cinnamon/SettingsDaemon/Power",
            "org.cinnamon.SettingsDaemon.Power.Screen", None)

        try:
            brightness = proxy.GetPercentage()
        except GLib.Error as e:
            print("Power module brightness page not available: %s" % e.message)

            if self.show_battery_page:
                self.sidePage.add_widget(self.sidePage.stack)
                self.sidePage.stack.add_titled(power_page, "power", _("Power"))
                self.sidePage.stack.add_titled(self.battery_page, "batteries",
                                               _("Batteries"))
            else:
                self.sidePage.add_widget(power_page)
        else:
            self.sidePage.add_widget(self.sidePage.stack)
            self.sidePage.stack.add_titled(power_page, "power", _("Power"))
            if self.show_battery_page:
                self.sidePage.stack.add_titled(self.battery_page, "batteries",
                                               _("Batteries"))

            page = SettingsPage()
            self.sidePage.stack.add_titled(page, "brightness", _("Brightness"))

            size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)

            section = page.add_section(_("Screen brightness"))
            section.add_row(
                BrightnessSlider(section, proxy, _("Screen brightness")))

            section.add_row(
                GSettingsSwitch(_("On battery, dim screen when inactive"),
                                CSD_SCHEMA, "idle-dim-battery"))

            section.add_reveal_row(
                GSettingsComboBox(_("Brightness level when inactive"),
                                  CSD_SCHEMA,
                                  "idle-brightness",
                                  IDLE_BRIGHTNESS_OPTIONS,
                                  valtype=int,
                                  size_group=size_group), CSD_SCHEMA,
                "idle-dim-battery")

            section.add_reveal_row(
                GSettingsComboBox(_("Dim screen after inactive for"),
                                  CSD_SCHEMA,
                                  "idle-dim-time",
                                  IDLE_DELAY_OPTIONS,
                                  valtype=int,
                                  size_group=size_group), CSD_SCHEMA,
                "idle-dim-battery")

            proxy = Gio.DBusProxy.new_sync(
                Gio.bus_get_sync(Gio.BusType.SESSION,
                                 None), Gio.DBusProxyFlags.NONE, None,
                "org.cinnamon.SettingsDaemon.Power",
                "/org/cinnamon/SettingsDaemon/Power",
                "org.cinnamon.SettingsDaemon.Power.Keyboard", None)

            try:
                brightness = proxy.GetPercentage()
            except GLib.Error as e:
                print("Power module no keyboard backlight: %s" % e.message)
            else:
                section = page.add_section(_("Keyboard backlight"))
                section.add_row(
                    BrightnessSlider(section, proxy,
                                     _("Backlight brightness")))

    def build_battery_page(self, *args):

        self.aliases = {}
        device_aliases = self.settings.get_strv("device-aliases")
        for alias in device_aliases:
            try:
                (device_id, device_nickname) = alias.split(":=")
                self.aliases[device_id] = device_nickname
            except:
                pass  # ignore malformed aliases

        #destroy all widgets in this page
        for widget in self.battery_page.get_children():
            widget.destroy()

        secondary_settings = None
        primary_settings = None

        # UPowerGlib segfaults when trying to get device. Use CSD instead
        devices = self.csd_power_proxy.GetDevices()

        have_primary = False
        ups_as_primary = False

        # first we look for a discharging UPS, which is promoted to the
        # primary device if it's discharging. Otherwise we use the first
        # listed laptop battery as the primary device

        for device in devices:
            if device[UP_TYPE] == UPowerGlib.DeviceKind.UPS and device[
                    UP_STATE] == UPowerGlib.DeviceState.DISCHARGING:
                ups_as_primary = True

        for device in devices:
            if device[UP_TYPE] == UPowerGlib.DeviceKind.LINE_POWER:
                pass  # Do nothing
            elif device[
                    UP_TYPE] == UPowerGlib.DeviceKind.UPS and ups_as_primary:
                if not primary_settings:
                    primary_settings = self.battery_page.add_section(
                        _("Batteries"))
                    primary_settings.add_row(
                        self.set_device_ups_primary(device))
                    self.show_battery_page = True
                else:
                    primary_settings.add_row(
                        self.set_device_ups_primary(device))
            elif device[
                    UP_TYPE] == UPowerGlib.DeviceKind.BATTERY and not ups_as_primary:
                if not have_primary:
                    if not primary_settings:
                        primary_settings = self.battery_page.add_section(
                            _("Batteries"))
                        primary_settings.add_row(
                            self.set_device_battery_primary(device))
                        self.show_battery_page = True
                    have_primary = True
                else:
                    widget = self.set_device_battery_additional(device)
                    if widget:
                        primary_settings.add_row(widget)
            else:
                if not secondary_settings:
                    secondary_settings = self.battery_page.add_section(
                        _("Devices"))
                    secondary_settings.add_row(
                        self.add_battery_device_secondary(device))
                    self.show_battery_page = True
                else:
                    secondary_settings.add_row(
                        self.add_battery_device_secondary(device))

        #show all the widgets in this page, but not the page itself
        visible = self.battery_page.get_visible()
        self.battery_page.show_all()
        self.battery_page.set_visible(visible)

    def set_device_ups_primary(self, device):
        device_id = device[UP_ID]
        percentage = device[UP_PERCENTAGE]
        battery_level = device[UP_BATTERY_LEVEL]
        state = device[UP_STATE]
        time = device[UP_SECONDS]
        vendor = device[UP_VENDOR]
        model = device[UP_MODEL]
        details = None

        if time > 0:
            time_string = get_timestring(time)

            if state == UPowerGlib.DeviceState.DISCHARGING:
                if percentage < 20:
                    details = _("Caution low UPS, %s remaining") % time_string
                else:
                    details = _("Using UPS power - %s remaining") % time_string
            else:
                details = UPowerGlib.Device.state_to_string(state)
        else:
            if state == UPowerGlib.DeviceState.DISCHARGING:
                if percentage < 20:
                    details = _("Caution low UPS")
                else:
                    details = _("Using UPS power")
            else:
                details = UPowerGlib.Device.state_to_string(state)

        desc = _("UPS")
        if (model != "" or vendor != ""):
            desc = "%s %s" % (vendor, model)

        widget = self.create_battery_row(device_id, "battery", desc,
                                         percentage, battery_level, details)
        return widget

    def set_device_battery_primary(self, device):
        device_id = device[UP_ID]
        percentage = device[UP_PERCENTAGE]
        battery_level = device[UP_BATTERY_LEVEL]
        state = device[UP_STATE]
        time = device[UP_SECONDS]
        vendor = device[UP_VENDOR]
        model = device[UP_MODEL]
        details = None

        if time > 0:
            time_string = get_timestring(time)

            if state == UPowerGlib.DeviceState.CHARGING or state == UPowerGlib.DeviceState.PENDING_CHARGE:
                details = _("Charging - %s until fully charged") % time_string
            elif state == UPowerGlib.DeviceState.DISCHARGING or state == UPowerGlib.DeviceState.PENDING_DISCHARGE:
                if percentage < 20:
                    details = _(
                        "Caution low battery, %s remaining") % time_string
                else:
                    details = _(
                        "Using battery power - %s remaining") % time_string
            else:
                details = UPowerGlib.Device.state_to_string(state)
        else:
            if state == UPowerGlib.DeviceState.CHARGING or state == UPowerGlib.DeviceState.PENDING_CHARGE:
                details = _("Charging")
            elif state == UPowerGlib.DeviceState.DISCHARGING or state == UPowerGlib.DeviceState.PENDING_DISCHARGE:
                details = _("Using battery power")
            elif state == UPowerGlib.DeviceState.FULLY_CHARGED:
                details = _("Charging - fully charged")
            elif state == UPowerGlib.DeviceState.EMPTY:
                details = _("Empty")
            else:
                details = UPowerGlib.Device.state_to_string(state)

        desc = _("Battery")
        if (model != "" or vendor != ""):
            desc = "%s %s" % (vendor, model)

        widget = self.create_battery_row(device_id, "battery", desc,
                                         percentage, battery_level, details)
        return widget

    def set_device_battery_additional(self, device):
        state = device[UP_STATE]
        details = None

        if state == UPowerGlib.DeviceState.FULLY_CHARGED:
            details = _("Fully charged")
        elif state == UPowerGlib.DeviceState.EMPTY:
            details = _("Empty")

        if details:
            widget = SettingsWidget()
            icon = Gtk.Image.new_from_icon_name("battery", Gtk.IconSize.DND)
            widget.pack_start(icon, False, False, 0)
            label = Gtk.Label(_("Secondary battery"))
            widget.pack_start(label, False, False, 0)
            label = Gtk.Label()
            label.set_markup(details)
            label.get_style_context().add_class("dim-label")
            widget.pack_end(label, False, False, 0)

            return widget
        else:
            return None

    def add_battery_device_secondary(self, device):
        device_id = device[UP_ID]
        kind = device[UP_TYPE]
        percentage = device[UP_PERCENTAGE]
        battery_level = device[UP_BATTERY_LEVEL]
        vendor = device[UP_VENDOR]
        model = device[UP_MODEL]

        if kind == UPowerGlib.DeviceKind.UPS:
            icon_name = "uninterruptible-power-supply"
            desc = _("Uninterruptible power supply")
        elif kind == UPowerGlib.DeviceKind.MOUSE:
            icon_name = "input-mouse"
            desc = _("Wireless mouse")
        elif kind == UPowerGlib.DeviceKind.KEYBOARD:
            icon_name = "input-keyboard"
            desc = _("Wireless Keyboard")
        elif kind == UPowerGlib.DeviceKind.TABLET:
            icon_name = "input-tablet"
            desc = _("Tablet")
        elif kind == UPowerGlib.DeviceKind.PDA:
            icon_name = "pda"
            desc = _("Personal digital assistant")
        elif kind == UPowerGlib.DeviceKind.PHONE:
            icon_name = "phone"
            desc = _("Cellphone")
        elif kind == UPowerGlib.DeviceKind.MEDIA_PLAYER:
            icon_name = "multimedia-player"
            desc = _("Media player")
        elif kind == UPowerGlib.DeviceKind.COMPUTER:
            icon_name = "computer"
            desc = _("Computer")
        else:
            icon_name = "battery"
            desc = (_("Battery"))

        if (model != "" or vendor != ""):
            desc = "%s %s" % (vendor, model)

        widget = self.create_battery_row(device_id, icon_name, desc,
                                         percentage, battery_level)
        return widget

    def create_battery_row(self,
                           device_id,
                           icon_name,
                           desc,
                           percentage,
                           battery_level,
                           details=None):

        if device_id in self.aliases:
            desc = self.aliases[device_id]

        widget = SettingsWidget()

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        label_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=15)

        image = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.DND)
        entry = Gtk.Entry()
        entry.set_text(desc)
        entry.connect('focus-out-event', self.on_alias_changed, device_id)
        label_box.pack_start(image, False, False, 0)
        label_box.pack_start(entry, False, False, 0)
        self.battery_label_size_group.add_widget(label_box)
        hbox.pack_start(label_box, False, False, 0)

        if battery_level == UPowerGlib.DeviceLevel.NONE:
            label = Gtk.Label()
            label.set_markup("%d%%" % int(percentage))
            label.set_size_request(30, -1)
            hbox.pack_start(label, False, False, 15)

            level_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
            level_bar = Gtk.LevelBar()
            level_bar.set_mode(Gtk.LevelBarMode.DISCRETE)
            level_bar.set_min_value(0)
            level_bar.set_max_value(10)
            level_bar.add_offset_value("high", 5)
            level_bar.add_offset_value("low", 2)
            level_box.set_valign(Gtk.Align.CENTER)
            level_bar.set_value(round(percentage / 10))
            level_box.pack_start(level_bar, True, True, 0)
            hbox.pack_start(level_box, True, True, 0)
        else:
            status_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
            status_icon = Gtk.Image.new_from_icon_name(
                self.bat_level_to_icon(battery_level), Gtk.IconSize.BUTTON)
            status_icon.set_size_request(30, -1)

            status_box.pack_start(status_icon, False, False, 15)

            status_label = Gtk.Label(self.bat_level_to_label(battery_level))
            status_box.pack_end(status_label, False, False, 0)
            hbox.pack_start(status_box, True, True, 0)

        vbox.pack_start(hbox, False, False, 0)

        if details:
            label = Gtk.Label()
            label.set_markup(details)
            label.get_style_context().add_class("dim-label")
            label.set_halign(Gtk.Align.END)
            vbox.pack_end(label, False, False, 0)

        widget.pack_start(vbox, True, True, 0)

        return widget

    def bat_level_to_icon(self, level):
        if level in (UPowerGlib.DeviceLevel.FULL, UPowerGlib.DeviceLevel.HIGH):
            return "battery-full-symbolic"
        elif level == UPowerGlib.DeviceLevel.NORMAL:
            return "battery-good-symbolic"
        elif level == UPowerGlib.DeviceLevel.LOW:
            return "battery-low-symbolic"
        elif level == UPowerGlib.DeviceLevel.CRITICAL:
            return "battery-caution-symbolic"

    def bat_level_to_label(self, level):
        if level == UPowerGlib.DeviceLevel.FULL:
            return _("Battery full")
        elif level == UPowerGlib.DeviceLevel.HIGH:
            return _("Battery almost full")
        elif level == UPowerGlib.DeviceLevel.NORMAL:
            return _("Battery good")
        elif level == UPowerGlib.DeviceLevel.LOW:
            return _("Low battery")
        elif level == UPowerGlib.DeviceLevel.CRITICAL:
            return _("Critically low battery")

    def on_alias_changed(self, entry, event, device_id):
        self.aliases[device_id] = entry.get_text()
        aliases = []
        for alias in self.aliases:
            aliases.append("%s:=%s" % (alias, self.aliases[alias]))
        self.settings.set_strv("device-aliases", aliases)
示例#9
0
class Module:
    name = "display"
    comment = _("Manage display settings")
    category = "hardware"

    def __init__(self, content_box):
        keywords = _("display, screen, monitor, layout, resolution, dual, lcd")
        self.sidePage = SidePage(_("Display"),
                                 "cs-display",
                                 keywords,
                                 content_box,
                                 650,
                                 module=self)
        self.display_c_widget = None

    def on_module_selected(self):
        if not self.loaded:
            print("Loading Display module")

            self.sidePage.stack = SettingsStack()
            self.sidePage.add_widget(self.sidePage.stack)

            page = SettingsPage()
            self.sidePage.stack.add_titled(page, "layout", _("Layout"))

            try:
                settings = page.add_section(_("Layout"))

                widget = SettingsWidget()
                widget.set_border_width(0)
                widget.set_margin_start(0)
                widget.set_margin_end(0)

                content = self.sidePage.content_box.c_manager.get_c_widget(
                    "display")
                widget.pack_start(content, True, True, 0)

                self.display_c_widget = content
                settings.add_row(widget)
                widget.get_parent().set_activatable(False)

            except Exception as detail:
                print(detail)

            page = SettingsPage()
            self.sidePage.stack.add_titled(page, "settings", _("Settings"))
            settings = page.add_section(_("Settings"))

            switch = GSettingsSwitch(
                _("Disable automatic screen rotation"),
                "org.cinnamon.settings-daemon.peripherals.touchscreen",
                "orientation-lock")
            switch.set_tooltip_text(
                _("Select this option to disable automatic screen rotation on hardware equipped with supported accelerometers."
                  ))
            settings.add_row(switch)

            switch = Switch(
                _("Enable fractional scaling controls (experimental)"))
            switch.set_tooltip_text(
                _("Select this option to display additional layout controls for per-monitor scaling."
                  ))
            settings.add_row(switch)
            self.fractional_switch = switch.content_widget

            self.muffin_settings = Gio.Settings(
                schema_id="org.cinnamon.muffin")
            self.experimental_features_changed(self.muffin_settings,
                                               "x11-randr-fractional-scaling")
            self.muffin_settings.connect("changed::experimental-features",
                                         self.experimental_features_changed)
            self.fractional_switch.connect("notify::active",
                                           self.fractional_switch_toggled)

    def experimental_features_changed(self, settings, key):
        self.fractional_switch.freeze_notify()

        features = self.muffin_settings.get_strv("experimental-features")
        self.fractional_switch.set_active(
            "x11-randr-fractional-scaling" in features)

        self.fractional_switch.thaw_notify()

    def fractional_switch_toggled(self, switch, pspec):
        active = switch.get_active()

        features = self.muffin_settings.get_strv("experimental-features")

        if active:
            if "x11-randr-fractional-scaling" in features:
                return
            else:
                features.append("x11-randr-fractional-scaling")
        else:
            try:
                features.remove("x11-randr-fractional-scaling")
            except ValueError:
                pass

        self.muffin_settings.set_strv("experimental-features", features)

    def on_navigate_out_of_module(self):
        if self.display_c_widget:
            self.display_c_widget.hide()