示例#1
0
    def __init__(self, text=None, tooltip=None):
        super(LabelRow, self).__init__()

        self.label = SettingsLabel()
        self.label.set_hexpand(True)
        self.pack_start(self.label, False, False, 0)
        self.label.set_markup(text)
        self.set_tooltip_text(tooltip)
示例#2
0
    def __init__(self,
                 label,
                 event_sounds=True,
                 size_group=None,
                 dep_key=None,
                 tooltip=""):
        super(SoundFileChooser, self).__init__(dep_key=dep_key)

        self.event_sounds = event_sounds

        self.label = SettingsLabel(label)
        self.content_widget = Gtk.Box()

        c = self.content_widget.get_style_context()
        c.add_class(Gtk.STYLE_CLASS_LINKED)

        self.file_picker_button = Gtk.Button()
        self.file_picker_button.connect("clicked", self.on_picker_clicked)

        button_content = Gtk.Box(spacing=5)
        self.file_picker_button.add(button_content)

        self.button_label = Gtk.Label()
        button_content.pack_start(Gtk.Image(icon_name="sound"), False, False,
                                  0)
        button_content.pack_start(self.button_label, False, False, 0)

        self.content_widget.pack_start(self.file_picker_button, True, True, 0)

        self.pack_start(self.label, False, False, 0)
        self.pack_end(self.content_widget, False, False, 0)

        self.play_button = Gtk.Button()
        self.play_button.set_image(
            Gtk.Image.new_from_icon_name("media-playback-start-symbolic",
                                         Gtk.IconSize.BUTTON))
        self.play_button.connect("clicked", self.on_play_clicked)
        self.content_widget.pack_start(self.play_button, False, False, 0)

        self._proxy = None

        try:
            Gio.DBusProxy.new_for_bus(Gio.BusType.SESSION,
                                      Gio.DBusProxyFlags.NONE, None,
                                      'org.cinnamon.SettingsDaemon.Sound',
                                      '/org/cinnamon/SettingsDaemon/Sound',
                                      'org.cinnamon.SettingsDaemon.Sound',
                                      None, self._on_proxy_ready, None)
        except dbus.exceptions.DBusException as e:
            print(e)
            self._proxy = None
            self.play_button.set_sensitive(False)

        self.set_tooltip_text(tooltip)

        if size_group:
            self.add_to_size_group(size_group)
示例#3
0
    def __init__(self, label, num_bind=2, size_group=None, dep_key=None, tooltip=""):
        super(Keybinding, self).__init__(dep_key=dep_key)

        self.num_bind = num_bind

        self.label = SettingsLabel(label)

        self.buttons = []
        self.teach_button = None

        self.content_widget = Gtk.Frame(shadow_type=Gtk.ShadowType.IN)
        self.content_widget.set_valign(Gtk.Align.CENTER)
        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        self.content_widget.add(box)

        self.pack_start(self.label, False, False, 0)
        self.pack_end(self.content_widget, False, False, 0)

        for x in range(self.num_bind):
            if x != 0:
                box.add(Gtk.Separator(orientation=Gtk.Orientation.VERTICAL))
            kb = ButtonKeybinding()
            kb.set_size_request(150, -1)
            kb.connect("accel-edited", self.on_kb_changed)
            kb.connect("accel-cleared", self.on_kb_changed)
            box.pack_start(kb, False, False, 0)
            self.buttons.append(kb)

        self.event_id = None
        self.teaching = False

        self.set_tooltip_text(tooltip)

        if size_group:
            self.add_to_size_group(size_group)
