Skip to content
Merged
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
113 changes: 86 additions & 27 deletions biglinux-livecd/usr/share/biglinux/livecd/desktop_theme.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
from collections.abc import Mapping
from typing import Protocol

from gnome_layout import LAYOUT_NAMES

logger = logging.getLogger(__name__)
GNOME_LIGHT_STYLE_UUID = "light-style@gnome-shell-extensions.gcampax.github.com"
GNOME_USER_THEME_UUID = "user-theme@gnome-shell-extensions.gcampax.github.com"
GNOME_KIWI_UUID = "kiwi@kemma"
GNOME_DTP_UUID = "dash-to-panel@jderose9.github.com"
GNOME_ALWAYS_DARK_LAYOUTS = frozenset({"biggnome", "g-unity", "minimal"})
GNOME_ORCHIS_LAYOUTS = frozenset({"biggnome", "desk-ux"})
MAX_SETTINGS_BYTES = 1024 * 1024

SettingsChanges = Mapping[str, Mapping[str, str]]
Expand All @@ -22,6 +26,7 @@ class ThemeHost(Protocol):
theme_list_script: str
theme_apply_script: str
theme_state_file: str
gnome_layout_state_file: str

def _run_command(
self,
Expand Down Expand Up @@ -205,23 +210,35 @@ def _settings_key_values(


def _gnome_extension_changes(
settings_file: str, dark: bool
settings_file: str,
*,
user_theme: bool,
light_style: bool,
) -> dict[str, dict[str, str]]:
values = _settings_key_values(settings_file, "org/gnome/shell")
if values is None:
return {}
enabled = _parse_settings_list(values.get("enabled-extensions", "[]"))
disabled = _parse_settings_list(values.get("disabled-extensions", "[]"))
if dark:
enabled = [item for item in enabled if item != GNOME_LIGHT_STYLE_UUID]
enabled = [
item
for item in enabled
if item not in {GNOME_USER_THEME_UUID, GNOME_LIGHT_STYLE_UUID}
]
disabled = [
item
for item in disabled
if item not in {GNOME_USER_THEME_UUID, GNOME_LIGHT_STYLE_UUID}
]
if user_theme:
disabled = [item for item in disabled if item != GNOME_USER_THEME_UUID]
enabled.append(GNOME_USER_THEME_UUID)
disabled.append(GNOME_LIGHT_STYLE_UUID)
else:
enabled = [item for item in enabled if item != GNOME_USER_THEME_UUID]
disabled = [item for item in disabled if item != GNOME_LIGHT_STYLE_UUID]
enabled.append(GNOME_LIGHT_STYLE_UUID)
disabled.append(GNOME_USER_THEME_UUID)
if light_style:
enabled.append(GNOME_LIGHT_STYLE_UUID)
else:
disabled.append(GNOME_LIGHT_STYLE_UUID)
return {
"org/gnome/shell": {
"enabled-extensions": repr(list(dict.fromkeys(enabled))),
Expand All @@ -231,19 +248,39 @@ def _gnome_extension_changes(


def _gnome_layout_class(settings_file: str) -> str:
values = _settings_key_values(settings_file, "org/gnome/shell")
if values is None:
return "biggnome"
enabled = _parse_settings_list(values.get("enabled-extensions", "[]"))
shell_values = _settings_key_values(settings_file, "org/gnome/shell") or {}
user_theme_values = (
_settings_key_values(
settings_file,
"org/gnome/shell/extensions/user-theme",
)
or {}
)
enabled = _parse_settings_list(shell_values.get("enabled-extensions", "[]"))
user_theme_name = user_theme_values.get("name", "").strip().strip("'\"")
if user_theme_name:
return "desk-ux" if GNOME_DTP_UUID in enabled else "biggnome"
if GNOME_KIWI_UUID in enabled:
return "kiwi"
if GNOME_DTP_UUID in enabled:
return "panel"
return "biggnome"
return "minimal"
return "hybrid"


def _selected_gnome_layout(host: ThemeHost) -> str:
state_file = getattr(host, "gnome_layout_state_file", "")
if not state_file:
return ""
try:
layout = _read_regular_text(state_file).strip()
except (OSError, UnicodeError):
return ""
return layout if layout in LAYOUT_NAMES else ""


def _desktop_changes(
desktop_environment: str, settings_file: str, dark: bool
desktop_environment: str,
settings_file: str,
dark: bool,
gnome_layout: str = "",
) -> dict[str, dict[str, str]]:
color_scheme = "'prefer-dark'" if dark else "'default'"
gtk_theme = "'adw-gtk3-dark'" if dark else "'adw-gtk3'"
Expand All @@ -264,16 +301,31 @@ def _desktop_changes(
"name": "'Big-Orange'" if dark else "'Big-Orange-Light'"
}
elif desktop_environment == "GNOME":
layout_class = _gnome_layout_class(settings_file)
if dark and layout_class != "kiwi":
changes["org/gnome/shell/extensions/user-theme"] = {"name": "'Big-Blue'"}
changes.update(_gnome_extension_changes(settings_file, dark=True))
elif not dark and layout_class == "biggnome":
changes["org/gnome/shell/extensions/user-theme"] = {"name": "'Big-Blue'"}
changes.update(_gnome_extension_changes(settings_file, dark=True))
elif not dark and layout_class == "panel":
changes["org/gnome/shell/extensions/user-theme"] = {"name": "'Big-Blue'"}
changes.update(_gnome_extension_changes(settings_file, dark=False))
layout = (
gnome_layout
if gnome_layout in LAYOUT_NAMES
else _gnome_layout_class(settings_file)
)
orchis = layout in GNOME_ORCHIS_LAYOUTS
shell_theme = (
"'Big-Blue-Light'"
if layout == "desk-ux" and not dark
else "'Big-Blue'"
if orchis
else "''"
)
changes["org/gnome/shell/extensions/user-theme"] = {"name": shell_theme}
changes.update(
_gnome_extension_changes(
settings_file,
user_theme=orchis,
light_style=(
not dark
and not orchis
and layout not in GNOME_ALWAYS_DARK_LAYOUTS
),
)
)
return changes


Expand All @@ -298,13 +350,20 @@ def apply_simple_theme(host: ThemeHost, theme: str) -> bool:
return False
dark = theme == "dark"
desktop_environment = host.get_desktop_environment()
gnome_layout = ""
if desktop_environment == "GNOME":
host._ensure_gnome_settings_file()
gnome_layout = _selected_gnome_layout(host)
settings_file = settings_file_path(desktop_environment)
if not modify_settings_file(
host,
settings_file,
_desktop_changes(desktop_environment, settings_file, dark),
_desktop_changes(
desktop_environment,
settings_file,
dark,
gnome_layout=gnome_layout,
),
):
return False
if desktop_environment == "XFCE":
Expand Down
68 changes: 50 additions & 18 deletions tests/test_desktop_settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import ast
import os
import sys
from pathlib import Path
Expand All @@ -11,11 +12,10 @@
sys.path.insert(0, str(LIBRARY))

from desktop_theme import ( # noqa: E402
GNOME_DTP_UUID,
GNOME_KIWI_UUID,
GNOME_LIGHT_STYLE_UUID,
GNOME_USER_THEME_UUID,
_desktop_changes,
_selected_gnome_layout,
apply_packaged_theme,
apply_simple_theme,
update_settings_text,
Expand Down Expand Up @@ -177,31 +177,63 @@ def test_gnome_layout_normalization_is_monitor_independent() -> None:
assert "unrelated='kept'" in normalized


@pytest.mark.parametrize("dark", [False, True], ids=["light", "dark"])
@pytest.mark.parametrize(
("extensions", "expected_enabled", "has_user_theme"),
("layout", "user_theme", "light_style", "light_name", "dark_name"),
[
(["dash-to-dock@micxgx.gmail.com"], GNOME_USER_THEME_UUID, True),
([GNOME_DTP_UUID], GNOME_LIGHT_STYLE_UUID, True),
([GNOME_KIWI_UUID], "", False),
("biggnome", True, False, "'Big-Blue'", "'Big-Blue'"),
("desk-ux", True, False, "'Big-Blue-Light'", "'Big-Blue'"),
("hybrid", False, True, "''", "''"),
("classic", False, True, "''", "''"),
("g-unity", False, False, "''", "''"),
("minimal", False, False, "''", "''"),
],
)
def test_gnome_light_theme_respects_layout_shell_contract(
def test_gnome_theme_matrix_respects_each_layout_shell_contract(
tmp_path: Path,
extensions: list[str],
expected_enabled: str,
has_user_theme: bool,
layout: str,
user_theme: bool,
light_style: bool,
light_name: str,
dark_name: str,
dark: bool,
) -> None:
settings = tmp_path / "settings.gnome"
settings.write_text(
"[org/gnome/shell]\n"
f"enabled-extensions={extensions!r}\n"
f"enabled-extensions={[GNOME_USER_THEME_UUID, GNOME_LIGHT_STYLE_UUID]!r}\n"
"disabled-extensions=[]\n",
encoding="utf-8",
)
changes = _desktop_changes("GNOME", str(settings), dark=False)
shell_changes = changes.get("org/gnome/shell", {})
if expected_enabled:
assert expected_enabled in shell_changes["enabled-extensions"]
else:
assert shell_changes == {}
assert ("org/gnome/shell/extensions/user-theme" in changes) is has_user_theme
changes = _desktop_changes(
"GNOME",
str(settings),
dark=dark,
gnome_layout=layout,
)
shell_changes = changes["org/gnome/shell"]
enabled = ast.literal_eval(shell_changes["enabled-extensions"])
disabled = ast.literal_eval(shell_changes["disabled-extensions"])
expected_light_style = light_style and not dark

assert (GNOME_USER_THEME_UUID in enabled) is user_theme
assert (GNOME_USER_THEME_UUID in disabled) is not user_theme
assert (GNOME_LIGHT_STYLE_UUID in enabled) is expected_light_style
assert (GNOME_LIGHT_STYLE_UUID in disabled) is not expected_light_style
assert changes["org/gnome/shell/extensions/user-theme"] == {
"name": dark_name if dark else light_name
}
assert changes["org/gnome/desktop/interface"]["color-scheme"] == (
"'prefer-dark'" if dark else "'default'"
)


def test_selected_gnome_layout_uses_live_state(tmp_path: Path) -> None:
state = tmp_path / "big_gnome_layout"
state.write_text("hybrid\n", encoding="utf-8")
host = type("Host", (), {"gnome_layout_state_file": str(state)})()

assert _selected_gnome_layout(host) == "hybrid"

state.write_text("../../invalid\n", encoding="utf-8")
assert _selected_gnome_layout(host) == ""
Loading