Skip to content

Commit ef1cfca

Browse files
authored
Merge pull request slgobinath#692 from deltragon/style-priorities
rework custom stylesheet loading
2 parents f3e34c3 + d6c6a9d commit ef1cfca

File tree

6 files changed

+81
-41
lines changed

6 files changed

+81
-41
lines changed

safeeyes/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def main():
130130
utility.initialize_logging(args.debug)
131131
utility.initialize_platform()
132132
config = Config()
133-
utility.create_user_stylesheet_if_missing()
133+
utility.cleanup_old_user_stylesheet()
134134

135135
if __running():
136136
logging.info("Safe Eyes is already running")

safeeyes/config/locale/safeeyes.pot

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,3 +557,7 @@ msgstr ""
557557

558558
msgid "License:"
559559
msgstr ""
560+
561+
#, python-format
562+
msgid "Old stylesheet found at '%(old)s', ignoring. For custom styles, create a new stylesheet in '%(new)s' instead."
563+
msgstr ""

safeeyes/model.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,8 +327,6 @@ def __init__(self, init=True):
327327
self.__user_config, self.__system_config
328328
)
329329
self.__user_config = self.__system_config
330-
# Update the style sheet
331-
utility.replace_style_sheet()
332330

333331
utility.merge_plugins(self.__user_config)
334332
self.save()

safeeyes/safeeyes.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,11 @@ def do_startup(self):
104104
else:
105105
self.context["session"] = {"plugin": {}}
106106

107+
# Initialize the theme
108+
self._initialize_styles()
109+
107110
self.break_screen = BreakScreen(
108-
self,
109-
self.context,
110-
self.on_skipped,
111-
self.on_postponed,
112-
utility.STYLE_SHEET_PATH,
111+
self, self.context, self.on_skipped, self.on_postponed
113112
)
114113
self.break_screen.initialize(self.config)
115114
self.plugins_manager = PluginManager()
@@ -166,6 +165,16 @@ def do_activate(self):
166165
elif self.cli_args.take_break:
167166
self.take_break()
168167

168+
def _initialize_styles(self):
169+
utility.load_css_file(
170+
utility.SYSTEM_STYLE_SHEET_PATH, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
171+
)
172+
utility.load_css_file(
173+
utility.CUSTOM_STYLE_SHEET_PATH,
174+
Gtk.STYLE_PROVIDER_PRIORITY_USER,
175+
required=False,
176+
)
177+
169178
def _retry_errored_plugins(self):
170179
if not self.plugins_manager.needs_retry():
171180
return