示例#4
0
    def __init__(self,
                 label,
                 event_sounds=True,
                 size_group=None,
                 dep_key=None,
                 tooltip=""):
        super(SoundFileChooser, self).__init__(dep_key=dep_key)

        self.event_sounds = event_sounds

        self.label = SettingsLabel(label)
        self.content_widget = Gtk.Box()

        c = self.content_widget.get_style_context()
        c.add_class(Gtk.STYLE_CLASS_LINKED)

        self.file_picker_button = Gtk.Button()
        self.file_picker_button.connect("clicked", self.on_picker_clicked)

        button_content = Gtk.Box(spacing=5)
        self.file_picker_button.add(button_content)

        self.button_label = Gtk.Label()
        button_content.pack_start(Gtk.Image(icon_name="sound"), False, False,
                                  0)
        button_content.pack_start(self.button_label, False, False, 0)

        self.content_widget.pack_start(self.file_picker_button, True, True, 0)

        self.pack_start(self.label, False, False, 0)
        self.pack_end(self.content_widget, False, False, 0)

        self.play_button = Gtk.Button()
        self.play_button.set_image(
            Gtk.Image.new_from_icon_name("media-playback-start-symbolic",
                                         Gtk.IconSize.BUTTON))
        self.play_button.connect("clicked", self.on_play_clicked)
        self.content_widget.pack_start(self.play_button, False, False, 0)

        self.set_tooltip_text(tooltip)

        if size_group:
            self.add_to_size_group(size_group)
示例#5
0
    def __init__(self, label, size_group=None, dep_key=None, tooltip=""):
        super(TimeChooser, self).__init__(dep_key=dep_key)

        self.label = SettingsLabel(label)

        self.content_widget = TimeChooserButton()

        self.pack_start(self.label, False, False, 0)
        self.pack_end(self.content_widget, False, False, 0)

        self.set_tooltip_text(tooltip)

        if size_group:
            self.add_to_size_group(size_group)
示例#6
0
    def __init__(self, uuid, data, spices, size_groups):
        super().__init__()

        self.uuid = uuid
        self.data = data
        self.spices = spices
        self.name = data['name']
        self.description = data['description']
        self.score = data['score']
        self.timestamp = data['last_edited']

        self.has_update = False

        self.status_ids = {}

        self.installed = self.spices.get_is_installed(uuid)

        widget = SettingsWidget()
        widget.set_spacing(15)
        self.add(widget)

        icon = spices.get_icon(uuid)
        widget.pack_start(icon, False, False, 0)

        desc_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        desc_box.set_hexpand(True)
        desc_box.set_halign(Gtk.Align.FILL)
        name_label = Gtk.Label()
        name_markup = GLib.markup_escape_text(self.name)
        name_label.set_markup('<b>{}</b>'.format(name_markup))
        name_label.set_hexpand(True)
        name_label.set_halign(Gtk.Align.START)
        desc_box.pack_start(name_label, False, False, 0)

        description_label = SettingsLabel()
        description_markup = GLib.markup_escape_text(
            sanitize_html(self.description))
        description_label.set_markup(
            '<small>{}</small>'.format(description_markup))
        desc_box.pack_start(description_label, False, False, 0)

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

        score_box = Gtk.Box()
        score_image = Gtk.Image.new_from_icon_name('starred-symbolic', 2)
        score_box.pack_start(score_image, False, False, 0)
        score_label = Gtk.Label(self.score)
        score_box.pack_start(score_label, False, False, 5)
        widget.pack_start(score_box, False, False, 0)
        size_groups[0].add_widget(score_box)

        self.status_box = Gtk.Box()
        self.status_box.set_spacing(4)
        widget.pack_start(self.status_box, False, False, 0)
        size_groups[1].add_widget(self.status_box)

        self.button_box = Gtk.Box()
        self.button_box.set_valign(Gtk.Align.CENTER)
        self.button_box.set_baseline_position(Gtk.BaselinePosition.CENTER)
        widget.pack_start(self.button_box, False, False, 0)
        size_groups[2].add_widget(self.button_box)

        if not self.installed:
            download_button = Gtk.Button.new_from_icon_name(
                'go-down-symbolic', 2)
            self.button_box.pack_start(download_button, False, False, 0)
            download_button.connect('clicked', self.download)
            download_button.set_tooltip_text(_("Install"))
        elif self.spices.get_has_update(uuid):
            self.has_update = True
            download_button = Gtk.Button.new_from_icon_name(
                'view-refresh-symbolic', 2)
            self.button_box.pack_start(download_button, False, False, 0)
            download_button.connect('clicked', self.download)
            download_button.set_tooltip_text(_("Update"))

        if self.installed:
            self.add_status('installed', 'object-select-symbolic',
                            _("Installed"))
