Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 59 additions & 12 deletions files/usr/share/cinnamon/cinnamon-settings/bin/ExtensionCore.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,12 @@ def sanitize_html(string):


class ManageSpicesRow(Gtk.ListBoxRow):
def __init__(self, extension_type, metadata, size_groups):
def __init__(self, extension_type, metadata, size_groups, use_inline_toggle=False, toggle_callback=None):
super().__init__()
self.extension_type = extension_type
self.metadata = metadata
self.use_inline_toggle = use_inline_toggle
self.toggle_callback = toggle_callback

self.status_ids = {}

Expand Down Expand Up @@ -225,16 +227,31 @@ def __init__(self, extension_type, metadata, size_groups):

enabled_box = Gtk.Box()
enabled_box.set_spacing(4)
enabled_box.set_halign(Gtk.Align.CENTER)
enabled_box.set_valign(Gtk.Align.CENTER)
size_groups[0].add_widget(enabled_box)
self.enabled_image = Gtk.Image.new_from_icon_name('xsi-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)
self.enabled_image = None
self.enabled_toggle = None
self.enabled_toggle_id = None

if self.use_inline_toggle:
self.enabled_toggle = Gtk.CheckButton()
self.enabled_toggle.set_valign(Gtk.Align.CENTER)
self.enabled_toggle.set_halign(Gtk.Align.CENTER)
self.enabled_toggle.set_size_request(32, 32)
self.enabled_toggle.set_tooltip_text(_("Enable or disable this extension"))
self.enabled_toggle_id = self.enabled_toggle.connect('toggled', self.on_enabled_toggled)
enabled_box.pack_end(self.enabled_toggle, False, False, 0)
else:
self.enabled_image = Gtk.Image.new_from_icon_name('xsi-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)

Expand Down Expand Up @@ -375,10 +392,20 @@ def remove_status(self, status_id):
self.status_ids[status_id].destroy()
del self.status_ids[status_id]

def on_enabled_toggled(self, button):
if self.toggle_callback is None:
return

self.toggle_callback(self, button.get_active())

def set_enabled(self, enabled):
self.enabled = enabled

if self.enabled:
if self.enabled_toggle is not None:
self.enabled_toggle.handler_block(self.enabled_toggle_id)
self.enabled_toggle.set_active(self.enabled > 0)
self.enabled_toggle.handler_unblock(self.enabled_toggle_id)
elif self.enabled:
self.enabled_image.show()
else:
self.enabled_image.hide()
Expand Down Expand Up @@ -425,6 +452,8 @@ def on_scan_complete(self, is_dangerous):


class ManageSpicesPage(SettingsPage):
use_inline_toggle = False

def __init__(self, parent, collection_type, spices, window):
super().__init__()
self.expand = True
Expand Down Expand Up @@ -589,6 +618,18 @@ def add_instance(self, *args):
extension_row = self.list_box.get_selected_row()
self.enable_extension(extension_row.uuid, extension_row.name, extension_row.version_supported)

def on_row_toggle_enabled(self, extension_row, enabled):
self.list_box.select_row(extension_row)

if enabled:
if extension_row.enabled == 0:
self.enable_extension(extension_row.uuid, extension_row.name, extension_row.version_supported)
elif extension_row.enabled:
self.spices.disable_extension(extension_row.uuid)

extension_row.set_enabled(self.spices.get_enabled(extension_row.uuid))
self.update_button_states()

def enable_extension(self, uuid, name, version_check=True):
if not version_check:
show_message(_("Extension %s is not compatible with your version of Cinnamon.") % uuid, self.window)
Expand Down Expand Up @@ -654,7 +695,13 @@ def load_extensions(self, *args):

for uuid, metadata in self.spices.get_installed().items():
try:
extension_row = ManageSpicesRow(self.collection_type, metadata, size_groups)
extension_row = ManageSpicesRow(
self.collection_type,
metadata,
size_groups,
use_inline_toggle=self.use_inline_toggle,
toggle_callback=self.on_row_toggle_enabled,
)
self.list_box.add(extension_row)
self.extension_rows.append(extension_row)
extension_row.set_enabled(self.spices.get_enabled(uuid))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ class ManageExtensionsPage(ManageSpicesPage):
remove_button_text = _("Disable")
uninstall_button_text = _("Uninstall")
restore_button_text = _("Disable all")
use_inline_toggle = True

def __init__(self, parent, spices, window):
super(ManageExtensionsPage, self).__init__(parent, self.collection_type, spices, window)
self.instance_button.set_no_show_all(True)
self.remove_button.set_no_show_all(True)
self.instance_button.hide()
self.remove_button.hide()
123 changes: 123 additions & 0 deletions tools/test-extensions-checkbox-overlay.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env bash

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"

BACKUP_ROOT="${HOME}/.cache/cinnamon-settings-overlay"
STATE_FILE="${BACKUP_ROOT}/current-backup"

SRC_EXTENSION_CORE="${REPO_ROOT}/files/usr/share/cinnamon/cinnamon-settings/bin/ExtensionCore.py"
SRC_CS_EXTENSIONS="${REPO_ROOT}/files/usr/share/cinnamon/cinnamon-settings/modules/cs_extensions.py"

DST_EXTENSION_CORE="/usr/share/cinnamon/cinnamon-settings/bin/ExtensionCore.py"
DST_CS_EXTENSIONS="/usr/share/cinnamon/cinnamon-settings/modules/cs_extensions.py"

usage() {
cat <<'EOF'
Usage:
./tools/test-extensions-checkbox-overlay.sh install
./tools/test-extensions-checkbox-overlay.sh restore
./tools/test-extensions-checkbox-overlay.sh status

Commands:
install Back up the installed Cinnamon settings files and overlay this repo's versions.
restore Restore the last backup created by install.
status Show the active backup location, if any.
EOF
}

require_sources() {
[[ -f "${SRC_EXTENSION_CORE}" ]] || { echo "Missing source file: ${SRC_EXTENSION_CORE}" >&2; exit 1; }
[[ -f "${SRC_CS_EXTENSIONS}" ]] || { echo "Missing source file: ${SRC_CS_EXTENSIONS}" >&2; exit 1; }
}

require_installed_targets() {
[[ -f "${DST_EXTENSION_CORE}" ]] || { echo "Missing installed file: ${DST_EXTENSION_CORE}" >&2; exit 1; }
[[ -f "${DST_CS_EXTENSIONS}" ]] || { echo "Missing installed file: ${DST_CS_EXTENSIONS}" >&2; exit 1; }
}

install_overlay() {
require_sources
require_installed_targets

mkdir -p "${BACKUP_ROOT}"

local backup_dir
backup_dir="${BACKUP_ROOT}/$(date +%Y%m%d-%H%M%S)"
mkdir -p "${backup_dir}/bin" "${backup_dir}/modules"

echo "Creating backup in ${backup_dir}"
sudo cp "${DST_EXTENSION_CORE}" "${backup_dir}/bin/ExtensionCore.py"
sudo cp "${DST_CS_EXTENSIONS}" "${backup_dir}/modules/cs_extensions.py"

echo "Overlaying repo versions into /usr/share/cinnamon/cinnamon-settings"
sudo cp "${SRC_EXTENSION_CORE}" "${DST_EXTENSION_CORE}"
sudo cp "${SRC_CS_EXTENSIONS}" "${DST_CS_EXTENSIONS}"

printf '%s\n' "${backup_dir}" > "${STATE_FILE}"

cat <<'EOF'

Overlay installed.

Launch the Extensions settings page with:
cinnamon-settings extensions --tab installed

Restore the original files later with:
./tools/test-extensions-checkbox-overlay.sh restore
EOF
}

restore_overlay() {
require_installed_targets

if [[ ! -f "${STATE_FILE}" ]]; then
echo "No backup state file found at ${STATE_FILE}" >&2
exit 1
fi

local backup_dir
backup_dir="$(<"${STATE_FILE}")"

[[ -f "${backup_dir}/bin/ExtensionCore.py" ]] || { echo "Missing backup file in ${backup_dir}" >&2; exit 1; }
[[ -f "${backup_dir}/modules/cs_extensions.py" ]] || { echo "Missing backup file in ${backup_dir}" >&2; exit 1; }

echo "Restoring backup from ${backup_dir}"
sudo cp "${backup_dir}/bin/ExtensionCore.py" "${DST_EXTENSION_CORE}"
sudo cp "${backup_dir}/modules/cs_extensions.py" "${DST_CS_EXTENSIONS}"

rm -f "${STATE_FILE}"
echo "Restore complete."
}

show_status() {
if [[ -f "${STATE_FILE}" ]]; then
echo "Active backup: $(<"${STATE_FILE}")"
else
echo "No active overlay backup recorded."
fi
}

main() {
local command="${1:-}"

case "${command}" in
install)
install_overlay
;;
restore)
restore_overlay
;;
status)
show_status
;;
*)
usage
exit 1
;;
esac
}

main "$@"
Loading