mirror of
https://github.com/imarkoff/Marble-shell-theme.git
synced 2025-09-18 01:07:55 -07:00
159 lines
6.9 KiB
Python
159 lines
6.9 KiB
Python
import os
|
|
from typing import Optional
|
|
|
|
from .install.colors_definer import ColorsDefiner
|
|
from scripts.utils.theme.theme import Theme
|
|
from .types.theme_base import ThemeBase
|
|
from .utils import remove_properties, remove_keywords
|
|
from . import config
|
|
from .utils.alternatives_updater import AlternativesUpdater
|
|
from scripts.utils.logger.console import Console, Color, Format
|
|
from .utils.command_runner.subprocess_command_runner import SubprocessCommandRunner
|
|
from .utils.files_labeler import FilesLabeler
|
|
from .utils.gresource import GresourceBackupNotFoundError
|
|
from .utils.gresource.gresource import Gresource
|
|
from .utils.theme.gnome_shell_theme_builder import GnomeShellThemeBuilder
|
|
|
|
|
|
class GlobalTheme(ThemeBase):
|
|
"""Class to install global theme for GDM"""
|
|
def __init__(self,
|
|
colors_json: ColorsDefiner, source_folder: str,
|
|
destination_folder: str, destination_file: str, temp_folder: str | bytes,
|
|
mode: Optional[str] = None, is_filled = False
|
|
):
|
|
"""
|
|
:param colors_json: location of a JSON file with color values
|
|
:param source_folder: raw theme location
|
|
:param destination_folder: folder where themes will be installed
|
|
:param temp_folder: folder where files will be collected
|
|
:param mode: theme mode (light or dark)
|
|
:param is_filled: if True, the theme will be filled
|
|
"""
|
|
self.colors_json = colors_json
|
|
self.source_folder = source_folder
|
|
self.destination_folder = destination_folder
|
|
self.destination_file = destination_file
|
|
self.temp_folder = temp_folder
|
|
self.is_filled = is_filled
|
|
self.mode = mode
|
|
|
|
self.themes: list[ThemePrepare] = []
|
|
|
|
self.__is_installed_trigger = "\n/* Marble theme */\n"
|
|
self.__gresource_file = os.path.join(self.destination_folder, self.destination_file)
|
|
|
|
self.__gresource_temp_folder = os.path.join(self.temp_folder, config.extracted_gdm_folder)
|
|
self.__gresource = Gresource(self.destination_file, self.__gresource_temp_folder, self.destination_folder,
|
|
logger_factory=Console(), runner=SubprocessCommandRunner())
|
|
|
|
def prepare(self):
|
|
if self.__is_installed():
|
|
Console.Line().info("Theme is installed. Reinstalling...")
|
|
self.__gresource.use_backup_gresource()
|
|
|
|
self.__gresource.extract()
|
|
self.__find_themes()
|
|
|
|
def __is_installed(self) -> bool:
|
|
if not hasattr(self, '__is_installed_cached'):
|
|
with open(self.__gresource_file, "rb") as f:
|
|
self.__is_installed_cached = self.__is_installed_trigger.encode() in f.read()
|
|
|
|
return self.__is_installed_cached
|
|
|
|
def __find_themes(self):
|
|
extracted_theme_files = os.listdir(self.__gresource_temp_folder)
|
|
|
|
allowed_modes = ("dark", "light")
|
|
allowed_css = ("gnome-shell-dark", "gnome-shell-light", "gnome-shell")
|
|
|
|
for style_name in allowed_css:
|
|
style_file = style_name + ".css"
|
|
if style_file in extracted_theme_files:
|
|
last_mode = style_name.split("-")[-1]
|
|
mode = last_mode if last_mode in allowed_modes else None
|
|
self.__append_theme(style_name, mode=mode or self.mode, label=mode)
|
|
|
|
def __append_theme(self, theme_type: str, mode = None, label: Optional[str] = None):
|
|
"""Helper to create theme objects"""
|
|
theme_builder = GnomeShellThemeBuilder(self.colors_json)
|
|
theme_builder.with_temp_folder(self.temp_folder)
|
|
theme_builder.with_theme_name(theme_type)
|
|
theme_builder.destination_folder = self.__gresource_temp_folder
|
|
theme_builder.with_mode(mode)
|
|
theme_builder.filled(self.is_filled)
|
|
|
|
theme = theme_builder.build()
|
|
theme.prepare()
|
|
theme_file = os.path.join(self.__gresource_temp_folder, f"{theme_type}.css")
|
|
self.themes.append(ThemePrepare(theme=theme, theme_file=theme_file, label=label))
|
|
|
|
def install(self, hue, sat=None):
|
|
"""Install theme globally"""
|
|
if os.geteuid() != 0:
|
|
raise Exception("Root privileges required to install GDM theme")
|
|
|
|
self.__generate_themes(hue, 'Marble', sat)
|
|
|
|
self.__gresource.compile()
|
|
if not self.__is_installed():
|
|
self.__gresource.backup()
|
|
self.__gresource.move()
|
|
|
|
self.__update_alternatives()
|
|
|
|
def __generate_themes(self, hue: int, color: str, sat: Optional[int] = None):
|
|
"""Generate theme files for gnome-shell-theme.gresource.xml"""
|
|
for theme_prepare in self.themes:
|
|
if theme_prepare.label is not None:
|
|
temp_folder = theme_prepare.theme.temp_folder
|
|
main_styles = theme_prepare.theme.main_styles
|
|
FilesLabeler(temp_folder, main_styles).append_label(theme_prepare.label)
|
|
|
|
remove_keywords(theme_prepare.theme_file, "!important")
|
|
remove_properties(theme_prepare.theme_file, "background-color", "color", "box-shadow", "border-radius")
|
|
|
|
self.__add_gnome_styles(theme_prepare.theme)
|
|
|
|
theme_prepare.theme.install(hue, color, sat, destination=self.__gresource_temp_folder)
|
|
|
|
def __add_gnome_styles(self, theme: Theme):
|
|
"""Add gnome styles to the start of the file"""
|
|
with open(f"{theme.destination_folder}/{theme.theme_name}.css", 'r') as gnome_theme:
|
|
gnome_styles = gnome_theme.read() + self.__is_installed_trigger
|
|
theme.add_to_start(gnome_styles)
|
|
|
|
def __update_alternatives(self):
|
|
link = os.path.join(self.destination_folder, config.ubuntu_gresource_link)
|
|
name = config.ubuntu_gresource_link
|
|
path = os.path.join(self.destination_folder, self.destination_file)
|
|
AlternativesUpdater.install_and_set(link, name, path)
|
|
|
|
def remove(self):
|
|
if self.__is_installed():
|
|
removing_line = Console.Line()
|
|
removing_line.update("Theme is installed. Removing...")
|
|
|
|
try:
|
|
self.__gresource.restore()
|
|
removing_line.success("Global theme removed successfully. Restart GDM to apply changes.")
|
|
except GresourceBackupNotFoundError:
|
|
formatted_shell = Console.format("gnome-shell", color=Color.BLUE, format_type=Format.BOLD)
|
|
removing_line.error(f"Backup file not found. Try reinstalling {formatted_shell} package.")
|
|
else:
|
|
Console.Line().error("Theme is not installed. Nothing to remove.")
|
|
Console.Line().warn("If theme is still installed globally, try reinstalling gnome-shell package.")
|
|
|
|
def __remove_alternatives(self):
|
|
name = config.ubuntu_gresource_link
|
|
path = os.path.join(self.destination_folder, self.destination_file)
|
|
AlternativesUpdater.remove(name, path)
|
|
|
|
|
|
class ThemePrepare:
|
|
"""Theme data class prepared for installation"""
|
|
def __init__(self, theme: Theme, theme_file, label: Optional[str] = None):
|
|
self.theme = theme
|
|
self.theme_file = theme_file
|
|
self.label = label |