示例#7
0
    def __init__(self, extension_type, metadata, size_group):
        super(ManageSpicesRow, self).__init__()
        self.extension_type = extension_type
        self.metadata = metadata

        self.status_ids = {}

        self.writable = metadata['writable']

        self.uuid = self.metadata['uuid']
        self.name = translate(self.metadata['uuid'], self.metadata['name'])
        self.description = translate(self.metadata['uuid'],
                                     self.metadata['description'])

        try:
            self.max_instances = int(self.metadata['max-instances'])
            if self.max_instances < -1:
                self.max_instances = 1
        except (KeyError, ValueError):
            self.max_instances = 1

        try:
            self.role = self.metadata['role']
        except (KeyError, ValueError):
            self.role = None

        try:
            last_edited = self.metadata['last-edited']
        except (KeyError, ValueError):
            last_edited = -1

        if 'multiversion' in self.metadata and self.metadata['multiversion']:
            self.metadata['path'] = find_extension_subdir(
                self.metadata['path'])

        # "hide-configuration": true in metadata trumps all
        # otherwise we check for "external-configuration-app" in metadata and settings-schema.json in settings
        self.has_config = False
        self.ext_config_app = None
        if not 'hide-configuration' in self.metadata or self.metadata[
                'hide-configuration'] != True:
            if 'external-configuration-app' in self.metadata:
                self.ext_config_app = os.path.join(
                    self.metadata['path'],
                    self.metadata['external-configuration-app'])

            if self.ext_config_app is not None:
                if os.path.exists(self.ext_config_app):
                    self.has_config = True
                else:
                    self.ext_config_app = None

            if self.ext_config_app is None and os.path.exists(
                    '%s/settings-schema.json' % self.metadata['path']):
                self.has_config = True

        widget = SettingsWidget()
        self.add(widget)

        grid = Gtk.Grid()
        grid.set_column_spacing(15)
        widget.pack_start(grid, True, True, 0)

        icon = None
        if 'icon' in self.metadata:
            icon_name = self.metadata['icon']
            if Gtk.IconTheme.get_default().has_icon(icon_name):
                icon = Gtk.Image.new_from_icon_name(icon_name, 3)

        if icon is None and os.path.exists(
                '%s/icon.png' % self.metadata['path']):
            try:
                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
                    '%s/icon.png' % self.metadata['path'], 24, 24, True)
                icon = Gtk.Image.new_from_pixbuf(pixbuf)
            except:
                icon = None

        if icon is None:
            icon = Gtk.Image.new_from_icon_name('cs-%ss' % (extension_type), 3)

        grid.attach(icon, 0, 0, 1, 1)

        desc_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        desc_box.props.hexpand = True
        desc_box.props.halign = Gtk.Align.START
        name_label = Gtk.Label()
        name_markup = GLib.markup_escape_text(self.name)
        name_label.set_markup('<b>{}</b>'.format(name_markup))
        name_label.props.xalign = 0.0
        desc_box.add(name_label)

        description_label = SettingsLabel()
        description_markup = GLib.markup_escape_text(
            sanitize_html(self.description))
        description_label.set_markup(
            '<small>{}</small>'.format(description_markup))
        desc_box.add(description_label)

        grid.attach_next_to(desc_box, icon, Gtk.PositionType.RIGHT, 1, 1)

        self.status_box = Gtk.Box()
        self.status_box.set_spacing(4)
        grid.attach_next_to(self.status_box, desc_box, Gtk.PositionType.RIGHT,
                            1, 1)

        self.button_box = Gtk.Box()
        self.button_box.set_valign(Gtk.Align.CENTER)
        grid.attach_next_to(self.button_box, self.status_box,
                            Gtk.PositionType.RIGHT, 1, 1)
        size_group.add_widget(self.button_box)

        if self.has_config:
            config_icon = Gtk.Image.new_from_icon_name('system-run-symbolic',
                                                       2)
            self.config_button = Gtk.Button(image=config_icon)
            self.config_button.set_tooltip_text(_('Configure'))
            self.button_box.pack_start(self.config_button, False, False, 0)
            self.config_button.connect('clicked', self.configure)
            self.set_can_config()

        if not self.writable:
            if self.extension_type == "applet":
                self.add_status(
                    'locked', 'changes-prevent-symbolic',
                    _("This is a system applet. It cannot be removed."))
            elif self.extension_type == "desklet":
                self.add_status(
                    'locked', 'changes-prevent-symbolic',
                    _("This is a system desklet. It cannot be removed."))
            elif self.extension_type == "extension":
                self.add_status(
                    'locked', 'changes-prevent-symbolic',
                    _("This is a system extension. It cannot be removed."))

        try:
            schema_filename = self.metadata['schema-file']
        except (KeyError, ValueError):
            schema_filename = ''

        if self.writable:
            self.scan_extension_for_danger(self.metadata['path'])

        self.version_supported = False
        try:
            self.version_supported = curr_ver in self.metadata[
                'cinnamon-version'] or curr_ver.rsplit(
                    '.', 1)[0] in self.metadata['cinnamon-version']
        except (KeyError, ValueError):
            self.version_supported = True  # Don't check version if not specified.