safeeyes/ui/break_screen.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@ class BreakScreen:
4343
interface.
4444
"""
4545

46-
def __init__(
47-
self, application, context, on_skipped, on_postponed, style_sheet_path
48-
):
46+
def __init__(self, application, context, on_skipped, on_postponed):
4947
self.application = application
5048
self.context = context
5149
self.count_labels = []
@@ -64,15 +62,6 @@ def __init__(
6462
if not self.context["is_wayland"]:
6563
self.x11_display = Display()
6664

67-
# Initialize the theme
68-
css_provider = Gtk.CssProvider()
69-
css_provider.load_from_path(style_sheet_path)
70-
71-
display = Gdk.Display.get_default()
72-
Gtk.StyleContext.add_provider_for_display(
73-
display, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
74-
)
75-
7665
def initialize(self, config):
7766
"""Initialize the internal properties from configuration."""
7867
logging.info("Initialize the break screen")

safeeyes/utility.py

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"""This module contains utility functions for Safe Eyes and its plugins."""
2020

2121
import errno
22+
import hashlib
2223
import inspect
2324
import importlib
2425
import json
@@ -38,13 +39,14 @@
3839
import gi
3940

4041
gi.require_version("Gtk", "4.0")
42+
gi.require_version("Gdk", "4.0")
43+
44+
from gi.repository import Gdk
4145
from gi.repository import Gtk
4246
from gi.repository import GLib
4347
from gi.repository import GdkPixbuf
4448
from packaging.version import parse
4549

46-
gi.require_version("Gdk", "4.0")
47-
4850
BIN_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
4951
HOME_DIRECTORY = os.environ.get("HOME") or os.path.expanduser("~")
5052
CONFIG_DIRECTORY = os.path.join(
@@ -55,7 +57,10 @@
5557
CONFIG_FILE_PATH = os.path.join(CONFIG_DIRECTORY, "safeeyes.json")
5658
CONFIG_RESOURCE = os.path.join(CONFIG_DIRECTORY, "resource")
5759
SESSION_FILE_PATH = os.path.join(CONFIG_DIRECTORY, "session.json")
58-
STYLE_SHEET_PATH = os.path.join(STYLE_SHEET_DIRECTORY, "safeeyes_style.css")
60+
OLD_STYLE_SHEET_PATH = os.path.join(STYLE_SHEET_DIRECTORY, "safeeyes_style.css")
61+
CUSTOM_STYLE_SHEET_PATH = os.path.join(
62+
STYLE_SHEET_DIRECTORY, "safeeyes_custom_style.css"
63+
)
5964
SYSTEM_CONFIG_FILE_PATH = os.path.join(BIN_DIRECTORY, "config/safeeyes.json")
6065
SYSTEM_STYLE_SHEET_PATH = os.path.join(BIN_DIRECTORY, "config/style/safeeyes_style.css")
6166
LOG_FILE_PATH = os.path.join(HOME_DIRECTORY, "safeeyes.log")
@@ -372,8 +377,32 @@ def merge_configs(new_config, old_config):
372377
return new_config
373378

374379

380+
def sha256sum(filename):
381+
"""Get the sha256 hash of the given file."""
382+
h = hashlib.sha256()
383+
b = bytearray(128 * 1024)
384+
mv = memoryview(b)
385+
with open(filename, "rb", buffering=0) as f:
386+
for n in iter(lambda: f.readinto(mv), 0):
387+
h.update(mv[:n])
388+
return h.hexdigest()
389+
390+
391+
def load_css_file(style_sheet_path, priority, required=True):
392+
if not os.path.isfile(style_sheet_path):
393+
if required:
394+
logging.warning("Failed loading required stylesheet")
395+
return
396+
397+
css_provider = Gtk.CssProvider()
398+
css_provider.load_from_path(style_sheet_path)
399+
400+
display = Gdk.Display.get_default()
401+
Gtk.StyleContext.add_provider_for_display(display, css_provider, priority)
402+
403+
375404
def initialize_safeeyes():
376-
"""Create the config file and style sheet in XDG_CONFIG_HOME(or
405+
"""Create the config file in XDG_CONFIG_HOME(or
377406
~/.config)/safeeyes directory.
378407
"""
379408
logging.info("Copy the config files to XDG_CONFIG_HOME(or ~/.config)/safeeyes")
@@ -388,24 +417,45 @@ def initialize_safeeyes():
388417
shutil.copy2(SYSTEM_CONFIG_FILE_PATH, CONFIG_FILE_PATH)
389418
os.chmod(CONFIG_FILE_PATH, 0o666)
390419

391-
create_user_stylesheet_if_missing()
392-
393420
# initialize_safeeyes gets called when the configuration file is not present, which
394421
# happens just after installation or manual deletion of
395422
# .config/safeeyes/safeeyes.json file. In these cases, we want to force the creation
396423
# of a startup entry
397424
create_startup_entry(force=True)
398425

399426

400-
def create_user_stylesheet_if_missing():
427+
def cleanup_old_user_stylesheet():
401428
# Create the XDG_CONFIG_HOME(or ~/.config)/safeeyes/style directory
402429
if not os.path.isdir(STYLE_SHEET_DIRECTORY):
403430
mkdir(STYLE_SHEET_DIRECTORY)
404431

405-
# Copy the new style sheet
406-
if not os.path.isfile(STYLE_SHEET_PATH):
407-
shutil.copy2(SYSTEM_STYLE_SHEET_PATH, STYLE_SHEET_PATH)
408-
os.chmod(STYLE_SHEET_PATH, 0o666)
432+
# Delete the old stylesheet, unless it has customizations
433+
if os.path.isfile(OLD_STYLE_SHEET_PATH):
434+
hash = sha256sum(OLD_STYLE_SHEET_PATH)
435+
old_default_versions = [
436+
# 2.2.3
437+
"fdc2a305613ae4eeb269650452789d35df3df5bdf1c56eb576cd5ebac70a6f09",
438+
# 2.1.0 - 2.2.2
439+
"fbde048fc234db757461971a7542df43a467869035ca3d05ff9b236ca250e4c5",
440+
# 2.0.9
441+
"70ca55c12d83ad7a6a4e1c5e7758a38617a43f5d32f28709ede75426d3186713",
442+
# 2.0.7 - 2.0.8
443+
"7a15f985e0da6d92c8a62d49ce151781e6d423f87e66d205cc1dc4536e369e19",
444+
# 2.0.6 and earlier
445+
"f26621a883e323ca7685a4adba25027e70daa471e0db4a21c261e6c15caaa5ee",
446+
]
447+
if hash in old_default_versions:
448+
logging.info("Deleting old stylesheet containing default content")
449+
delete(OLD_STYLE_SHEET_PATH)
450+
else:
451+
# Stylesheet was likely customized, don't delete but warn
452+
logging.warning(
453+
_(
454+
"Old stylesheet found at '%(old)s', ignoring. For custom styles, "
455+
"create a new stylesheet in '%(new)s' instead.",
456+
)
457+
% {"old": OLD_STYLE_SHEET_PATH, "new": CUSTOM_STYLE_SHEET_PATH}
458+
)
409459

410460

411461
def create_startup_entry(force=False):
@@ -517,26 +567,16 @@ def initialize_platform():
517567
def reset_config():
518568
# Remove the ~/.config/safeeyes/safeeyes.json and safeeyes_style.css
519569
delete(CONFIG_FILE_PATH)
520-
delete(STYLE_SHEET_PATH)
521570

522571
# Copy the safeeyes.json and safeeyes_style.css
523572
shutil.copy2(SYSTEM_CONFIG_FILE_PATH, CONFIG_FILE_PATH)
524-
shutil.copy2(SYSTEM_STYLE_SHEET_PATH, STYLE_SHEET_PATH)
525573

526574
# Add write permission (e.g. if original file was stored in /nix/store)
527575
os.chmod(CONFIG_FILE_PATH, 0o666)
528-
os.chmod(STYLE_SHEET_PATH, 0o666)
529576

530577
create_startup_entry()
531578

532579

533-
def replace_style_sheet():
534-
"""Replace the user style sheet by system style sheet."""
535-
delete(STYLE_SHEET_PATH)
536-
shutil.copy2(SYSTEM_STYLE_SHEET_PATH, STYLE_SHEET_PATH)
537-
os.chmod(STYLE_SHEET_PATH, 0o666)
538-
539-
540580
def initialize_logging(debug):
541581
"""Initialize the logging framework using the Safe Eyes specific
542582
configurations.

0 commit comments

Comments
 (0)