示例#8
0
class SoundFileChooser(SettingsWidget):
    bind_dir = None

    def __init__(self,
                 label,
                 event_sounds=True,
                 size_group=None,
                 dep_key=None,
                 tooltip=""):
        super(SoundFileChooser, self).__init__(dep_key=dep_key)

        self.event_sounds = event_sounds

        self.label = SettingsLabel(label)
        self.content_widget = Gtk.Box()

        c = self.content_widget.get_style_context()
        c.add_class(Gtk.STYLE_CLASS_LINKED)

        self.file_picker_button = Gtk.Button()
        self.file_picker_button.connect("clicked", self.on_picker_clicked)

        button_content = Gtk.Box(spacing=5)
        self.file_picker_button.add(button_content)

        self.button_label = Gtk.Label()
        button_content.pack_start(Gtk.Image(icon_name="sound"), False, False,
                                  0)
        button_content.pack_start(self.button_label, False, False, 0)

        self.content_widget.pack_start(self.file_picker_button, True, True, 0)

        self.pack_start(self.label, False, False, 0)
        self.pack_end(self.content_widget, False, False, 0)

        self.play_button = Gtk.Button()
        self.play_button.set_image(
            Gtk.Image.new_from_icon_name("media-playback-start-symbolic",
                                         Gtk.IconSize.BUTTON))
        self.play_button.connect("clicked", self.on_play_clicked)
        self.content_widget.pack_start(self.play_button, False, False, 0)

        self.set_tooltip_text(tooltip)

        if size_group:
            self.add_to_size_group(size_group)

    def on_play_clicked(self, widget):
        util.play_sound_file(self.get_value())

    def on_picker_clicked(self, widget):
        dialog = Gtk.FileChooserDialog(title=self.label.get_text(),
                                       action=Gtk.FileChooserAction.OPEN,
                                       transient_for=self.get_toplevel(),
                                       buttons=(_("_Cancel"),
                                                Gtk.ResponseType.CANCEL,
                                                _("_Open"),
                                                Gtk.ResponseType.ACCEPT))

        if os.path.exists(self.get_value()):
            dialog.set_filename(self.get_value())
        else:
            dialog.set_current_folder('/usr/share/sounds')

        sound_filter = Gtk.FileFilter()
        if self.event_sounds:
            sound_filter.add_mime_type("audio/x-wav")
            sound_filter.add_mime_type("audio/x-vorbis+ogg")
        else:
            sound_filter.add_mime_type("audio/*")
        sound_filter.set_name(_("Sound files"))
        dialog.add_filter(sound_filter)

        if (dialog.run() == Gtk.ResponseType.ACCEPT):
            name = dialog.get_filename()
            self.set_value(name)
            self.update_button_label(name)

        dialog.destroy()

    def update_button_label(self, absolute_path):
        if absolute_path != "":
            f = Gio.File.new_for_path(absolute_path)
            self.button_label.set_label(f.get_basename())

    def on_setting_changed(self, *args):
        self.update_button_label(self.get_value())

    def connect_widget_handlers(self, *args):
        pass
示例#9
0
    def __init__(self, uuid, data, spices, size_groups):
        super().__init__()

        self.uuid = uuid
        self.data = data
        self.spices = spices
        self.name = data['name']
        self.description = data['description']
        self.score = data['score']
        self.timestamp = data['last_edited']

        self.author = ""
        if 'author_user' in data:
            if data['author_user'].lower(
            ) != "none" and data['author_user'].lower() != "unknown":
                self.author = data['author_user']

        if 'translations' in data.keys():
            key = 'name_%s' % LANGUAGE_CODE
            if key in data['translations'].keys():
                self.name = data['translations'][key]
            key = 'description_%s' % LANGUAGE_CODE
            if key in data['translations'].keys():
                self.description = data['translations'][key]

        self.has_update = False

        self.status_ids = {}

        self.installed = self.spices.get_is_installed(uuid)

        widget = SettingsWidget()
        widget.set_spacing(15)
        self.add(widget)

        installed_box = Gtk.Box()
        installed_box.set_spacing(4)
        widget.pack_start(installed_box, False, False, 0)
        size_groups[0].add_widget(installed_box)
        installed_image = Gtk.Image.new_from_icon_name(
            'object-select-symbolic', 2)
        installed_box.pack_end(installed_image, False, False, 0)
        installed_image.set_tooltip_text(_("Installed"))
        installed_image.set_no_show_all(True)
        if self.installed:
            installed_image.show()
        else:
            installed_image.hide()

        icon = spices.get_icon(uuid)
        widget.pack_start(icon, False, False, 0)

        desc_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        desc_box.set_hexpand(True)
        desc_box.set_halign(Gtk.Align.FILL)
        desc_box.set_spacing(1)

        name_label = Gtk.Label()
        name_markup = GLib.markup_escape_text(self.name)
        if self.author == "":
            name_label.set_markup('<b>{}</b>'.format(name_markup))
        else:
            by_author = _("by %s") % self.author
            name_label.set_markup('<b>{}</b><small> {}</small>'.format(
                name_markup, by_author))
        name_label.set_hexpand(True)
        name_label.set_halign(Gtk.Align.START)
        desc_box.pack_start(name_label, False, False, 0)

        uuid_label = Gtk.Label()
        uuid_markup = GLib.markup_escape_text(self.uuid)
        uuid_label.set_markup('<small><i>{}</i></small>'.format(uuid_markup))
        uuid_label.props.xalign = 0.0
        desc_box.add(uuid_label)

        description_label = SettingsLabel()
        description_markup = GLib.markup_escape_text(
            sanitize_html(self.description))
        description_label.set_markup(
            '<small>{}</small>'.format(description_markup))
        description_label.set_margin_top(2)
        desc_box.pack_start(description_label, False, False, 0)

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

        score_box = Gtk.Box()
        score_image = Gtk.Image.new_from_icon_name('starred-symbolic', 2)
        score_box.pack_start(score_image, False, False, 0)
        score_label = Gtk.Label(self.score)
        score_box.pack_start(score_label, False, False, 5)
        widget.pack_start(score_box, False, False, 0)
        size_groups[1].add_widget(score_box)

        self.status_box = Gtk.Box()
        self.status_box.set_spacing(4)
        widget.pack_start(self.status_box, False, False, 0)
        size_groups[2].add_widget(self.status_box)

        self.button_box = Gtk.Box()
        self.button_box.set_valign(Gtk.Align.CENTER)
        self.button_box.set_baseline_position(Gtk.BaselinePosition.CENTER)
        widget.pack_start(self.button_box, False, False, 0)
        size_groups[3].add_widget(self.button_box)

        if not self.installed:
            download_button = Gtk.Button.new_from_icon_name(
                'go-down-symbolic', 2)
            self.button_box.pack_start(download_button, False, False, 0)
            download_button.connect('clicked', self.download)
            download_button.set_tooltip_text(_("Install"))
        elif self.spices.get_has_update(uuid):
            self.has_update = True
            download_button = Gtk.Button.new_from_icon_name(
                'view-refresh-symbolic', 2)
            self.button_box.pack_start(download_button, False, False, 0)
            download_button.connect('clicked', self.download)
            download_button.set_tooltip_text(_("Update"))
示例#10
0
    def __init__(self, extension_type, metadata, size_groups):
        super(ManageSpicesRow, self).__init__()
        self.extension_type = extension_type
        self.metadata = metadata

        self.status_ids = {}

        self.writable = metadata['writable']

        self.uuid = self.metadata['uuid']
        self.name = translate(self.metadata['uuid'], self.metadata['name'])
        self.description = translate(self.metadata['uuid'],
                                     self.metadata['description'])

        self.author = ""
        if 'author' in metadata:
            if metadata['author'].lower(
            ) != "none" and metadata['author'].lower() != "unknown":
                self.author = metadata['author']

        icon_path = os.path.join(self.metadata['path'], 'icon.png')

        try:
            self.max_instances = int(self.metadata['max-instances'])
            if self.max_instances < -1:
                self.max_instances = 1
        except (KeyError, ValueError):
            self.max_instances = 1

        try:
            self.role = self.metadata['role']
        except (KeyError, ValueError):
            self.role = None

        try:
            last_edited = self.metadata['last-edited']
        except (KeyError, ValueError):
            last_edited = -1

        # Check for the right version subdir (if the spice is multi-versioned, it won't necessarily be in its root directory)
        self.metadata['path'] = find_extension_subdir(self.metadata['path'])

        # "hide-configuration": true in metadata trumps all
        # otherwise we check for "external-configuration-app" in metadata and settings-schema.json in settings
        self.has_config = False
        self.ext_config_app = None
        if not 'hide-configuration' in self.metadata or self.metadata[
                'hide-configuration'] != True:
            if 'external-configuration-app' in self.metadata:
                self.ext_config_app = os.path.join(
                    self.metadata['path'],
                    self.metadata['external-configuration-app'])

            if self.ext_config_app is not None:
                if os.path.exists(self.ext_config_app):
                    self.has_config = True
                else:
                    self.ext_config_app = None

            if self.ext_config_app is None and os.path.exists(
                    '%s/settings-schema.json' % self.metadata['path']):
                self.has_config = True

        widget = SettingsWidget()
        self.add(widget)

        grid = Gtk.Grid()
        grid.set_column_spacing(15)
        widget.pack_start(grid, True, True, 0)

        enabled_box = Gtk.Box()
        enabled_box.set_spacing(4)
        size_groups[0].add_widget(enabled_box)
        self.enabled_image = Gtk.Image.new_from_icon_name(
            'object-select-symbolic', 2)
        if self.extension_type == "applet":
            self.enabled_image.set_tooltip_text(
                _("This applet is currently enabled"))
        elif self.extension_type == "desklet":
            self.enabled_image.set_tooltip_text(
                _("This desklet is currently enabled"))
        elif self.extension_type == "extension":
            self.enabled_image.set_tooltip_text(
                _("This extension is currently enabled"))
        self.enabled_image.set_no_show_all(True)
        enabled_box.pack_end(self.enabled_image, False, False, 0)
        enabled_box.show()
        grid.attach(enabled_box, 0, 0, 1, 1)

        icon = None
        if 'icon' in self.metadata:
            icon_name = self.metadata['icon']
            if Gtk.IconTheme.get_default().has_icon(icon_name):
                icon = Gtk.Image.new_from_icon_name(icon_name, 3)

        if os.path.exists(icon_path):
            try:
                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
                    icon_path, 24, 24, True)
                icon = Gtk.Image.new_from_pixbuf(pixbuf)
            except:
                icon = None

        if icon is None:
            icon = Gtk.Image.new_from_icon_name('cs-%ss' % (extension_type), 3)

        grid.attach_next_to(icon, enabled_box, Gtk.PositionType.RIGHT, 1, 1)

        desc_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        desc_box.props.hexpand = True
        desc_box.props.halign = Gtk.Align.START
        desc_box.set_spacing(1)

        name_label = Gtk.Label()
        name_markup = GLib.markup_escape_text(self.name)
        if self.author == "":
            name_label.set_markup('<b>{}</b>'.format(name_markup))
        else:
            by_author = _("by %s") % self.author
            name_label.set_markup('<b>{}</b><small> {}</small>'.format(
                name_markup, by_author))
        name_label.props.xalign = 0.0
        desc_box.add(name_label)

        uuid_label = Gtk.Label()
        uuid_markup = GLib.markup_escape_text(self.uuid)
        uuid_label.set_markup('<small><i>{}</i></small>'.format(uuid_markup))
        uuid_label.props.xalign = 0.0
        desc_box.add(uuid_label)

        description_label = SettingsLabel()
        description_markup = GLib.markup_escape_text(
            sanitize_html(self.description))
        description_label.set_markup(
            '<small>{}</small>'.format(description_markup))
        description_label.set_margin_top(2)
        desc_box.add(description_label)

        grid.attach_next_to(desc_box, icon, Gtk.PositionType.RIGHT, 1, 1)

        self.status_box = Gtk.Box()
        self.status_box.set_spacing(4)
        grid.attach_next_to(self.status_box, desc_box, Gtk.PositionType.RIGHT,
                            1, 1)
        size_groups[1].add_widget(self.status_box)

        self.button_box = Gtk.Box()
        self.button_box.set_valign(Gtk.Align.CENTER)
        grid.attach_next_to(self.button_box, self.status_box,
                            Gtk.PositionType.RIGHT, 1, 1)
        size_groups[2].add_widget(self.button_box)

        if self.has_config:
            config_icon = Gtk.Image.new_from_icon_name('system-run-symbolic',
                                                       2)
            self.config_button = Gtk.Button(image=config_icon)
            self.config_button.set_tooltip_text(_('Configure'))
            self.button_box.pack_start(self.config_button, False, False, 0)
            self.config_button.connect('clicked', self.configure)
            self.set_can_config()

        if not self.writable:
            if self.extension_type == "applet":
                self.add_status(
                    'locked', 'changes-prevent-symbolic',
                    _("This is a system applet. It cannot be removed."))
            elif self.extension_type == "desklet":
                self.add_status(
                    'locked', 'changes-prevent-symbolic',
                    _("This is a system desklet. It cannot be removed."))
            elif self.extension_type == "extension":
                self.add_status(
                    'locked', 'changes-prevent-symbolic',
                    _("This is a system extension. It cannot be removed."))

        try:
            schema_filename = self.metadata['schema-file']
        except (KeyError, ValueError):
            schema_filename = ''

        if self.writable:
            self.scan_extension_for_danger(self.metadata['path'])

        self.version_supported = self.is_compatible_with_cinnamon_version()