From 1245951da9e6c044d156bcc0d8cce271120ab421 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Fri, 16 Feb 2024 20:13:22 -0600 Subject: [PATCH 01/27] Cleanup of starting file collection --- src/core/controllers/base_controller.py | 13 ++++--------- src/core/controllers/base_controller_data.py | 14 ++++++++++++++ src/libs/settings_manager/manager.py | 8 +++++++- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/core/controllers/base_controller.py b/src/core/controllers/base_controller.py index a42387f..42280ac 100644 --- a/src/core/controllers/base_controller.py +++ b/src/core/controllers/base_controller.py @@ -1,5 +1,4 @@ # Python imports -import os # Lib imports import gi @@ -19,6 +18,8 @@ from .bridge_controller import BridgeController class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): def __init__(self, args, unknownargs): + self.collect_files_dirs(args, unknownargs) + self.setup_controller_data() self._setup_styling() @@ -29,14 +30,8 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): if args.no_plugins == "false": self.plugins.launch_plugins() - for arg in unknownargs + [args.new_tab,]: - if os.path.isfile(arg): - message = f"FILE|{arg}" - event_system.emit("post_file_to_ipc", message) - - if os.path.isdir(arg): - message = f"DIR|{arg}" - event_system.emit("post_file_to_ipc", message) + for file in settings_manager.get_starting_files(): + event_system.emit("post_file_to_ipc", file) logger.info(f"Made it past {self.__class__} loading...") diff --git a/src/core/controllers/base_controller_data.py b/src/core/controllers/base_controller_data.py index 937ba88..3a5c7da 100644 --- a/src/core/controllers/base_controller_data.py +++ b/src/core/controllers/base_controller_data.py @@ -25,6 +25,20 @@ class BaseControllerData: self.setup_builder_and_container() self.plugins = PluginsController() + def collect_files_dirs(self, args, unknownargs): + files = [] + for arg in unknownargs + [args.new_tab,]: + if os.path.isdir( arg.replace("file://", "") ): + files.append( f"DIR|{arg.replace('file://', '')}" ) + + # NOTE: If passing line number with file split against : + if os.path.isfile( arg.replace("file://", "").split(":")[0] ): + files.append( f"FILE|{arg.replace('file://', '')}" ) + + if len(files) > 0: + settings_manager.set_is_starting_with_file(True) + settings_manager.set_starting_files(files) + def get_base_container(self): return self.base_container diff --git a/src/libs/settings_manager/manager.py b/src/libs/settings_manager/manager.py index 6aa0fb7..da1b183 100644 --- a/src/libs/settings_manager/manager.py +++ b/src/libs/settings_manager/manager.py @@ -110,6 +110,8 @@ class SettingsManager(StartCheckMixin, Singleton): self._trace_debug = False self._debug = False self._dirty_start = False + self._passed_in_file = False + self._starting_files = [] def register_signals_to_builder(self, classes=None): @@ -128,7 +130,6 @@ class SettingsManager(StartCheckMixin, Singleton): def set_main_window(self, window): self._main_window = window def set_builder(self, builder) -> any: self._builder = builder - def get_monitor_data(self) -> list: screen = self._main_window.get_screen() monitors = [] @@ -152,9 +153,11 @@ class SettingsManager(StartCheckMixin, Singleton): def get_home_config_path(self) -> str: return self._HOME_CONFIG_PATH def get_window_icon(self) -> str: return self._WINDOW_ICON def get_home_path(self) -> str: return self._USER_HOME + def get_starting_files(self) -> []: return self._starting_files def is_trace_debug(self) -> str: return self._trace_debug def is_debug(self) -> str: return self._debug + def is_starting_with_file(self) -> bool: return self._passed_in_file def call_method(self, target_class = None, _method_name = None, data = None): method_name = str(_method_name) @@ -167,6 +170,7 @@ class SettingsManager(StartCheckMixin, Singleton): def set_main_window_height(self, height = 600): self.settings.config.main_window_height = height def set_main_window_min_width(self, width = 720): self.settings.config.main_window_min_width = width def set_main_window_min_height(self, height = 480): self.settings.config.main_window_min_height = height + def set_starting_files(self, files: []) -> None: self._starting_files = files def set_trace_debug(self, trace_debug): self._trace_debug = trace_debug @@ -174,6 +178,8 @@ class SettingsManager(StartCheckMixin, Singleton): def set_debug(self, debug): self._debug = debug + def set_is_starting_with_file(self, is_passed_in_file: False): + self._passed_in_file = is_passed_in_file def load_settings(self): if not path.exists(self._CONFIG_FILE): From 1695f5bc5c8d67ee3e770d45aab1b38a55617f04 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Fri, 16 Feb 2024 20:43:09 -0600 Subject: [PATCH 02/27] Overode method to add debug logging --- src/core/widgets/webkit_ui.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/widgets/webkit_ui.py b/src/core/widgets/webkit_ui.py index 074adf0..6b1f4ee 100644 --- a/src/core/widgets/webkit_ui.py +++ b/src/core/widgets/webkit_ui.py @@ -62,3 +62,6 @@ class WebkitUI(WebKit2.WebView): command = f"displayMessage('{message}', '{mtype}', '3')" self.run_javascript(command, None, None) + def run_javascript(self, script, cancellable, callback): + logger.debug(script) + super().run_javascript(script, cancellable, callback) From d81bf3815a988550fe1c4109916c037f2dd62868 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Wed, 21 Feb 2024 20:34:42 -0600 Subject: [PATCH 03/27] Removed logging item --- src/libs/mixins/keyboard_signals_mixin.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/mixins/keyboard_signals_mixin.py b/src/libs/mixins/keyboard_signals_mixin.py index 4659adf..0a2d690 100644 --- a/src/libs/mixins/keyboard_signals_mixin.py +++ b/src/libs/mixins/keyboard_signals_mixin.py @@ -89,8 +89,6 @@ class KeyboardSignalsMixin: self.handle_as_key_event_system(sender, eve_type) def handle_as_key_event_scope(self, mapping): - logger.debug(f"on_global_key_release_controller > key > {keyname}") - if self.ctrl_down and not keyname in ["1", "kp_1", "2", "kp_2", "3", "kp_3", "4", "kp_4"]: self.handle_key_event_system(None, mapping) From 2389f1d4147fced6d6f715a1034df1e11ef46cfd Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Wed, 21 Feb 2024 22:15:25 -0600 Subject: [PATCH 04/27] moved db stuff to own folder --- src/libs/db/__init__.py | 6 ++++++ src/libs/{ => db}/db.py | 0 src/libs/{ => db}/models.py | 0 3 files changed, 6 insertions(+) create mode 100644 src/libs/db/__init__.py rename src/libs/{ => db}/db.py (100%) rename src/libs/{ => db}/models.py (100%) diff --git a/src/libs/db/__init__.py b/src/libs/db/__init__.py new file mode 100644 index 0000000..135071c --- /dev/null +++ b/src/libs/db/__init__.py @@ -0,0 +1,6 @@ +""" + DB module +""" + +from .models import User +from .db import DB diff --git a/src/libs/db.py b/src/libs/db/db.py similarity index 100% rename from src/libs/db.py rename to src/libs/db/db.py diff --git a/src/libs/models.py b/src/libs/db/models.py similarity index 100% rename from src/libs/models.py rename to src/libs/db/models.py From cc8f62776d36dc8210757362a5373b7d0c323d33 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Fri, 23 Feb 2024 23:45:13 -0600 Subject: [PATCH 05/27] Fixed bindings; added bindings --- src/core/containers/header_container.py | 5 ++++- src/libs/mixins/keyboard_signals_mixin.py | 10 +++++----- user_config/usr/share/app_name/key-bindings.json | 1 + 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/core/containers/header_container.py b/src/core/containers/header_container.py index 857cbeb..155e79c 100644 --- a/src/core/containers/header_container.py +++ b/src/core/containers/header_container.py @@ -32,7 +32,7 @@ class HeaderContainer(Gtk.Box): ... def _subscribe_to_events(self): - ... + event_system.subscribe("tggl_top_main_menubar", self.tggl_top_main_menubar) def _load_widgets(self): @@ -44,3 +44,6 @@ class HeaderContainer(Gtk.Box): def _interactive_debug(self, widget = None, eve = None): event_system.emit("load_interactive_debug") + + def tggl_top_main_menubar(self): + self.hide() if self.is_visible() else self.show() diff --git a/src/libs/mixins/keyboard_signals_mixin.py b/src/libs/mixins/keyboard_signals_mixin.py index 0a2d690..03446d0 100644 --- a/src/libs/mixins/keyboard_signals_mixin.py +++ b/src/libs/mixins/keyboard_signals_mixin.py @@ -68,11 +68,11 @@ class KeyboardSignalsMixin: if mapping: self.handle_mapped_key_event(mapping) else: - self.handle_as_key_event_scope(mapping) + self.handle_as_key_event_scope(keyname) def handle_mapped_key_event(self, mapping): try: - self.handle_as_controller_scope() + self.handle_as_controller_scope(mapping) except Exception: self.handle_as_plugin_scope(mapping) @@ -86,11 +86,11 @@ class KeyboardSignalsMixin: sender = "" eve_type = mapping - self.handle_as_key_event_system(sender, eve_type) + self.handle_key_event_system(sender, eve_type) - def handle_as_key_event_scope(self, mapping): + def handle_as_key_event_scope(self, keyname): if self.ctrl_down and not keyname in ["1", "kp_1", "2", "kp_2", "3", "kp_3", "4", "kp_4"]: - self.handle_key_event_system(None, mapping) + self.handle_key_event_system(None, keyname) def handle_key_event_system(self, sender, eve_type): event_system.emit(eve_type) \ No newline at end of file diff --git a/user_config/usr/share/app_name/key-bindings.json b/user_config/usr/share/app_name/key-bindings.json index a172eea..52a4f6d 100644 --- a/user_config/usr/share/app_name/key-bindings.json +++ b/user_config/usr/share/app_name/key-bindings.json @@ -6,6 +6,7 @@ "refresh_tab" : ["F5", "r"], "delete_files" : "Delete", "tggl_top_main_menubar" : "Alt_L", + "tggl_top_main_menubar" : "0", "trash_files" : "t", "tear_down" : "q", "go_up" : "Up", From ea62eb280c5535badedd26f236cfe1b3d811d47c Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sat, 24 Feb 2024 21:55:40 -0600 Subject: [PATCH 06/27] Added builder wrapper due to plugin setup --- src/core/builder_wrapper.py | 33 ++++++++++++++++++++ src/core/controllers/base_controller.py | 6 ++-- src/core/controllers/base_controller_data.py | 6 ++-- 3 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 src/core/builder_wrapper.py diff --git a/src/core/builder_wrapper.py b/src/core/builder_wrapper.py new file mode 100644 index 0000000..9245da9 --- /dev/null +++ b/src/core/builder_wrapper.py @@ -0,0 +1,33 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports + + + +class BuilderWrapper(Gtk.Builder): + """docstring for BuilderWrapper.""" + + def __init__(self): + super(BuilderWrapper, self).__init__() + + self.objects = {} + + def get_object(self, id: str, use_gtk: bool = True) -> any: + if not use_gtk: + return self.objects[id] + + return super(BuilderWrapper, self).get_object(id) + + def expose_object(self, id: str, object: any, use_gtk: bool = True) -> None: + if not use_gtk: + self.objects[id] = object + else: + super(BuilderWrapper, self).expose_object(id, object) + + def dereference_object(self, id: str) -> None: + del self.objects[id] diff --git a/src/core/controllers/base_controller.py b/src/core/controllers/base_controller.py index 42280ac..1728ca1 100644 --- a/src/core/controllers/base_controller.py +++ b/src/core/controllers/base_controller.py @@ -56,12 +56,12 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): def _tggl_top_main_menubar(self): logger.debug("_tggl_top_main_menubar > stub...") - def setup_builder_and_container(self): - self.builder = Gtk.Builder() + def _load_glade_file(self): self.builder.add_from_file(settings_manager.get_glade_file()) self.builder.expose_object("main_window", self.window) settings_manager.set_builder(self.builder) self.base_container = BaseContainer() - settings_manager.register_signals_to_builder([self, self.base_container]) \ No newline at end of file + settings_manager.register_signals_to_builder([self, self.base_container]) + diff --git a/src/core/controllers/base_controller_data.py b/src/core/controllers/base_controller_data.py index 3a5c7da..23f7461 100644 --- a/src/core/controllers/base_controller_data.py +++ b/src/core/controllers/base_controller_data.py @@ -7,6 +7,7 @@ from shutil import which # Application imports from plugins.plugins_controller import PluginsController +from ..builder_wrapper import BuilderWrapper @@ -15,14 +16,15 @@ class BaseControllerData: def setup_controller_data(self) -> None: self.window = settings_manager.get_main_window() - self.builder = None + self.builder = BuilderWrapper() + self.base_container = None self.was_midified_key = False self.ctrl_down = False self.shift_down = False self.alt_down = False - self.setup_builder_and_container() + self._load_glade_file() self.plugins = PluginsController() def collect_files_dirs(self, args, unknownargs): From b1096055b769d328fd54e732b141c94d4eec1335 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sun, 25 Feb 2024 16:19:14 -0600 Subject: [PATCH 07/27] Renamed settings folder; hyphenated event names --- src/__builtins__.py | 2 +- src/core/containers/base_container.py | 4 +- src/core/containers/center_container.py | 1 - src/core/containers/header_container.py | 4 +- src/core/containers/left_container.py | 1 - src/core/containers/right_container.py | 1 - src/core/controllers/base_controller.py | 10 +-- src/core/controllers/bridge_controller.py | 10 +-- src/core/widgets/transparency_scale.py | 4 +- src/core/widgets/webkit/webkit_ui.py | 56 +++------------- src/core/widgets/webkit_ui.py | 67 ------------------- src/core/window.py | 12 ++-- src/libs/{data_types => dto}/__init__.py | 0 src/libs/{data_types => dto}/event.py | 0 src/libs/ipc_server.py | 6 +- src/libs/mixins/dnd_mixin.py | 2 +- .../__init__.py | 0 .../{settings_manager => settings}/manager.py | 0 .../options/__init__.py | 0 .../options/config.py | 0 .../options/debugging.py | 0 .../options/filters.py | 0 .../options/settings.py | 0 .../options/theming.py | 0 .../other/__init__.py | 0 .../other/webkit_ui_settings.py | 0 .../start_check_mixin.py | 0 .../usr/share/app_name/key-bindings.json | 38 +++++------ 28 files changed, 55 insertions(+), 163 deletions(-) delete mode 100644 src/core/widgets/webkit_ui.py rename src/libs/{data_types => dto}/__init__.py (100%) rename src/libs/{data_types => dto}/event.py (100%) rename src/libs/{settings_manager => settings}/__init__.py (100%) rename src/libs/{settings_manager => settings}/manager.py (100%) rename src/libs/{settings_manager => settings}/options/__init__.py (100%) rename src/libs/{settings_manager => settings}/options/config.py (100%) rename src/libs/{settings_manager => settings}/options/debugging.py (100%) rename src/libs/{settings_manager => settings}/options/filters.py (100%) rename src/libs/{settings_manager => settings}/options/settings.py (100%) rename src/libs/{settings_manager => settings}/options/theming.py (100%) rename src/libs/{settings_manager => settings}/other/__init__.py (100%) rename src/libs/{settings_manager => settings}/other/webkit_ui_settings.py (100%) rename src/libs/{settings_manager => settings}/start_check_mixin.py (100%) diff --git a/src/__builtins__.py b/src/__builtins__.py index 827ee12..770a5a3 100644 --- a/src/__builtins__.py +++ b/src/__builtins__.py @@ -11,7 +11,7 @@ from libs.event_system import EventSystem from libs.endpoint_registry import EndpointRegistry from libs.keybindings import Keybindings from libs.logger import Logger -from libs.settings_manager.manager import SettingsManager +from libs.settings.manager import SettingsManager diff --git a/src/core/containers/base_container.py b/src/core/containers/base_container.py index 387cbbd..2dad04a 100644 --- a/src/core/containers/base_container.py +++ b/src/core/containers/base_container.py @@ -33,8 +33,8 @@ class BaseContainer(Gtk.Box): ... def _subscribe_to_events(self): - event_system.subscribe("update_transparency", self._update_transparency) - event_system.subscribe("remove_transparency", self._remove_transparency) + event_system.subscribe("update-transparency", self._update_transparency) + event_system.subscribe("remove-transparency", self._remove_transparency) def _load_widgets(self): self.add(HeaderContainer()) diff --git a/src/core/containers/center_container.py b/src/core/containers/center_container.py index 7d51eb2..887f2f2 100644 --- a/src/core/containers/center_container.py +++ b/src/core/containers/center_container.py @@ -31,7 +31,6 @@ class CenterContainer(Gtk.Box): ... def _subscribe_to_events(self): - # event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc) ... def _load_widgets(self): diff --git a/src/core/containers/header_container.py b/src/core/containers/header_container.py index 155e79c..7ed41a3 100644 --- a/src/core/containers/header_container.py +++ b/src/core/containers/header_container.py @@ -32,7 +32,7 @@ class HeaderContainer(Gtk.Box): ... def _subscribe_to_events(self): - event_system.subscribe("tggl_top_main_menubar", self.tggl_top_main_menubar) + event_system.subscribe("tggl-top-main-menubar", self.tggl_top_main_menubar) def _load_widgets(self): @@ -43,7 +43,7 @@ class HeaderContainer(Gtk.Box): self.add(button) def _interactive_debug(self, widget = None, eve = None): - event_system.emit("load_interactive_debug") + event_system.emit("load-interactive-debug") def tggl_top_main_menubar(self): self.hide() if self.is_visible() else self.show() diff --git a/src/core/containers/left_container.py b/src/core/containers/left_container.py index 77cd490..aa9ec97 100644 --- a/src/core/containers/left_container.py +++ b/src/core/containers/left_container.py @@ -28,7 +28,6 @@ class LeftContainer(Gtk.Box): ... def _subscribe_to_events(self): - # event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc) ... def _load_widgets(self): diff --git a/src/core/containers/right_container.py b/src/core/containers/right_container.py index f0ac75d..a5869fc 100644 --- a/src/core/containers/right_container.py +++ b/src/core/containers/right_container.py @@ -28,7 +28,6 @@ class RightContainer(Gtk.Box): ... def _subscribe_to_events(self): - # event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc) ... def _load_widgets(self): diff --git a/src/core/controllers/base_controller.py b/src/core/controllers/base_controller.py index 1728ca1..8ccd90c 100644 --- a/src/core/controllers/base_controller.py +++ b/src/core/controllers/base_controller.py @@ -31,7 +31,7 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): self.plugins.launch_plugins() for file in settings_manager.get_starting_files(): - event_system.emit("post_file_to_ipc", file) + event_system.emit("post-file-to-ipc", file) logger.info(f"Made it past {self.__class__} loading...") @@ -45,10 +45,10 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): self.window.connect("key-release-event", self.on_global_key_release_controller) def _subscribe_to_events(self): - event_system.subscribe("shutting_down", lambda: print("Shutting down...")) - event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc) - event_system.subscribe("handle_dir_from_ipc", self.handle_dir_from_ipc) - event_system.subscribe("tggl_top_main_menubar", self._tggl_top_main_menubar) + event_system.subscribe("shutting-down", lambda: print("Shutting down...")) + event_system.subscribe("handle-file-from-ipc", self.handle_file_from_ipc) + event_system.subscribe("handle-dir-from-ipc", self.handle_dir_from_ipc) + event_system.subscribe("tggl-top-main-menubar", self._tggl_top_main_menubar) def _load_controllers(self): BridgeController() diff --git a/src/core/controllers/bridge_controller.py b/src/core/controllers/bridge_controller.py index 648139e..9a689c8 100644 --- a/src/core/controllers/bridge_controller.py +++ b/src/core/controllers/bridge_controller.py @@ -20,19 +20,19 @@ class BridgeController: ... def _subscribe_to_events(self): - event_system.subscribe("handle_bridge_event", self.handle_bridge_event) + event_system.subscribe("handle-bridge-event", self.handle_bridge_event) def handle_bridge_event(self, event): match event.topic: case "save": - event_system.emit(f"handle_file_event_{event.originator}", (event,)) + event_system.emit(f"handle-file-event-{event.originator}", (event,)) case "close": - event_system.emit(f"handle_file_event_{event.originator}", (event,)) + event_system.emit(f"handle-file-event-{event.originator}", (event,)) case "load_buffer": - event_system.emit(f"handle_file_event_{event.originator}", (event,)) + event_system.emit(f"handle-file-event-{event.originator}", (event,)) case "load_file": - event_system.emit(f"handle_file_event_{event.originator}", (event,)) + event_system.emit(f"handle-file-event-{event.originator}", (event,)) case "alert": content = base64.b64decode( event.content.encode() ).decode("utf-8") logger.info(f"\nMessage Topic: {event.topic}\nMessage Content: {content}") diff --git a/src/core/widgets/transparency_scale.py b/src/core/widgets/transparency_scale.py index 1e48177..02c11e4 100644 --- a/src/core/widgets/transparency_scale.py +++ b/src/core/widgets/transparency_scale.py @@ -42,7 +42,7 @@ class TransparencyScale(Gtk.Scale): adjust.set_step_increment(1.0) def _update_transparency(self, range): - event_system.emit("remove_transparency") + event_system.emit("remove-transparency") tp = int(range.get_value()) settings.theming.transparency = tp - event_system.emit("update_transparency") \ No newline at end of file + event_system.emit("update-transparency") \ No newline at end of file diff --git a/src/core/widgets/webkit/webkit_ui.py b/src/core/widgets/webkit/webkit_ui.py index b16bebc..9b55997 100644 --- a/src/core/widgets/webkit/webkit_ui.py +++ b/src/core/widgets/webkit/webkit_ui.py @@ -9,7 +9,8 @@ from gi.repository import Gdk from gi.repository import WebKit2 # Application imports -from libs.data_types import Event +from libs.settings.other.webkit_ui_settings import WebkitUISettings +from libs.dto.event import Event @@ -17,9 +18,6 @@ class WebkitUI(WebKit2.WebView): def __init__(self): super(WebkitUI, self).__init__() - # self.get_context().set_sandbox_enabled(False) - - self._load_settings() self._setup_styling() self._subscribe_to_events() self._load_view() @@ -27,10 +25,6 @@ class WebkitUI(WebKit2.WebView): self.show_all() - if settings_manager.is_debug(): - inspector = self.get_inspector() - inspector.show() - def _setup_styling(self): self.set_vexpand(True) @@ -38,8 +32,8 @@ class WebkitUI(WebKit2.WebView): self.set_background_color( Gdk.RGBA(0, 0, 0, 0.0) ) def _subscribe_to_events(self): - event_system.subscribe(f"ui_message", self.ui_message) - + event_system.subscribe(f"ui-message", self.ui_message) + def _load_settings(self): self.set_settings( WebkitUISettings() ) @@ -54,7 +48,6 @@ class WebkitUI(WebKit2.WebView): def _setup_content_manager(self): content_manager = self.get_user_content_manager() - content_manager.connect("script-message-received", self._process_js_message) content_manager.register_script_message_handler("backend") @@ -64,45 +57,14 @@ class WebkitUI(WebKit2.WebView): try: event = Event( **json.loads(message) ) - event_system.emit("handle_bridge_event", (event,)) + event_system.emit("handle-bridge-event", (event,)) except Exception as e: logger.info(e) - def ui_message(self, mtype, message): + def ui_message(self, message, mtype): command = f"displayMessage('{message}', '{mtype}', '3')" self.run_javascript(command, None, None) - -class WebkitUISettings(WebKit2.Settings): - def __init__(self): - super(WebkitUISettings, self).__init__() - - self._set_default_settings() - - - # Note: Highly insecure setup but most "app" like setup I could think of. - # Audit heavily any scripts/links ran/clicked under this setup! - def _set_default_settings(self): - # self.set_enable_xss_auditor(True) - # self.set_enable_hyperlink_auditing(True) - self.set_enable_xss_auditor(False) - self.set_enable_hyperlink_auditing(False) - self.set_enable_dns_prefetching(False) - self.set_allow_file_access_from_file_urls(True) - self.set_allow_universal_access_from_file_urls(True) - # self.set_enable_java(True) - - self.set_enable_page_cache(False) - self.set_enable_offline_web_application_cache(False) - self.set_enable_html5_local_storage(False) - self.set_enable_html5_database(False) - - self.set_print_backgrounds(False) - self.set_enable_tabs_to_links(False) - self.set_enable_fullscreen(True) - self.set_enable_developer_extras(True) - self.set_enable_webrtc(True) - self.set_enable_webaudio(True) - self.set_enable_accelerated_2d_canvas(True) - - self.set_user_agent(f"Mozilla/5.0 {app_name}") \ No newline at end of file + def run_javascript(self, script, cancellable, callback): + logger.debug(script) + super().run_javascript(script, cancellable, callback) diff --git a/src/core/widgets/webkit_ui.py b/src/core/widgets/webkit_ui.py deleted file mode 100644 index 6b1f4ee..0000000 --- a/src/core/widgets/webkit_ui.py +++ /dev/null @@ -1,67 +0,0 @@ -# Python imports - -# Lib imports -import gi -gi.require_version('Gdk', '3.0') -gi.require_version('WebKit2', '4.0') -from gi.repository import Gdk -from gi.repository import WebKit2 - -# Application imports -from libs.settings_manager.other.webkit_ui_settings import WebkitUISettings - - -class WebkitUI(WebKit2.WebView): - def __init__(self): - super(WebkitUI, self).__init__() - - self._setup_styling() - self._subscribe_to_events() - self._load_view() - self._setup_content_manager() - - self.show_all() - - - def _setup_styling(self): - self.set_vexpand(True) - self.set_hexpand(True) - self.set_background_color( Gdk.RGBA(0, 0, 0, 0.0) ) - - def _subscribe_to_events(self): - event_system.subscribe(f"ui_message", self.ui_message) - - def _load_settings(self): - self.set_settings( WebkitUISettings() ) - - def _load_view(self): - path = settings_manager.get_context_path() - data = None - - with open(f"{path}/index.html", "r") as f: - data = f.read() - - self.load_html(content = data, base_uri = f"file://{path}/") - - def _setup_content_manager(self): - content_manager = self.get_user_content_manager() - content_manager.connect("script-message-received", self._process_js_message) - content_manager.register_script_message_handler("backend") - - def _process_js_message(self, user_content_manager, js_result): - js_value = js_result.get_js_value() - message = js_value.to_string() - - try: - event = Event( **json.loads(message) ) - event_system.emit("handle_bridge_event", (event,)) - except Exception as e: - logger.info(e) - - def ui_message(self, message, mtype): - command = f"displayMessage('{message}', '{mtype}', '3')" - self.run_javascript(command, None, None) - - def run_javascript(self, script, cancellable, callback): - logger.debug(script) - super().run_javascript(script, cancellable, callback) diff --git a/src/core/window.py b/src/core/window.py index 7fad7b8..d67e3da 100644 --- a/src/core/window.py +++ b/src/core/window.py @@ -58,8 +58,8 @@ class Window(Gtk.ApplicationWindow): GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self._tear_down) def _subscribe_to_events(self): - event_system.subscribe("tear_down", self._tear_down) - event_system.subscribe("load_interactive_debug", self._load_interactive_debug) + event_system.subscribe("tear-down", self._tear_down) + event_system.subscribe("load-interactive-debug", self._load_interactive_debug) def _load_widgets(self, args, unknownargs): if settings_manager.is_debug(): @@ -107,17 +107,17 @@ class Window(Gtk.ApplicationWindow): def _on_focus_in_event(self, widget, event): - event_system.emit("pause_dnd_signals") + event_system.emit("pause-dnd-signals") def _on_focus_out_event(self, widget, event): - event_system.emit("listen_dnd_signals") + event_system.emit("listen-dnd-signals") def _load_interactive_debug(self): self.set_interactive_debugging(True) def _tear_down(self, widget = None, eve = None): - event_system.emit("shutting_down") + event_system.emit("shutting-down") size = self.get_size() pos = self.get_position() @@ -132,4 +132,4 @@ class Window(Gtk.ApplicationWindow): Gtk.main_quit() def main(self): - Gtk.main() \ No newline at end of file + Gtk.main() diff --git a/src/libs/data_types/__init__.py b/src/libs/dto/__init__.py similarity index 100% rename from src/libs/data_types/__init__.py rename to src/libs/dto/__init__.py diff --git a/src/libs/data_types/event.py b/src/libs/dto/event.py similarity index 100% rename from src/libs/data_types/event.py rename to src/libs/dto/event.py diff --git a/src/libs/ipc_server.py b/src/libs/ipc_server.py index a351b66..e72f989 100644 --- a/src/libs/ipc_server.py +++ b/src/libs/ipc_server.py @@ -35,7 +35,7 @@ class IPCServer(Singleton): self._subscribe_to_events() def _subscribe_to_events(self): - event_system.subscribe("post_file_to_ipc", self.send_ipc_message) + event_system.subscribe("post-file-to-ipc", self.send_ipc_message) def create_ipc_listener(self) -> None: @@ -74,12 +74,12 @@ class IPCServer(Singleton): if "FILE|" in msg: file = msg.split("FILE|")[1].strip() if file: - event_system.emit("handle_file_from_ipc", file) + event_system.emit("handle-file-from-ipc", file) if "DIR|" in msg: file = msg.split("DIR|")[1].strip() if file: - event_system.emit("handle_dir_from_ipc", file) + event_system.emit("handle-dir-from-ipc", file) conn.close() break diff --git a/src/libs/mixins/dnd_mixin.py b/src/libs/mixins/dnd_mixin.py index e4c9eed..4e231d3 100644 --- a/src/libs/mixins/dnd_mixin.py +++ b/src/libs/mixins/dnd_mixin.py @@ -67,4 +67,4 @@ class DnDMixin: files.append(gfile) - event_system.emit('set_pre_drop_dnd', (files,)) \ No newline at end of file + event_system.emit('set-pre-drop-dnd', (files,)) \ No newline at end of file diff --git a/src/libs/settings_manager/__init__.py b/src/libs/settings/__init__.py similarity index 100% rename from src/libs/settings_manager/__init__.py rename to src/libs/settings/__init__.py diff --git a/src/libs/settings_manager/manager.py b/src/libs/settings/manager.py similarity index 100% rename from src/libs/settings_manager/manager.py rename to src/libs/settings/manager.py diff --git a/src/libs/settings_manager/options/__init__.py b/src/libs/settings/options/__init__.py similarity index 100% rename from src/libs/settings_manager/options/__init__.py rename to src/libs/settings/options/__init__.py diff --git a/src/libs/settings_manager/options/config.py b/src/libs/settings/options/config.py similarity index 100% rename from src/libs/settings_manager/options/config.py rename to src/libs/settings/options/config.py diff --git a/src/libs/settings_manager/options/debugging.py b/src/libs/settings/options/debugging.py similarity index 100% rename from src/libs/settings_manager/options/debugging.py rename to src/libs/settings/options/debugging.py diff --git a/src/libs/settings_manager/options/filters.py b/src/libs/settings/options/filters.py similarity index 100% rename from src/libs/settings_manager/options/filters.py rename to src/libs/settings/options/filters.py diff --git a/src/libs/settings_manager/options/settings.py b/src/libs/settings/options/settings.py similarity index 100% rename from src/libs/settings_manager/options/settings.py rename to src/libs/settings/options/settings.py diff --git a/src/libs/settings_manager/options/theming.py b/src/libs/settings/options/theming.py similarity index 100% rename from src/libs/settings_manager/options/theming.py rename to src/libs/settings/options/theming.py diff --git a/src/libs/settings_manager/other/__init__.py b/src/libs/settings/other/__init__.py similarity index 100% rename from src/libs/settings_manager/other/__init__.py rename to src/libs/settings/other/__init__.py diff --git a/src/libs/settings_manager/other/webkit_ui_settings.py b/src/libs/settings/other/webkit_ui_settings.py similarity index 100% rename from src/libs/settings_manager/other/webkit_ui_settings.py rename to src/libs/settings/other/webkit_ui_settings.py diff --git a/src/libs/settings_manager/start_check_mixin.py b/src/libs/settings/start_check_mixin.py similarity index 100% rename from src/libs/settings_manager/start_check_mixin.py rename to src/libs/settings/start_check_mixin.py diff --git a/user_config/usr/share/app_name/key-bindings.json b/user_config/usr/share/app_name/key-bindings.json index 52a4f6d..8eb8187 100644 --- a/user_config/usr/share/app_name/key-bindings.json +++ b/user_config/usr/share/app_name/key-bindings.json @@ -1,24 +1,24 @@ { "keybindings": { "help" : "F1", - "rename_files" : ["F2", "e"], - "open_terminal" : "F4", - "refresh_tab" : ["F5", "r"], - "delete_files" : "Delete", - "tggl_top_main_menubar" : "Alt_L", - "tggl_top_main_menubar" : "0", - "trash_files" : "t", - "tear_down" : "q", - "go_up" : "Up", - "go_home" : "slash", - "grab_focus_path_entry" : "l", - "open_files" : "o", - "show_hide_hidden_files" : "h", - "keyboard_create_tab" : "t", - "keyboard_close_tab" : "w", - "keyboard_copy_files" : "c", - "keyboard_cut_files" : "x", - "paste_files" : "v", - "show_new_file_menu" : "n" + "rename-files" : ["F2", "e"], + "open-terminal" : "F4", + "refresh-tab" : ["F5", "r"], + "delete-files" : "Delete", + "tggl-top-main-menubar" : "Alt_L", + "tggl-top-main-menubar" : "0", + "trash-files" : "t", + "tear-down" : "q", + "go-up" : "Up", + "go-home" : "slash", + "grab-focus-path-entry" : "l", + "open-files" : "o", + "show-hide-hidden-files" : "h", + "keyboard-create-tab" : "t", + "keyboard-close-tab" : "w", + "keyboard-copy-files" : "c", + "keyboard-cut-files" : "x", + "paste-files" : "v", + "show-new-file-menu" : "n" } } From a0f32a7c007be89acfb202b07502d7c57802ba9f Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Thu, 29 Feb 2024 18:50:34 -0600 Subject: [PATCH 08/27] app_name --> APP_NAME --- src/__builtins__.py | 2 +- src/__main__.py | 2 +- src/app.py | 2 +- src/core/window.py | 2 +- src/libs/ipc_server.py | 6 ++--- src/libs/settings/manager.py | 22 +++++++++---------- src/libs/settings/other/webkit_ui_settings.py | 2 +- src/libs/settings/start_check_mixin.py | 4 ++-- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/__builtins__.py b/src/__builtins__.py index 770a5a3..37abfc6 100644 --- a/src/__builtins__.py +++ b/src/__builtins__.py @@ -35,7 +35,7 @@ def daemon_threaded_wrapper(fn): # NOTE: Just reminding myself we can add to builtins two different ways... # __builtins__.update({"event_system": Builtins()}) -builtins.app_name = "" +builtins.APP_NAME = "" builtins.keybindings = Keybindings() builtins.event_system = EventSystem() diff --git a/src/__main__.py b/src/__main__.py index f5121f8..21ed66f 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -18,7 +18,7 @@ from app import Application def main(args, unknownargs): - setproctitle(f'{app_name}') + setproctitle(f'{APP_NAME}') if args.debug == "true": settings_manager.set_debug(True) diff --git a/src/app.py b/src/app.py index b945b22..3fd5717 100644 --- a/src/app.py +++ b/src/app.py @@ -39,7 +39,7 @@ class Application: message = f"FILE|{arg}" ipc_server.send_ipc_message(message) - raise AppLaunchException(f"{app_name} IPC Server Exists: Have sent path(s) to it and closing...") + raise AppLaunchException(f"{APP_NAME} IPC Server Exists: Have sent path(s) to it and closing...") def ipc_realization_check(self, ipc_server): try: diff --git a/src/core/window.py b/src/core/window.py index d67e3da..3f73174 100644 --- a/src/core/window.py +++ b/src/core/window.py @@ -41,7 +41,7 @@ class Window(Gtk.ApplicationWindow): def _setup_styling(self): - self.set_title(f"{app_name}") + self.set_title(f"{APP_NAME}") self.set_icon_from_file( settings_manager.get_window_icon() ) self.set_gravity(5) # 5 = CENTER self.set_position(1) # 1 = CENTER, 4 = CENTER_ALWAYS diff --git a/src/libs/ipc_server.py b/src/libs/ipc_server.py index e72f989..a6052c4 100644 --- a/src/libs/ipc_server.py +++ b/src/libs/ipc_server.py @@ -13,17 +13,17 @@ from .singleton import Singleton class IPCServer(Singleton): - """ Create a listener so that other {app_name} instances send requests back to existing instance. """ + """ Create a listener so that other {APP_NAME} instances send requests back to existing instance. """ def __init__(self, ipc_address: str = '127.0.0.1', conn_type: str = "socket"): self.is_ipc_alive = False self._ipc_port = 4848 self._ipc_address = ipc_address self._conn_type = conn_type - self._ipc_authkey = b'' + bytes(f'{app_name}-ipc', 'utf-8') + self._ipc_authkey = b'' + bytes(f'{APP_NAME}-ipc', 'utf-8') self._ipc_timeout = 15.0 if conn_type == "socket": - self._ipc_address = f'/tmp/{app_name}-ipc.sock' + self._ipc_address = f'/tmp/{APP_NAME}-ipc.sock' elif conn_type == "full_network": self._ipc_address = '0.0.0.0' elif conn_type == "full_network_unsecured": diff --git a/src/libs/settings/manager.py b/src/libs/settings/manager.py index da1b183..cb465bc 100644 --- a/src/libs/settings/manager.py +++ b/src/libs/settings/manager.py @@ -24,8 +24,8 @@ class SettingsManager(StartCheckMixin, Singleton): def __init__(self): self._SCRIPT_PTH = path.dirname(path.realpath(__file__)) self._USER_HOME = path.expanduser('~') - self._HOME_CONFIG_PATH = f"{self._USER_HOME}/.config/{app_name.lower()}" - self._USR_PATH = f"/usr/share/{app_name.lower()}" + self._HOME_CONFIG_PATH = f"{self._USER_HOME}/.config/{APP_NAME.lower()}" + self._USR_PATH = f"/usr/share/{APP_NAME.lower()}" self._USR_CONFIG_FILE = f"{self._USR_PATH}/settings.json" self._CONTEXT_PATH = f"{self._HOME_CONFIG_PATH}/context_path" @@ -35,10 +35,10 @@ class SettingsManager(StartCheckMixin, Singleton): self._GLADE_FILE = f"{self._HOME_CONFIG_PATH}/Main_Window.glade" self._CSS_FILE = f"{self._HOME_CONFIG_PATH}/stylesheet.css" self._KEY_BINDINGS_FILE = f"{self._HOME_CONFIG_PATH}/key-bindings.json" - self._PID_FILE = f"{self._HOME_CONFIG_PATH}/{app_name.lower()}.pid" + self._PID_FILE = f"{self._HOME_CONFIG_PATH}/{APP_NAME.lower()}.pid" self._UI_WIDEGTS_PATH = f"{self._HOME_CONFIG_PATH}/ui_widgets" self._CONTEXT_MENU = f"{self._HOME_CONFIG_PATH}/contexct_menu.json" - self._WINDOW_ICON = f"{self._DEFAULT_ICONS}/{app_name.lower()}.png" + self._WINDOW_ICON = f"{self._DEFAULT_ICONS}/{APP_NAME.lower()}.png" # self._USR_CONFIG_FILE = f"{self._USR_PATH}/settings.json" # self._PLUGINS_PATH = f"plugins" @@ -46,8 +46,8 @@ class SettingsManager(StartCheckMixin, Singleton): # self._GLADE_FILE = f"Main_Window.glade" # self._CSS_FILE = f"stylesheet.css" # self._KEY_BINDINGS_FILE = f"key-bindings.json" - # self._PID_FILE = f"{app_name.lower()}.pid" - # self._WINDOW_ICON = f"{app_name.lower()}.png" + # self._PID_FILE = f"{APP_NAME.lower()}.pid" + # self._WINDOW_ICON = f"{APP_NAME.lower()}.png" # self._UI_WIDEGTS_PATH = f"ui_widgets" # self._CONTEXT_MENU = f"contexct_menu.json" # self._DEFAULT_ICONS = f"icons" @@ -79,7 +79,7 @@ class SettingsManager(StartCheckMixin, Singleton): if not path.exists(self._CSS_FILE): raise MissingConfigError("Unable to find the application Stylesheet file.") if not path.exists(self._WINDOW_ICON): - self._WINDOW_ICON = f"{self._USR_PATH}/icons/{app_name.lower()}.png" + self._WINDOW_ICON = f"{self._USR_PATH}/icons/{APP_NAME.lower()}.png" if not path.exists(self._WINDOW_ICON): raise MissingConfigError("Unable to find the application icon.") if not path.exists(self._UI_WIDEGTS_PATH): @@ -164,10 +164,10 @@ class SettingsManager(StartCheckMixin, Singleton): method = getattr(target_class, method_name, lambda data: f"No valid key passed...\nkey={method_name}\nargs={data}") return method(data) if data else method() - def set_main_window_x(self, x = 0): self.settings.config.main_window_x = x - def set_main_window_y(self, y = 0): self.settings.config.main_window_y = y - def set_main_window_width(self, width = 800): self.settings.config.main_window_width = width - def set_main_window_height(self, height = 600): self.settings.config.main_window_height = height + def set_main_window_x(self, x = 0): self.settings.config.main_window_x = x + def set_main_window_y(self, y = 0): self.settings.config.main_window_y = y + def set_main_window_width(self, width = 800): self.settings.config.main_window_width = width + def set_main_window_height(self, height = 600): self.settings.config.main_window_height = height def set_main_window_min_width(self, width = 720): self.settings.config.main_window_min_width = width def set_main_window_min_height(self, height = 480): self.settings.config.main_window_min_height = height def set_starting_files(self, files: []) -> None: self._starting_files = files diff --git a/src/libs/settings/other/webkit_ui_settings.py b/src/libs/settings/other/webkit_ui_settings.py index 962fe60..981ea49 100644 --- a/src/libs/settings/other/webkit_ui_settings.py +++ b/src/libs/settings/other/webkit_ui_settings.py @@ -39,4 +39,4 @@ class WebkitUISettings(WebKit2.Settings): self.set_enable_webaudio(True) self.set_enable_accelerated_2d_canvas(True) - self.set_user_agent(f"{app_name}") \ No newline at end of file + self.set_user_agent(f"{APP_NAME}") \ No newline at end of file diff --git a/src/libs/settings/start_check_mixin.py b/src/libs/settings/start_check_mixin.py index 6fc8208..b47d9bd 100644 --- a/src/libs/settings/start_check_mixin.py +++ b/src/libs/settings/start_check_mixin.py @@ -41,7 +41,7 @@ class StartCheckMixin: try: os.kill(pid, 0) except OSError: - print(f"{app_name} PID file exists but PID is irrelevant; starting dirty...") + print(f"{APP_NAME} PID file exists but PID is irrelevant; starting dirty...") self._dirty_start = True return False @@ -53,7 +53,7 @@ class StartCheckMixin: self._print_pid(pid) def _print_pid(self, pid): - print(f"{app_name} PID: {pid}") + print(f"{APP_NAME} PID: {pid}") def _clean_pid(self): os.unlink(self._PID_FILE) From bdb9c157f7d4019bd859071ca0cf4733b15c5f72 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sat, 16 Mar 2024 22:36:04 -0500 Subject: [PATCH 09/27] moved controls to dir; added open files button example; css transparency changes --- src/core/containers/header_container.py | 10 ++- src/core/widgets/controls/__init__.py | 3 + .../widgets/controls/open_files_button.py | 86 +++++++++++++++++++ .../{ => controls}/transparency_scale.py | 2 +- user_config/usr/share/app_name/stylesheet.css | 14 +++ 5 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 src/core/widgets/controls/__init__.py create mode 100644 src/core/widgets/controls/open_files_button.py rename src/core/widgets/{ => controls}/transparency_scale.py (93%) diff --git a/src/core/containers/header_container.py b/src/core/containers/header_container.py index 7ed41a3..695c2cf 100644 --- a/src/core/containers/header_container.py +++ b/src/core/containers/header_container.py @@ -6,7 +6,8 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports -from ..widgets.transparency_scale import TransparencyScale +from ..widgets.controls.open_files_button import OpenFilesButton +from ..widgets.controls.transparency_scale import TransparencyScale @@ -36,14 +37,15 @@ class HeaderContainer(Gtk.Box): def _load_widgets(self): - button = Gtk.Button(label = "Interactive Debug") + button = Gtk.Button(label = "Interactive Debug") button.connect("clicked", self._interactive_debug) - self.add(TransparencyScale()) + self.add( OpenFilesButton() ) + self.add( TransparencyScale() ) self.add(button) def _interactive_debug(self, widget = None, eve = None): event_system.emit("load-interactive-debug") def tggl_top_main_menubar(self): - self.hide() if self.is_visible() else self.show() + self.hide() if self.is_visible() else self.show() \ No newline at end of file diff --git a/src/core/widgets/controls/__init__.py b/src/core/widgets/controls/__init__.py new file mode 100644 index 0000000..f53f627 --- /dev/null +++ b/src/core/widgets/controls/__init__.py @@ -0,0 +1,3 @@ +""" + Widgets.Controls Module +""" diff --git a/src/core/widgets/controls/open_files_button.py b/src/core/widgets/controls/open_files_button.py new file mode 100644 index 0000000..06e6a9f --- /dev/null +++ b/src/core/widgets/controls/open_files_button.py @@ -0,0 +1,86 @@ +# Python imports +import os + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import Gio + +# Application imports + + + +class OpenFilesButton(Gtk.Button): + """docstring for OpenFilesButton.""" + + def __init__(self): + super(OpenFilesButton, self).__init__() + + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + + def _setup_styling(self): + self.set_label("Open File(s)...") + self.set_image( Gtk.Image.new_from_icon_name("gtk-open", 4) ) + self.set_always_show_image(True) + self.set_image_position(1) # Left - 0, Right = 1 + self.set_hexpand(False) + + def _setup_signals(self): + self.connect("button-release-event", self._open_files) + + def _subscribe_to_events(self): + event_system.subscribe("open_files", self._open_files) + + def _load_widgets(self): + ... + + def _open_files(self, widget = None, eve = None, gfile = None): + start_dir = None + _gfiles = [] + + if gfile and gfile.query_exists(): + start_dir = gfile.get_parent() + + chooser = Gtk.FileChooserDialog("Open File(s)...", None, + Gtk.FileChooserAction.OPEN, + ( + Gtk.STOCK_CANCEL, + Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, + Gtk.ResponseType.OK + ) + ) + + chooser.set_select_multiple(True) + + try: + folder = widget.get_current_file().get_parent() if not start_dir else start_dir + chooser.set_current_folder( folder.get_path() ) + except Exception as e: + ... + + response = chooser.run() + if not response == Gtk.ResponseType.OK: + chooser.destroy() + return _gfiles + + filenames = chooser.get_filenames() + if not filenames: + chooser.destroy() + return _gfiles + + for file in filenames: + path = file if os.path.isabs(file) else os.path.abspath(file) + _gfiles.append( Gio.File.new_for_path(path) ) + + chooser.destroy() + + logger.debug(_gfiles) + return _gfiles \ No newline at end of file diff --git a/src/core/widgets/transparency_scale.py b/src/core/widgets/controls/transparency_scale.py similarity index 93% rename from src/core/widgets/transparency_scale.py rename to src/core/widgets/controls/transparency_scale.py index 02c11e4..223b59a 100644 --- a/src/core/widgets/transparency_scale.py +++ b/src/core/widgets/controls/transparency_scale.py @@ -37,7 +37,7 @@ class TransparencyScale(Gtk.Scale): def _load_widgets(self): adjust = self.get_adjustment() adjust.set_lower(0) - adjust.set_upper(99) + adjust.set_upper(100) adjust.set_value(settings.theming.transparency) adjust.set_step_increment(1.0) diff --git a/user_config/usr/share/app_name/stylesheet.css b/user_config/usr/share/app_name/stylesheet.css index ce012b1..db9ed2c 100644 --- a/user_config/usr/share/app_name/stylesheet.css +++ b/user_config/usr/share/app_name/stylesheet.css @@ -1,3 +1,16 @@ +/* ---- Make most desired things base transparent ---- */ +popover, +popover > *, +scrolledwindow > *, +textview > *, +.main-window > .base-container > .body-container, +.main-window > .base-container > .body-container > .left-container, +.main-window > .base-container > .body-container > .center-container, +.main-window > .base-container > .body-container > .right-container { + background: rgba(0, 0, 0, 0.0); + color: rgba(255, 255, 255, 1); +} + .base-container { margin: 10px; } @@ -128,3 +141,4 @@ XfdesktopIconView.view:active { .mw_transparency_97 { background: rgba(39, 43, 52, 0.97); } .mw_transparency_98 { background: rgba(39, 43, 52, 0.98); } .mw_transparency_99 { background: rgba(39, 43, 52, 0.99); } +.mw_transparency_100 { background: rgba(39, 43, 52, 1.00); } \ No newline at end of file From b78fac0aa5f06061272417b6259d9edfa8097877 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Mon, 25 Mar 2024 22:48:05 -0500 Subject: [PATCH 10/27] Fixed depricated exception type; fixed siguser type --- src/app.py | 2 +- src/libs/debugging.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app.py b/src/app.py index 3fd5717..02bf996 100644 --- a/src/app.py +++ b/src/app.py @@ -56,7 +56,7 @@ class Application: try: # kill -SIGUSR2 from Linux/Unix or SIGBREAK signal from Windows signal.signal( - vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR1"), + vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR2"), debug_signal_handler ) except ValueError: diff --git a/src/libs/debugging.py b/src/libs/debugging.py index b84193a..70cdf82 100644 --- a/src/libs/debugging.py +++ b/src/libs/debugging.py @@ -18,7 +18,7 @@ def debug_signal_handler(signal, frame): rpdb2.start_embedded_debugger("foobar", True, True) rpdb2.setbreak(depth=1) return - except StandardError: + except Exception: ... try: @@ -26,7 +26,7 @@ def debug_signal_handler(signal, frame): logger.debug("\n\nStarting embedded rconsole debugger...\n\n") rconsole.spawn_server() return - except StandardError as ex: + except Exception as ex: ... try: @@ -34,7 +34,7 @@ def debug_signal_handler(signal, frame): logger.debug("\n\nStarting PuDB debugger...\n\n") set_trace(paused = True) return - except StandardError as ex: + except Exception as ex: ... try: @@ -42,11 +42,11 @@ def debug_signal_handler(signal, frame): logger.debug("\n\nStarting embedded PDB debugger...\n\n") pdb.Pdb(skip=['gi.*']).set_trace() return - except StandardError as ex: + except Exception as ex: ... try: import code code.interact() - except StandardError as ex: - logger.debug(f"{ex}, returning to normal program flow...") + except Exception as ex: + logger.debug(f"{ex}, returning to normal program flow...") \ No newline at end of file From 48bac7e791389a4e6eb2c39d5e62633309ea52c6 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Fri, 3 May 2024 01:08:49 -0500 Subject: [PATCH 11/27] Added a requirement; added a debug handler --- README.md | 1 + requirements.txt | 3 ++- src/core/window.py | 4 ++-- src/libs/debugging.py | 8 ++++++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cb2c302..0ae0e44 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ A template project for Python with Gtk applications. ### Requirements * PyGObject (Gtk introspection library) +* pygobject-stubs (For actually getting pylsp or python-language-server to auto complete in LSPs. Do if GTK3 --no-cache-dir --config-settings=config=Gtk3,Gdk3,Soup2) * pyxdg (Desktop ".desktop" file parser) * setproctitle (Define process title to search and kill more easily) * sqlmodel (SQL databases and is powered by Pydantic and SQLAlchemy) diff --git a/requirements.txt b/requirements.txt index 4f65d82..7de6c98 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ PyGObject +pygobject-stubs pyxdg setproctitle -sqlmodel +sqlmodel \ No newline at end of file diff --git a/src/core/window.py b/src/core/window.py index 3f73174..a6dac07 100644 --- a/src/core/window.py +++ b/src/core/window.py @@ -90,7 +90,7 @@ class Window(Gtk.ApplicationWindow): if visual and screen.is_composited() and settings.config.make_transparent == 0: self.set_visual(visual) self.set_app_paintable(True) - self.connect("draw", self._area_draw) + # self.connect("draw", self._area_draw) # bind css file cssProvider = Gtk.CssProvider() @@ -132,4 +132,4 @@ class Window(Gtk.ApplicationWindow): Gtk.main_quit() def main(self): - Gtk.main() + Gtk.main() \ No newline at end of file diff --git a/src/libs/debugging.py b/src/libs/debugging.py index 70cdf82..5eaa286 100644 --- a/src/libs/debugging.py +++ b/src/libs/debugging.py @@ -37,6 +37,14 @@ def debug_signal_handler(signal, frame): except Exception as ex: ... + try: + import ipdb + logger.debug("\n\nStarting IPDB debugger...\n\n") + ipdb.set_trace() + return + except Exception as ex: + ... + try: import pdb logger.debug("\n\nStarting embedded PDB debugger...\n\n") From e82e4fb1eb1dc66a1d22bf61636af632560fda1b Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Fri, 3 May 2024 01:11:52 -0500 Subject: [PATCH 12/27] Updated a requirement --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7de6c98..feb761b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ PyGObject -pygobject-stubs +pygobject-stubs --no-cache-dir --config-settings=config=Gtk3,Gdk3,Soup2 pyxdg setproctitle sqlmodel \ No newline at end of file From cc5966dab27a67f61b910f1273b307da31e0f10b Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Mon, 6 May 2024 19:11:18 -0500 Subject: [PATCH 13/27] Added status icon for system trays --- src/core/widgets/webkit/webkit_ui.py | 1 - src/core/window.py | 7 ++- src/libs/status_icon.py | 67 ++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 src/libs/status_icon.py diff --git a/src/core/widgets/webkit/webkit_ui.py b/src/core/widgets/webkit/webkit_ui.py index 9b55997..263e491 100644 --- a/src/core/widgets/webkit/webkit_ui.py +++ b/src/core/widgets/webkit/webkit_ui.py @@ -13,7 +13,6 @@ from libs.settings.other.webkit_ui_settings import WebkitUISettings from libs.dto.event import Event - class WebkitUI(WebKit2.WebView): def __init__(self): super(WebkitUI, self).__init__() diff --git a/src/core/window.py b/src/core/window.py index a6dac07..f1f8997 100644 --- a/src/core/window.py +++ b/src/core/window.py @@ -11,6 +11,7 @@ from gi.repository import Gdk from gi.repository import GLib # Application imports +from libs.status_icon import StatusIcon from core.controllers.base_controller import BaseController @@ -27,7 +28,8 @@ class Window(Gtk.ApplicationWindow): super(Window, self).__init__() settings_manager.set_main_window(self) - self._controller = None + self._status_icon = None + self._controller = None self._setup_styling() self._setup_signals() @@ -65,7 +67,8 @@ class Window(Gtk.ApplicationWindow): if settings_manager.is_debug(): self.set_interactive_debugging(True) - self._controller = BaseController(args, unknownargs) + self._controller = BaseController(args, unknownargs) + self._status_icon = StatusIcon() if not self._controller: raise ControllerStartException("BaseController exited and doesn't exist...") diff --git a/src/libs/status_icon.py b/src/libs/status_icon.py new file mode 100644 index 0000000..2769a05 --- /dev/null +++ b/src/libs/status_icon.py @@ -0,0 +1,67 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('AppIndicator3', '0.1') +from gi.repository import Gtk +from gi.repository import GLib +from gi.repository import AppIndicator3 + +# Application imports + + + +class StatusIcon(): + """ StatusIcon for Application to go to Status Tray. """ + + def __init__(self): + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + + def _setup_styling(self): + ... + + def _setup_signals(self): + ... + + def _subscribe_to_events(self): + ... + + def _load_widgets(self): + status_menu = Gtk.Menu() + icon_theme = Gtk.IconTheme.get_default() + check_menu_item = Gtk.CheckMenuItem.new_with_label("Update icon") + quit_menu_item = Gtk.MenuItem.new_with_label("Quit") + + # Create StatusNotifierItem + self.indicator = AppIndicator3.Indicator.new( + f"{APP_NAME}-statusicon", + "gtk-info", + AppIndicator3.IndicatorCategory.APPLICATION_STATUS) + self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE) + + check_menu_item.connect("activate", self.check_menu_item_cb) + quit_menu_item.connect("activate", self.quit_menu_item_cb) + icon_theme.connect('changed', self.icon_theme_changed_cb) + + self.indicator.set_menu(status_menu) + status_menu.append(check_menu_item) + status_menu.append(quit_menu_item) + status_menu.show_all() + + def update_icon(self, icon_name): + self.indicator.set_icon(icon_name) + + def check_menu_item_cb(self, widget, data = None): + icon_name = "parole" if widget.get_active() else "gtk-info" + self.update_icon(icon_name) + + def icon_theme_changed_cb(self, theme): + self.update_icon("gtk-info") + + def quit_menu_item_cb(self, widget, data = None): + event_system.emit("tear-down") From 62debf9ece02fb93356ea8d84173a375f7fe5565 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sat, 29 Jun 2024 21:24:57 -0500 Subject: [PATCH 14/27] extending plugins to load pre or post app start --- plugins/README.txt | 31 +++++++++- requirements.txt | 10 +-- src/core/controllers/base_controller.py | 5 +- src/core/controllers/base_controller_data.py | 19 +++--- src/core/window.py | 2 +- src/libs/settings/manager.py | 2 +- src/plugins/manifest.py | 31 +++++----- src/plugins/plugins_controller.py | 57 +++++++++++++++--- ...p_name-64x64.png => -64x64.png} | Bin .../icons/{app_name.png => .png} | Bin 10 files changed, 117 insertions(+), 40 deletions(-) rename user_config/usr/share/app_name/icons/{app_name-64x64.png => -64x64.png} (100%) rename user_config/usr/share/app_name/icons/{app_name.png => .png} (100%) diff --git a/plugins/README.txt b/plugins/README.txt index 4173ddd..dfbb0f9 100644 --- a/plugins/README.txt +++ b/plugins/README.txt @@ -1,2 +1,31 @@ ### Note -Copy the example and rename it to your desired name. The Main class and passed in arguments are required. You don't necessarily need to use the passed in socket_id or event_system. +Copy the example and rename it to your desired name. Plugins define a ui target slot with the 'ui_target' requests data but don't have to if not directly interacted with. +Plugins must have a run method defined; though, you do not need to necessarily do anything within it. The run method implies that the passed in event system or other data is ready for the plugin to use. + + +### Manifest Example (All are required even if empty.) +``` +class Manifest: + name: str = "Example Plugin" + author: str = "John Doe" + version: str = "0.0.1" + support: str = "" + requests: {} = { + 'pass_ui_objects': ["plugin_control_list"], + 'pass_events': "true", + 'bind_keys': [] + } + pre_launch: bool = False +``` + + +### Requests +``` +requests: {} = { + 'pass_events': "true", # If empty or not present will be ignored. + "pass_ui_objects": [""], # Request reference to a UI component. Will be passed back as array to plugin. + 'bind_keys': [f"{name}||send_message:f"], + f"{name}||do_save:s"] # Bind keys with method and key pare using list. Must pass "name" like shown with delimiter to its right. + +} +``` diff --git a/requirements.txt b/requirements.txt index feb761b..bfb1be3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ -PyGObject +PyGObject==3.40.1 pygobject-stubs --no-cache-dir --config-settings=config=Gtk3,Gdk3,Soup2 -pyxdg -setproctitle -sqlmodel \ No newline at end of file +setproctitle==1.2.2 +pyxdg==0.27 +psutil==5.8.0 +pycryptodome==3.20.0 +sqlmodel==0.0.19 \ No newline at end of file diff --git a/src/core/controllers/base_controller.py b/src/core/controllers/base_controller.py index 8ccd90c..9da61d9 100644 --- a/src/core/controllers/base_controller.py +++ b/src/core/controllers/base_controller.py @@ -28,7 +28,10 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): self._load_controllers() if args.no_plugins == "false": - self.plugins.launch_plugins() + self.plugins_controller.pre_launch_plugins() + + if args.no_plugins == "false": + self.plugins_controller.post_launch_plugins() for file in settings_manager.get_starting_files(): event_system.emit("post-file-to-ipc", file) diff --git a/src/core/controllers/base_controller_data.py b/src/core/controllers/base_controller_data.py index 23f7461..4581209 100644 --- a/src/core/controllers/base_controller_data.py +++ b/src/core/controllers/base_controller_data.py @@ -15,17 +15,18 @@ class BaseControllerData: ''' BaseControllerData contains most of the state of the app at ay given time. It also has some support methods. ''' def setup_controller_data(self) -> None: - self.window = settings_manager.get_main_window() - self.builder = BuilderWrapper() + self.window = settings_manager.get_main_window() + self.builder = BuilderWrapper() + self.plugins_controller = PluginsController() - self.base_container = None - self.was_midified_key = False - self.ctrl_down = False - self.shift_down = False - self.alt_down = False + self.base_container = None + self.was_midified_key = False + self.ctrl_down = False + self.shift_down = False + self.alt_down = False self._load_glade_file() - self.plugins = PluginsController() + def collect_files_dirs(self, args, unknownargs): files = [] @@ -96,4 +97,4 @@ class BaseControllerData: proc = subprocess.Popen(command, stdin = subprocess.PIPE) proc.stdin.write(data.encode(encoding)) proc.stdin.close() - retcode = proc.wait() \ No newline at end of file + retcode = proc.wait() diff --git a/src/core/window.py b/src/core/window.py index f1f8997..1b09fb4 100644 --- a/src/core/window.py +++ b/src/core/window.py @@ -135,4 +135,4 @@ class Window(Gtk.ApplicationWindow): Gtk.main_quit() def main(self): - Gtk.main() \ No newline at end of file + Gtk.main() diff --git a/src/libs/settings/manager.py b/src/libs/settings/manager.py index cb465bc..ab449da 100644 --- a/src/libs/settings/manager.py +++ b/src/libs/settings/manager.py @@ -193,4 +193,4 @@ class SettingsManager(StartCheckMixin, Singleton): def save_settings(self): with open(self._CONFIG_FILE, 'w') as outfile: - json.dump(self.settings.as_dict(), outfile, separators=(',', ':'), indent=4) \ No newline at end of file + json.dump(self.settings.as_dict(), outfile, separators=(',', ':'), indent=4) diff --git a/src/plugins/manifest.py b/src/plugins/manifest.py index 1b93f34..b2320f5 100644 --- a/src/plugins/manifest.py +++ b/src/plugins/manifest.py @@ -15,13 +15,14 @@ class ManifestProcessor(Exception): class Plugin: - path: str = None - name: str = None - author: str = None - version: str = None - support: str = None - requests:{} = None - reference: type = None + path: str = None + name: str = None + author: str = None + version: str = None + support: str = None + requests:{} = None + reference: type = None + pre_launch: bool = False class ManifestProcessor: @@ -46,23 +47,25 @@ class ManifestProcessor: plugin.support = self._manifest["support"] plugin.requests = self._manifest["requests"] + if "pre_launch" in self._manifest.keys(): + plugin.pre_launch = True if self._manifest["pre_launch"] == "true" else False + return plugin def get_loading_data(self): loading_data = {} requests = self._plugin.requests - keys = requests.keys() - if "pass_events" in keys: + if "pass_events" in requests: if requests["pass_events"] in ["true"]: loading_data["pass_events"] = True - if "bind_keys" in keys: - if isinstance(requests["bind_keys"], list): - loading_data["bind_keys"] = requests["bind_keys"] - - if "pass_ui_objects" in keys: + if "pass_ui_objects" in requests: if isinstance(requests["pass_ui_objects"], list): loading_data["pass_ui_objects"] = [ self._builder.get_object(obj) for obj in requests["pass_ui_objects"] ] + if "bind_keys" in requests: + if isinstance(requests["bind_keys"], list): + loading_data["bind_keys"] = requests["bind_keys"] + return self._plugin, loading_data diff --git a/src/plugins/plugins_controller.py b/src/plugins/plugins_controller.py index a77186c..10d5dc2 100644 --- a/src/plugins/plugins_controller.py +++ b/src/plugins/plugins_controller.py @@ -10,6 +10,7 @@ from os.path import isdir import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk +from gi.repository import GLib from gi.repository import Gio # Application imports @@ -35,11 +36,23 @@ class PluginsController: self._plugins_dir_watcher = None self._plugin_collection = [] + self._plugin_manifests = {} + + self._load_manifests() - def launch_plugins(self) -> None: + def _load_manifests(self): + logger.info(f"Loading manifests...") + + for path, folder in [[join(self._plugins_path, item), item] if os.path.isdir(join(self._plugins_path, item)) else None for item in os.listdir(self._plugins_path)]: + manifest = ManifestProcessor(path, self._builder) + self._plugin_manifests[path] = { + "path": path, + "folder": folder, + "manifest": manifest + } + self._set_plugins_watcher() - self.load_plugins() def _set_plugins_watcher(self) -> None: self._plugins_dir_watcher = Gio.File.new_for_path(self._plugins_path) \ @@ -52,21 +65,47 @@ class PluginsController: Gio.FileMonitorEvent.MOVED_OUT]: self.reload_plugins(file) - def load_plugins(self, file: str = None) -> None: - logger.info(f"Loading plugins...") + def pre_launch_plugins(self) -> None: + logger.info(f"Loading pre-launch plugins...") + plugin_manifests: {} = {} + + for key in self._plugin_manifests: + target_manifest = self._plugin_manifests[key]["manifest"] + if target_manifest.is_pre_launch(): + plugin_manifests[key] = self._plugin_manifests[key] + + self._load_plugins(plugin_manifests, is_pre_launch = True) + + def post_launch_plugins(self) -> None: + logger.info(f"Loading post-launch plugins...") + plugin_manifests: {} = {} + + for key in self._plugin_manifests: + target_manifest = self._plugin_manifests[key]["manifest"] + if not target_manifest.is_pre_launch(): + plugin_manifests[key] = self._plugin_manifests[key] + + self._load_plugins(plugin_manifests) + + def _load_plugins(self, plugin_manifests: {} = {}, is_pre_launch: bool = False) -> None: parent_path = os.getcwd() - for path, folder in [[join(self._plugins_path, item), item] if os.path.isdir(join(self._plugins_path, item)) else None for item in os.listdir(self._plugins_path)]: - try: - target = join(path, "plugin.py") - manifest = ManifestProcessor(path, self._builder) + for key in plugin_manifests: + target_manifest = plugin_manifests[key] + path, folder, manifest = target_manifest["path"], target_manifest["folder"], target_manifest["manifest"] + try: + target = join(path, "plugin.py") if not os.path.exists(target): raise InvalidPluginException("Invalid Plugin Structure: Plugin doesn't have 'plugin.py'. Aboarting load...") plugin, loading_data = manifest.get_loading_data() module = self.load_plugin_module(path, folder, target) - self.execute_plugin(module, plugin, loading_data) + + if is_pre_launch: + self.execute_plugin(module, plugin, loading_data) + else: + GLib.idle_add(self.execute_plugin, *(module, plugin, loading_data)) except Exception as e: logger.info(f"Malformed Plugin: Not loading -->: '{folder}' !") logger.debug("Trace: ", traceback.print_exc()) diff --git a/user_config/usr/share/app_name/icons/app_name-64x64.png b/user_config/usr/share/app_name/icons/-64x64.png similarity index 100% rename from user_config/usr/share/app_name/icons/app_name-64x64.png rename to user_config/usr/share/app_name/icons/-64x64.png diff --git a/user_config/usr/share/app_name/icons/app_name.png b/user_config/usr/share/app_name/icons/.png similarity index 100% rename from user_config/usr/share/app_name/icons/app_name.png rename to user_config/usr/share/app_name/icons/.png From 25b6b5305b71840a3d671f11d31610bbf96063ba Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Fri, 26 Jul 2024 19:53:04 -0500 Subject: [PATCH 15/27] update readme --- README.md | 3 ++- pyrightconfig.json | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 pyrightconfig.json diff --git a/README.md b/README.md index 0ae0e44..6d2b8f3 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ A template project for Python with Gtk applications. * sqlmodel (SQL databases and is powered by Pydantic and SQLAlchemy) ### Note +* pyrightconfig.json can prompt IDEs that use pyright lsp on where imports are located- look at venvPath and venv. "venvPath" is parent path of "venv" where "venv" is just the name of the folder under the parent path that is the python created venv. * Move respetive sub folder content under user_config to the same places in Linux. Though, user/share/ can go to ~/.config folder if prefered. * In additiion, place the plugins folder in the same app folder you moved to /usr/share/ or ~/.config/ . There are a "\" strings and files that need to be set according to your app's name located at: @@ -21,4 +22,4 @@ There are a "\" strings and files that need to be set according to y For the user_config, after changing names and files, copy all content to their respective destinations. -The logic follows Debian Dpkg packaging and its placement logic. \ No newline at end of file +The logic follows Debian Dpkg packaging and its placement logic. diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 0000000..4d8b8ec --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,13 @@ +{ + "reportUndefinedVariable": false, + "reportUnusedVariable": false, + "reportUnusedImport": true, + "reportDuplicateImport": true, + "executionEnvironments": [ + { + "root": "./src/versions/solarfm-0.0.1/solarfm" + } + ], + "venvPath": ".", + "venv": ".venv" +} From e2e9dc8c1f9d266008deae775844b22ec1186d50 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sat, 31 Aug 2024 22:27:11 -0500 Subject: [PATCH 16/27] made default hiding transparency controls easier with restructured show calls --- src/core/containers/base_container.py | 2 +- src/core/containers/body_container.py | 2 +- src/core/containers/center_container.py | 5 +++++ src/core/containers/header_container.py | 2 +- src/core/containers/left_container.py | 4 +++- src/core/containers/right_container.py | 4 +++- 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/core/containers/base_container.py b/src/core/containers/base_container.py index 2dad04a..79ab27e 100644 --- a/src/core/containers/base_container.py +++ b/src/core/containers/base_container.py @@ -22,7 +22,7 @@ class BaseContainer(Gtk.Box): self._subscribe_to_events() self._load_widgets() - self.show_all() + self.show() def _setup_styling(self): diff --git a/src/core/containers/body_container.py b/src/core/containers/body_container.py index e1d94b2..ffe3043 100644 --- a/src/core/containers/body_container.py +++ b/src/core/containers/body_container.py @@ -23,7 +23,7 @@ class BodyContainer(Gtk.Box): self._subscribe_to_events() self._load_widgets() - self.show_all() + self.show() def _setup_styling(self): diff --git a/src/core/containers/center_container.py b/src/core/containers/center_container.py index 887f2f2..ae6858f 100644 --- a/src/core/containers/center_container.py +++ b/src/core/containers/center_container.py @@ -21,6 +21,8 @@ class CenterContainer(Gtk.Box): self._subscribe_to_events() self._load_widgets() + self.show() + def _setup_styling(self): self.set_orientation(Gtk.Orientation.VERTICAL) @@ -39,6 +41,9 @@ class CenterContainer(Gtk.Box): button.connect("clicked", self._hello_world) + button.show() + glade_box.show() + self.add(button) self.add(glade_box) self.add( WebkitUI() ) diff --git a/src/core/containers/header_container.py b/src/core/containers/header_container.py index 695c2cf..6463b1d 100644 --- a/src/core/containers/header_container.py +++ b/src/core/containers/header_container.py @@ -48,4 +48,4 @@ class HeaderContainer(Gtk.Box): event_system.emit("load-interactive-debug") def tggl_top_main_menubar(self): - self.hide() if self.is_visible() else self.show() \ No newline at end of file + self.hide() if self.is_visible() else self.show_all() \ No newline at end of file diff --git a/src/core/containers/left_container.py b/src/core/containers/left_container.py index aa9ec97..4b4e564 100644 --- a/src/core/containers/left_container.py +++ b/src/core/containers/left_container.py @@ -18,6 +18,8 @@ class LeftContainer(Gtk.Box): self._subscribe_to_events() self._load_widgets() + self.show() + def _setup_styling(self): self.set_orientation(Gtk.Orientation.VERTICAL) @@ -31,4 +33,4 @@ class LeftContainer(Gtk.Box): ... def _load_widgets(self): - ... + ... \ No newline at end of file diff --git a/src/core/containers/right_container.py b/src/core/containers/right_container.py index a5869fc..5b61e21 100644 --- a/src/core/containers/right_container.py +++ b/src/core/containers/right_container.py @@ -18,6 +18,8 @@ class RightContainer(Gtk.Box): self._subscribe_to_events() self._load_widgets() + self.show() + def _setup_styling(self): self.set_orientation(Gtk.Orientation.VERTICAL) @@ -31,4 +33,4 @@ class RightContainer(Gtk.Box): ... def _load_widgets(self): - ... + ... \ No newline at end of file From fafc1a985fc1bb54406200d92dc892c5c6f6f03b Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Mon, 14 Oct 2024 21:57:18 -0500 Subject: [PATCH 17/27] Updated __init__ files; theming css changes, other --- src/__init__.py | 4 ++-- src/core/__init__.py | 2 +- src/core/containers/__init__.py | 4 ++-- src/core/controllers/__init__.py | 2 +- src/core/widgets/__init__.py | 4 ++-- src/core/widgets/controls/__init__.py | 4 ++-- src/core/widgets/webkit/__init__.py | 2 +- src/libs/__init__.py | 4 ++-- src/libs/db/__init__.py | 4 ++-- src/libs/dto/__init__.py | 2 +- src/libs/ipc_server.py | 9 ++++++--- src/libs/mixins/__init__.py | 2 +- src/libs/mixins/ipc_signals_mixin.py | 23 +++++++++++++++++------ src/libs/settings/__init__.py | 4 ++-- src/libs/settings/manager.py | 10 +++++----- src/libs/settings/options/__init__.py | 4 ++-- src/libs/settings/other/__init__.py | 4 ++-- src/plugins/manifest.py | 4 ++++ 18 files changed, 55 insertions(+), 37 deletions(-) diff --git a/src/__init__.py b/src/__init__.py index 90dc8da..6de34b8 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,3 +1,3 @@ """ - Start of package. -""" + Src Package. +""" \ No newline at end of file diff --git a/src/core/__init__.py b/src/core/__init__.py index f1af95c..6c4fff7 100644 --- a/src/core/__init__.py +++ b/src/core/__init__.py @@ -1,3 +1,3 @@ """ - Core Module + Core Package """ \ No newline at end of file diff --git a/src/core/containers/__init__.py b/src/core/containers/__init__.py index 4efd4b9..c59e952 100644 --- a/src/core/containers/__init__.py +++ b/src/core/containers/__init__.py @@ -1,3 +1,3 @@ """ - Containers Module -""" + Containers Package +""" \ No newline at end of file diff --git a/src/core/controllers/__init__.py b/src/core/controllers/__init__.py index c004b70..0f53a83 100644 --- a/src/core/controllers/__init__.py +++ b/src/core/controllers/__init__.py @@ -1,3 +1,3 @@ """ - Controllers Module + Controllers Package """ \ No newline at end of file diff --git a/src/core/widgets/__init__.py b/src/core/widgets/__init__.py index 72b072b..a379fc5 100644 --- a/src/core/widgets/__init__.py +++ b/src/core/widgets/__init__.py @@ -1,3 +1,3 @@ """ - Widgets Module -""" + Widgets Package +""" \ No newline at end of file diff --git a/src/core/widgets/controls/__init__.py b/src/core/widgets/controls/__init__.py index f53f627..a82161f 100644 --- a/src/core/widgets/controls/__init__.py +++ b/src/core/widgets/controls/__init__.py @@ -1,3 +1,3 @@ """ - Widgets.Controls Module -""" + Widgets.Controls Package +""" \ No newline at end of file diff --git a/src/core/widgets/webkit/__init__.py b/src/core/widgets/webkit/__init__.py index a0264af..1b77b51 100644 --- a/src/core/widgets/webkit/__init__.py +++ b/src/core/widgets/webkit/__init__.py @@ -1,3 +1,3 @@ """ - WebKit2 UI Module + WebKit2 UI Package """ \ No newline at end of file diff --git a/src/libs/__init__.py b/src/libs/__init__.py index a8e5edd..620f163 100644 --- a/src/libs/__init__.py +++ b/src/libs/__init__.py @@ -1,3 +1,3 @@ """ - Utils module -""" + Libs Package +""" \ No newline at end of file diff --git a/src/libs/db/__init__.py b/src/libs/db/__init__.py index 135071c..d20f589 100644 --- a/src/libs/db/__init__.py +++ b/src/libs/db/__init__.py @@ -1,6 +1,6 @@ """ - DB module + DB Package """ from .models import User -from .db import DB +from .db import DB \ No newline at end of file diff --git a/src/libs/dto/__init__.py b/src/libs/dto/__init__.py index 16675ec..8c55071 100644 --- a/src/libs/dto/__init__.py +++ b/src/libs/dto/__init__.py @@ -1,5 +1,5 @@ """ - Dasta Class module + Dasta Class Package """ from .event import Event \ No newline at end of file diff --git a/src/libs/ipc_server.py b/src/libs/ipc_server.py index a6052c4..ba412d2 100644 --- a/src/libs/ipc_server.py +++ b/src/libs/ipc_server.py @@ -56,7 +56,7 @@ class IPCServer(Singleton): @daemon_threaded def _run_ipc_loop(self, listener) -> None: # NOTE: Not thread safe if using with Gtk. Need to import GLib and use idle_add - while True: + while self.is_ipc_alive: try: conn = listener.accept() start_time = time.perf_counter() @@ -67,7 +67,7 @@ class IPCServer(Singleton): listener.close() def _handle_ipc_message(self, conn, start_time) -> None: - while True: + while self.is_ipc_alive: msg = conn.recv() logger.debug(msg) @@ -76,6 +76,9 @@ class IPCServer(Singleton): if file: event_system.emit("handle-file-from-ipc", file) + conn.close() + break + if "DIR|" in msg: file = msg.split("DIR|")[1].strip() if file: @@ -129,4 +132,4 @@ class IPCServer(Singleton): logger.error("IPC Socket no longer valid.... Removing.") os.unlink(self._ipc_address) except Exception as e: - logger.error( repr(e) ) + logger.error( repr(e) ) \ No newline at end of file diff --git a/src/libs/mixins/__init__.py b/src/libs/mixins/__init__.py index 6eb3b43..e852849 100644 --- a/src/libs/mixins/__init__.py +++ b/src/libs/mixins/__init__.py @@ -1,3 +1,3 @@ """ - Utils/Mixins module + Libs.Mixins Package """ \ No newline at end of file diff --git a/src/libs/mixins/ipc_signals_mixin.py b/src/libs/mixins/ipc_signals_mixin.py index bbabd1e..880266d 100644 --- a/src/libs/mixins/ipc_signals_mixin.py +++ b/src/libs/mixins/ipc_signals_mixin.py @@ -1,6 +1,8 @@ # Python imports # Lib imports +import gi +from gi.repository import GLib # Application imports @@ -8,13 +10,22 @@ class IPCSignalsMixin: - """ IPCSignalsMixin handle messages from another starting solarfm process. """ + """ IPCSignalsMixin handle messages from another starting {APP_NAME} process. """ - def print_to_console(self, message=None): + def print_to_console(self, message = None): logger.debug(message) - def handle_file_from_ipc(self, path: str) -> None: - logger.debug(f"File From IPC: {path}") + def handle_file_from_ipc(self, fpath: str) -> None: + logger.debug(f"File From IPC: {fpath}") + GLib.idle_add( + self.broadcast_message, "handle-file", (fpath,) + ) - def handle_dir_from_ipc(self, path: str) -> None: - logger.debug(f"Dir From IPC: {path}") \ No newline at end of file + def handle_dir_from_ipc(self, fpath: str) -> None: + logger.debug(f"Dir From IPC: {fpath}") + GLib.idle_add( + self.broadcast_message, "handle-folder", (fpath,) + ) + + def broadcast_message(self, message_type: str = "none", data: () = ()) -> None: + event_system.emit(message_type, data) \ No newline at end of file diff --git a/src/libs/settings/__init__.py b/src/libs/settings/__init__.py index a0b3452..228a75d 100644 --- a/src/libs/settings/__init__.py +++ b/src/libs/settings/__init__.py @@ -1,4 +1,4 @@ """ - Settings module + Settings Package """ -from .manager import SettingsManager +from .manager import SettingsManager \ No newline at end of file diff --git a/src/libs/settings/manager.py b/src/libs/settings/manager.py index ab449da..c343b2a 100644 --- a/src/libs/settings/manager.py +++ b/src/libs/settings/manager.py @@ -114,13 +114,13 @@ class SettingsManager(StartCheckMixin, Singleton): self._starting_files = [] - def register_signals_to_builder(self, classes=None): + def register_signals_to_builder(self, classes = None): handlers = {} for c in classes: methods = None try: - methods = inspect.getmembers(c, predicate=inspect.ismethod) + methods = inspect.getmembers(c, predicate = inspect.ismethod) handlers.update(methods) except Exception as e: ... @@ -153,7 +153,7 @@ class SettingsManager(StartCheckMixin, Singleton): def get_home_config_path(self) -> str: return self._HOME_CONFIG_PATH def get_window_icon(self) -> str: return self._WINDOW_ICON def get_home_path(self) -> str: return self._USER_HOME - def get_starting_files(self) -> []: return self._starting_files + def get_starting_files(self) -> list: return self._starting_files def is_trace_debug(self) -> str: return self._trace_debug def is_debug(self) -> str: return self._debug @@ -170,7 +170,7 @@ class SettingsManager(StartCheckMixin, Singleton): def set_main_window_height(self, height = 600): self.settings.config.main_window_height = height def set_main_window_min_width(self, width = 720): self.settings.config.main_window_min_width = width def set_main_window_min_height(self, height = 480): self.settings.config.main_window_min_height = height - def set_starting_files(self, files: []) -> None: self._starting_files = files + def set_starting_files(self, files: list) -> None: self._starting_files = files def set_trace_debug(self, trace_debug): self._trace_debug = trace_debug @@ -178,7 +178,7 @@ class SettingsManager(StartCheckMixin, Singleton): def set_debug(self, debug): self._debug = debug - def set_is_starting_with_file(self, is_passed_in_file: False): + def set_is_starting_with_file(self, is_passed_in_file: bool = False): self._passed_in_file = is_passed_in_file def load_settings(self): diff --git a/src/libs/settings/options/__init__.py b/src/libs/settings/options/__init__.py index 0046efd..e06487a 100644 --- a/src/libs/settings/options/__init__.py +++ b/src/libs/settings/options/__init__.py @@ -1,8 +1,8 @@ """ - Options module + Settings.Options Package """ from .settings import Settings from .config import Config from .filters import Filters from .theming import Theming -from .debugging import Debugging +from .debugging import Debugging \ No newline at end of file diff --git a/src/libs/settings/other/__init__.py b/src/libs/settings/other/__init__.py index e1b5377..c38a726 100644 --- a/src/libs/settings/other/__init__.py +++ b/src/libs/settings/other/__init__.py @@ -1,3 +1,3 @@ """ - Settings Other module -""" + Settings.Other Package +""" \ No newline at end of file diff --git a/src/plugins/manifest.py b/src/plugins/manifest.py index b2320f5..7cb701c 100644 --- a/src/plugins/manifest.py +++ b/src/plugins/manifest.py @@ -69,3 +69,7 @@ class ManifestProcessor: loading_data["bind_keys"] = requests["bind_keys"] return self._plugin, loading_data + + def is_pre_launch(self): + return self._plugin.pre_launch + From f2b33066affa861c22457b526053ef9a62d28822 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sun, 20 Oct 2024 15:06:20 -0500 Subject: [PATCH 18/27] Added stronger typing in settings; logging loading times; css changes to transparency --- src/__main__.py | 1 + src/core/controllers/base_controller.py | 3 +- src/libs/settings/manager.py | 99 ++++++++++--------- .../context_path/resources/css/main.css | 6 +- user_config/usr/share/app_name/stylesheet.css | 16 +-- 5 files changed, 67 insertions(+), 58 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 21ed66f..b854e86 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -19,6 +19,7 @@ from app import Application def main(args, unknownargs): setproctitle(f'{APP_NAME}') + settings_manager.set_start_load_time() if args.debug == "true": settings_manager.set_debug(True) diff --git a/src/core/controllers/base_controller.py b/src/core/controllers/base_controller.py index 9da61d9..7681c6a 100644 --- a/src/core/controllers/base_controller.py +++ b/src/core/controllers/base_controller.py @@ -37,6 +37,8 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): event_system.emit("post-file-to-ipc", file) logger.info(f"Made it past {self.__class__} loading...") + settings_manager.set_end_load_time() + settings_manager.log_load_time() def _setup_styling(self): @@ -67,4 +69,3 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): self.base_container = BaseContainer() settings_manager.register_signals_to_builder([self, self.base_container]) - diff --git a/src/libs/settings/manager.py b/src/libs/settings/manager.py index c343b2a..ed38192 100644 --- a/src/libs/settings/manager.py +++ b/src/libs/settings/manager.py @@ -1,5 +1,6 @@ # Python imports import inspect +import time import json import zipfile @@ -22,35 +23,35 @@ class MissingConfigError(Exception): class SettingsManager(StartCheckMixin, Singleton): def __init__(self): - self._SCRIPT_PTH = path.dirname(path.realpath(__file__)) - self._USER_HOME = path.expanduser('~') - self._HOME_CONFIG_PATH = f"{self._USER_HOME}/.config/{APP_NAME.lower()}" - self._USR_PATH = f"/usr/share/{APP_NAME.lower()}" - self._USR_CONFIG_FILE = f"{self._USR_PATH}/settings.json" + self._SCRIPT_PTH: str = path.dirname(path.realpath(__file__)) + self._USER_HOME: str = path.expanduser('~') + self._HOME_CONFIG_PATH: str = f"{self._USER_HOME}/.config/{APP_NAME.lower()}" + self._USR_PATH: str = f"/usr/share/{APP_NAME.lower()}" + self._USR_CONFIG_FILE: str = f"{self._USR_PATH}/settings.json" - self._CONTEXT_PATH = f"{self._HOME_CONFIG_PATH}/context_path" - self._PLUGINS_PATH = f"{self._HOME_CONFIG_PATH}/plugins" - self._DEFAULT_ICONS = f"{self._HOME_CONFIG_PATH}/icons" - self._CONFIG_FILE = f"{self._HOME_CONFIG_PATH}/settings.json" - self._GLADE_FILE = f"{self._HOME_CONFIG_PATH}/Main_Window.glade" - self._CSS_FILE = f"{self._HOME_CONFIG_PATH}/stylesheet.css" - self._KEY_BINDINGS_FILE = f"{self._HOME_CONFIG_PATH}/key-bindings.json" - self._PID_FILE = f"{self._HOME_CONFIG_PATH}/{APP_NAME.lower()}.pid" - self._UI_WIDEGTS_PATH = f"{self._HOME_CONFIG_PATH}/ui_widgets" - self._CONTEXT_MENU = f"{self._HOME_CONFIG_PATH}/contexct_menu.json" - self._WINDOW_ICON = f"{self._DEFAULT_ICONS}/{APP_NAME.lower()}.png" + self._CONTEXT_PATH: str = f"{self._HOME_CONFIG_PATH}/context_path" + self._PLUGINS_PATH: str = f"{self._HOME_CONFIG_PATH}/plugins" + self._DEFAULT_ICONS: str = f"{self._HOME_CONFIG_PATH}/icons" + self._CONFIG_FILE: str = f"{self._HOME_CONFIG_PATH}/settings.json" + self._GLADE_FILE: str = f"{self._HOME_CONFIG_PATH}/Main_Window.glade" + self._CSS_FILE: str = f"{self._HOME_CONFIG_PATH}/stylesheet.css" + self._KEY_BINDINGS_FILE: str = f"{self._HOME_CONFIG_PATH}/key-bindings.json" + self._PID_FILE: str = f"{self._HOME_CONFIG_PATH}/{APP_NAME.lower()}.pid" + self._UI_WIDEGTS_PATH: str = f"{self._HOME_CONFIG_PATH}/ui_widgets" + self._CONTEXT_MENU: str = f"{self._HOME_CONFIG_PATH}/contexct_menu.json" + self._WINDOW_ICON: str = f"{self._DEFAULT_ICONS}/{APP_NAME.lower()}.png" - # self._USR_CONFIG_FILE = f"{self._USR_PATH}/settings.json" - # self._PLUGINS_PATH = f"plugins" - # self._CONFIG_FILE = f"settings.json" - # self._GLADE_FILE = f"Main_Window.glade" - # self._CSS_FILE = f"stylesheet.css" - # self._KEY_BINDINGS_FILE = f"key-bindings.json" - # self._PID_FILE = f"{APP_NAME.lower()}.pid" - # self._WINDOW_ICON = f"{APP_NAME.lower()}.png" - # self._UI_WIDEGTS_PATH = f"ui_widgets" - # self._CONTEXT_MENU = f"contexct_menu.json" - # self._DEFAULT_ICONS = f"icons" + # self._USR_CONFIG_FILE: str = f"{self._USR_PATH}/settings.json" + # self._PLUGINS_PATH: str = f"plugins" + # self._CONFIG_FILE: str = f"settings.json" + # self._GLADE_FILE: str = f"Main_Window.glade" + # self._CSS_FILE: str = f"stylesheet.css" + # self._KEY_BINDINGS_FILE: str = f"key-bindings.json" + # self._PID_FILE: str = f"{APP_NAME.lower()}.pid" + # self._WINDOW_ICON: str = f"{APP_NAME.lower()}.png" + # self._UI_WIDEGTS_PATH: str = f"ui_widgets" + # self._CONTEXT_MENU: str = f"contexct_menu.json" + # self._DEFAULT_ICONS: str = f"icons" # with zipfile.ZipFile("files.zip", mode="r", allowZip64=True) as zf: @@ -102,16 +103,16 @@ class SettingsManager(StartCheckMixin, Singleton): print( f"Settings Manager: {self._CONTEXT_MENU}\n\t\t{repr(e)}" ) - self.settings: Settings = None - self._main_window = None - self._builder = None - self.PAINT_BG_COLOR = (0, 0, 0, 0.0) + self.settings: Settings = None + self._main_window = None + self._builder = None + self.PAINT_BG_COLOR: tuple = (0, 0, 0, 0.0) - self._trace_debug = False - self._debug = False - self._dirty_start = False - self._passed_in_file = False - self._starting_files = [] + self._trace_debug: bool = False + self._debug: bool = False + self._dirty_start: bool = False + self._passed_in_file: bool = False + self._starting_files: list = [] def register_signals_to_builder(self, classes = None): @@ -159,23 +160,27 @@ class SettingsManager(StartCheckMixin, Singleton): def is_debug(self) -> str: return self._debug def is_starting_with_file(self) -> bool: return self._passed_in_file - def call_method(self, target_class = None, _method_name = None, data = None): + def call_method(self, target_class: any = None, _method_name: str = "", data: any = None): method_name = str(_method_name) method = getattr(target_class, method_name, lambda data: f"No valid key passed...\nkey={method_name}\nargs={data}") return method(data) if data else method() - def set_main_window_x(self, x = 0): self.settings.config.main_window_x = x - def set_main_window_y(self, y = 0): self.settings.config.main_window_y = y - def set_main_window_width(self, width = 800): self.settings.config.main_window_width = width - def set_main_window_height(self, height = 600): self.settings.config.main_window_height = height - def set_main_window_min_width(self, width = 720): self.settings.config.main_window_min_width = width - def set_main_window_min_height(self, height = 480): self.settings.config.main_window_min_height = height - def set_starting_files(self, files: list) -> None: self._starting_files = files + def set_main_window_x(self, x: int = 0): self.settings.config.main_window_x = x + def set_main_window_y(self, y: int = 0): self.settings.config.main_window_y = y + def set_main_window_width(self, width: int = 800): self.settings.config.main_window_width = width + def set_main_window_height(self, height: int = 600): self.settings.config.main_window_height = height + def set_main_window_min_width(self, width: int = 720): self.settings.config.main_window_min_width = width + def set_main_window_min_height(self, height: int = 480): self.settings.config.main_window_min_height = height + def set_starting_files(self, files: list): self._starting_files = files - def set_trace_debug(self, trace_debug): + def set_start_load_time(self): self._start_load_time = time.perf_counter() + def set_end_load_time(self): self._end_load_time = time.perf_counter() + def log_load_time(self): logger.info( f"Load Time: {self._end_load_time - self._start_load_time}" ) + + def set_trace_debug(self, trace_debug: bool): self._trace_debug = trace_debug - def set_debug(self, debug): + def set_debug(self, debug: bool): self._debug = debug def set_is_starting_with_file(self, is_passed_in_file: bool = False): @@ -193,4 +198,4 @@ class SettingsManager(StartCheckMixin, Singleton): def save_settings(self): with open(self._CONFIG_FILE, 'w') as outfile: - json.dump(self.settings.as_dict(), outfile, separators=(',', ':'), indent=4) + json.dump(self.settings.as_dict(), outfile, separators=(',', ':'), indent=4) \ No newline at end of file diff --git a/user_config/usr/share/app_name/context_path/resources/css/main.css b/user_config/usr/share/app_name/context_path/resources/css/main.css index 7264b0e..d7dea7c 100644 --- a/user_config/usr/share/app_name/context_path/resources/css/main.css +++ b/user_config/usr/share/app_name/context_path/resources/css/main.css @@ -43,6 +43,6 @@ /* Other message text colors */ -.errorTxt { color: rgb(170, 18, 18); } -.warningTxt { color: rgb(255, 168, 0); } -.successTxt { color: rgb(136, 204, 39); } +.error-txt { color: rgb(170, 18, 18); } +.warning-txt { color: rgb(255, 168, 0); } +.success=txt { color: rgb(136, 204, 39); } \ No newline at end of file diff --git a/user_config/usr/share/app_name/stylesheet.css b/user_config/usr/share/app_name/stylesheet.css index db9ed2c..9ad1dcc 100644 --- a/user_config/usr/share/app_name/stylesheet.css +++ b/user_config/usr/share/app_name/stylesheet.css @@ -1,12 +1,14 @@ /* ---- Make most desired things base transparent ---- */ +/* ---- Make most desired things base transparent ---- */ popover, -popover > *, -scrolledwindow > *, -textview > *, -.main-window > .base-container > .body-container, -.main-window > .base-container > .body-container > .left-container, -.main-window > .base-container > .body-container > .center-container, -.main-window > .base-container > .body-container > .right-container { +popover > box +.main-window, +.base-container, +.body-container, +.center-container, +.header-container, +.left-containerm, +.right-container { background: rgba(0, 0, 0, 0.0); color: rgba(255, 255, 255, 1); } From 33c0827ca2bea3162cb09382afa24f0e94d5a18e Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sun, 20 Oct 2024 16:03:19 -0500 Subject: [PATCH 19/27] Moved args info to settings and restructured calls --- src/__main__.py | 17 +++++------ src/app.py | 12 ++++---- src/core/controllers/base_controller.py | 30 +++++++++++--------- src/core/controllers/base_controller_data.py | 9 ++++-- src/core/window.py | 10 +++---- src/libs/settings/manager.py | 27 +++++++++++------- 6 files changed, 60 insertions(+), 45 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index b854e86..5b387cc 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -17,7 +17,7 @@ from app import Application -def main(args, unknownargs): +def main(): setproctitle(f'{APP_NAME}') settings_manager.set_start_load_time() @@ -28,7 +28,7 @@ def main(args, unknownargs): settings_manager.set_trace_debug(True) settings_manager.do_dirty_start_check() - Application(args, unknownargs) + Application() @@ -37,19 +37,20 @@ if __name__ == "__main__": parser = argparse.ArgumentParser() # Add long and short arguments - parser.add_argument("--debug", "-d", default="false", help="Do extra console messaging.") - parser.add_argument("--trace-debug", "-td", default="false", help="Disable saves, ignore IPC lock, do extra console messaging.") - parser.add_argument("--no-plugins", "-np", default="false", help="Do not load plugins.") + parser.add_argument("--debug", "-d", default = "false", help = "Do extra console messaging.") + parser.add_argument("--trace-debug", "-td", default = "false", help = "Disable saves, ignore IPC lock, do extra console messaging.") + parser.add_argument("--no-plugins", "-np", default = "false", help = "Do not load plugins.") - parser.add_argument("--new-tab", "-nt", default="false", help="Opens a 'New Tab' if a handler is set for it.") - parser.add_argument("--file", "-f", default="default", help="JUST SOME FILE ARG.") + parser.add_argument("--new-tab", "-nt", default = "false", help = "Opens a 'New Tab' if a handler is set for it.") + parser.add_argument("--file", "-f", default = "default", help = "JUST SOME FILE ARG.") # Read arguments (If any...) args, unknownargs = parser.parse_known_args() + settings_manager.set_starting_args( args, unknownargs ) try: faulthandler.enable() # For better debug info - main(args, unknownargs) + main() except Exception as e: traceback.print_exc() quit() \ No newline at end of file diff --git a/src/app.py b/src/app.py index 02bf996..2f39b3b 100644 --- a/src/app.py +++ b/src/app.py @@ -19,18 +19,20 @@ class AppLaunchException(Exception): class Application: """ docstring for Application. """ - def __init__(self, args, unknownargs): + def __init__(self): super(Application, self).__init__() if not settings_manager.is_trace_debug(): - self.load_ipc(args, unknownargs) + self.load_ipc() self.setup_debug_hook() - Window(args, unknownargs).main() + Window().main() - def load_ipc(self, args, unknownargs): - ipc_server = IPCServer() + def load_ipc(self): + args, unknownargs = settings_manager.get_starting_args() + ipc_server = IPCServer() + self.ipc_realization_check(ipc_server) if not ipc_server.is_ipc_alive: diff --git a/src/core/controllers/base_controller.py b/src/core/controllers/base_controller.py index 7681c6a..db9d05a 100644 --- a/src/core/controllers/base_controller.py +++ b/src/core/controllers/base_controller.py @@ -17,24 +17,15 @@ from .bridge_controller import BridgeController class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): - def __init__(self, args, unknownargs): - self.collect_files_dirs(args, unknownargs) - + def __init__(self): + self.collect_files_dirs() self.setup_controller_data() self._setup_styling() self._setup_signals() self._subscribe_to_events() self._load_controllers() - - if args.no_plugins == "false": - self.plugins_controller.pre_launch_plugins() - - if args.no_plugins == "false": - self.plugins_controller.post_launch_plugins() - - for file in settings_manager.get_starting_files(): - event_system.emit("post-file-to-ipc", file) + self._load_plugins_and_files() logger.info(f"Made it past {self.__class__} loading...") settings_manager.set_end_load_time() @@ -58,14 +49,25 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): def _load_controllers(self): BridgeController() + def _load_plugins_and_files(self): + args, unknownargs = settings_manager.get_starting_args() + if args.no_plugins == "false": + self.plugins_controller.pre_launch_plugins() + + if args.no_plugins == "false": + self.plugins_controller.post_launch_plugins() + + for file in settings_manager.get_starting_files(): + event_system.emit("post-file-to-ipc", file) + def _tggl_top_main_menubar(self): logger.debug("_tggl_top_main_menubar > stub...") def _load_glade_file(self): - self.builder.add_from_file(settings_manager.get_glade_file()) + self.builder.add_from_file( settings_manager.get_glade_file() ) self.builder.expose_object("main_window", self.window) settings_manager.set_builder(self.builder) self.base_container = BaseContainer() - settings_manager.register_signals_to_builder([self, self.base_container]) + settings_manager.register_signals_to_builder([self, self.base_container]) \ No newline at end of file diff --git a/src/core/controllers/base_controller_data.py b/src/core/controllers/base_controller_data.py index 4581209..de531b4 100644 --- a/src/core/controllers/base_controller_data.py +++ b/src/core/controllers/base_controller_data.py @@ -28,8 +28,11 @@ class BaseControllerData: self._load_glade_file() - def collect_files_dirs(self, args, unknownargs): - files = [] + def collect_files_dirs(self): + args, \ + unknownargs = settings_manager.get_starting_args() + files = [] + for arg in unknownargs + [args.new_tab,]: if os.path.isdir( arg.replace("file://", "") ): files.append( f"DIR|{arg.replace('file://', '')}" ) @@ -97,4 +100,4 @@ class BaseControllerData: proc = subprocess.Popen(command, stdin = subprocess.PIPE) proc.stdin.write(data.encode(encoding)) proc.stdin.close() - retcode = proc.wait() + retcode = proc.wait() \ No newline at end of file diff --git a/src/core/window.py b/src/core/window.py index 1b09fb4..aec77f6 100644 --- a/src/core/window.py +++ b/src/core/window.py @@ -24,7 +24,7 @@ class ControllerStartExceptiom(Exception): class Window(Gtk.ApplicationWindow): """ docstring for Window. """ - def __init__(self, args, unknownargs): + def __init__(self): super(Window, self).__init__() settings_manager.set_main_window(self) @@ -34,7 +34,7 @@ class Window(Gtk.ApplicationWindow): self._setup_styling() self._setup_signals() self._subscribe_to_events() - self._load_widgets(args, unknownargs) + self._load_widgets() self._set_window_data() self._set_size_constraints() @@ -63,11 +63,11 @@ class Window(Gtk.ApplicationWindow): event_system.subscribe("tear-down", self._tear_down) event_system.subscribe("load-interactive-debug", self._load_interactive_debug) - def _load_widgets(self, args, unknownargs): + def _load_widgets(self): if settings_manager.is_debug(): self.set_interactive_debugging(True) - self._controller = BaseController(args, unknownargs) + self._controller = BaseController() self._status_icon = StatusIcon() if not self._controller: raise ControllerStartException("BaseController exited and doesn't exist...") @@ -135,4 +135,4 @@ class Window(Gtk.ApplicationWindow): Gtk.main_quit() def main(self): - Gtk.main() + Gtk.main() \ No newline at end of file diff --git a/src/libs/settings/manager.py b/src/libs/settings/manager.py index ed38192..5b77c38 100644 --- a/src/libs/settings/manager.py +++ b/src/libs/settings/manager.py @@ -156,14 +156,8 @@ class SettingsManager(StartCheckMixin, Singleton): def get_home_path(self) -> str: return self._USER_HOME def get_starting_files(self) -> list: return self._starting_files - def is_trace_debug(self) -> str: return self._trace_debug - def is_debug(self) -> str: return self._debug - def is_starting_with_file(self) -> bool: return self._passed_in_file - - def call_method(self, target_class: any = None, _method_name: str = "", data: any = None): - method_name = str(_method_name) - method = getattr(target_class, method_name, lambda data: f"No valid key passed...\nkey={method_name}\nargs={data}") - return method(data) if data else method() + def get_starting_args(self): + return self.args, self.unknownargs def set_main_window_x(self, x: int = 0): self.settings.config.main_window_x = x def set_main_window_y(self, y: int = 0): self.settings.config.main_window_y = y @@ -172,10 +166,12 @@ class SettingsManager(StartCheckMixin, Singleton): def set_main_window_min_width(self, width: int = 720): self.settings.config.main_window_min_width = width def set_main_window_min_height(self, height: int = 480): self.settings.config.main_window_min_height = height def set_starting_files(self, files: list): self._starting_files = files - def set_start_load_time(self): self._start_load_time = time.perf_counter() def set_end_load_time(self): self._end_load_time = time.perf_counter() - def log_load_time(self): logger.info( f"Load Time: {self._end_load_time - self._start_load_time}" ) + + def set_starting_args(self, args, unknownargs): + self.args = args + self.unknownargs = unknownargs def set_trace_debug(self, trace_debug: bool): self._trace_debug = trace_debug @@ -186,6 +182,17 @@ class SettingsManager(StartCheckMixin, Singleton): def set_is_starting_with_file(self, is_passed_in_file: bool = False): self._passed_in_file = is_passed_in_file + def is_trace_debug(self) -> str: return self._trace_debug + def is_debug(self) -> str: return self._debug + def is_starting_with_file(self) -> bool: return self._passed_in_file + + def log_load_time(self): logger.info( f"Load Time: {self._end_load_time - self._start_load_time}" ) + + def call_method(self, target_class: any = None, _method_name: str = "", data: any = None): + method_name = str(_method_name) + method = getattr(target_class, method_name, lambda data: f"No valid key passed...\nkey={method_name}\nargs={data}") + return method(data) if data else method() + def load_settings(self): if not path.exists(self._CONFIG_FILE): self.settings = Settings() From cca007db76886b29dda1788fee240afa17e50af8 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Fri, 8 Nov 2024 22:46:07 -0600 Subject: [PATCH 20/27] Added VTE widget; css changes; format cleanup --- src/__builtins__.py | 10 +- src/app.py | 6 +- src/core/containers/right_container.py | 4 +- src/core/controllers/base_controller.py | 3 +- src/core/controllers/base_controller_data.py | 5 +- src/core/widgets/vte_widget.py | 125 ++++++++++++++++++ .../context_path/resources/css/overrides.css | 3 +- 7 files changed, 143 insertions(+), 13 deletions(-) create mode 100644 src/core/widgets/vte_widget.py diff --git a/src/__builtins__.py b/src/__builtins__.py index 37abfc6..5bfe5a6 100644 --- a/src/__builtins__.py +++ b/src/__builtins__.py @@ -46,9 +46,11 @@ builtins.settings_manager = SettingsManager() settings_manager.load_settings() builtins.settings = settings_manager.settings -builtins.logger = Logger(settings_manager.get_home_config_path(), \ - _ch_log_lvl=settings.debugging.ch_log_lvl, \ - _fh_log_lvl=settings.debugging.fh_log_lvl).get_logger() +builtins.logger = Logger( + settings_manager.get_home_config_path(), \ + _ch_log_lvl = settings.debugging.ch_log_lvl, \ + _fh_log_lvl = settings.debugging.fh_log_lvl + ).get_logger() builtins.threaded = threaded_wrapper builtins.daemon_threaded = daemon_threaded_wrapper @@ -60,6 +62,6 @@ def custom_except_hook(exc_type, exc_value, exc_traceback): sys.__excepthook__(exc_type, exc_value, exc_traceback) return - logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback)) + logger.error("Uncaught exception", exc_info = (exc_type, exc_value, exc_traceback)) sys.excepthook = custom_except_hook \ No newline at end of file diff --git a/src/app.py b/src/app.py index 2f39b3b..1570122 100644 --- a/src/app.py +++ b/src/app.py @@ -30,11 +30,11 @@ class Application: def load_ipc(self): - args, unknownargs = settings_manager.get_starting_args() - ipc_server = IPCServer() + args, \ + unknownargs = settings_manager.get_starting_args() + ipc_server = IPCServer() self.ipc_realization_check(ipc_server) - if not ipc_server.is_ipc_alive: for arg in unknownargs + [args.new_tab,]: if os.path.isfile(arg): diff --git a/src/core/containers/right_container.py b/src/core/containers/right_container.py index 5b61e21..a8c0138 100644 --- a/src/core/containers/right_container.py +++ b/src/core/containers/right_container.py @@ -6,6 +6,7 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports +from ..widgets.vte_widget import VteWidget @@ -33,4 +34,5 @@ class RightContainer(Gtk.Box): ... def _load_widgets(self): - ... \ No newline at end of file + vte_widget = VteWidget() + self.add( vte_widget ) \ No newline at end of file diff --git a/src/core/controllers/base_controller.py b/src/core/controllers/base_controller.py index db9d05a..221a76a 100644 --- a/src/core/controllers/base_controller.py +++ b/src/core/controllers/base_controller.py @@ -18,9 +18,8 @@ from .bridge_controller import BridgeController class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): def __init__(self): - self.collect_files_dirs() - self.setup_controller_data() + self._setup_controller_data() self._setup_styling() self._setup_signals() self._subscribe_to_events() diff --git a/src/core/controllers/base_controller_data.py b/src/core/controllers/base_controller_data.py index de531b4..f070ac5 100644 --- a/src/core/controllers/base_controller_data.py +++ b/src/core/controllers/base_controller_data.py @@ -14,7 +14,7 @@ from ..builder_wrapper import BuilderWrapper class BaseControllerData: ''' BaseControllerData contains most of the state of the app at ay given time. It also has some support methods. ''' - def setup_controller_data(self) -> None: + def _setup_controller_data(self) -> None: self.window = settings_manager.get_main_window() self.builder = BuilderWrapper() self.plugins_controller = PluginsController() @@ -25,10 +25,11 @@ class BaseControllerData: self.shift_down = False self.alt_down = False + self._collect_files_dirs() self._load_glade_file() - def collect_files_dirs(self): + def _collect_files_dirs(self): args, \ unknownargs = settings_manager.get_starting_args() files = [] diff --git a/src/core/widgets/vte_widget.py b/src/core/widgets/vte_widget.py new file mode 100644 index 0000000..608e84a --- /dev/null +++ b/src/core/widgets/vte_widget.py @@ -0,0 +1,125 @@ +# Python imports +import os + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') +gi.require_version('Vte', '2.91') +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import GLib +from gi.repository import Vte + +# Application imports +from libs.dto.event import Event + + + +class VteWidgetException(Exception): + ... + + + +class VteWidget(Vte.Terminal): + """ + https://stackoverflow.com/questions/60454326/how-to-implement-a-linux-terminal-in-a-pygtk-app-like-vscode-and-pycharm-has + """ + + def __init__(self): + super(VteWidget, self).__init__() + + self.cd_cmd_prefix = ("cd".encode(), "cd ".encode()) + self.dont_process = False + + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + self._do_session_spawn() + + self.show() + + + def _setup_styling(self): + ctx = self.get_style_context() + ctx.add_class("vte-widget") + + self.set_clear_background(False) + self.set_enable_sixel(True) + self.set_cursor_shape( Vte.CursorShape.IBEAM ) + + def _setup_signals(self): + self.connect("commit", self._commit) + + def _subscribe_to_events(self): + event_system.subscribe("update_term_path", self.update_term_path) + + def _load_widgets(self): + ... + + def _do_session_spawn(self): + self.spawn_sync( + Vte.PtyFlags.DEFAULT, + settings_manager.get_home_path(), + ["/bin/bash"], + [], + GLib.SpawnFlags.DEFAULT, + None, None, + ) + + # Note: '-->:' is used as a delimiter to split on to get command actual. + # !!! DO NOT REMOVE UNLESS CODE UPDATED ACCORDINGLY !!! + startup_cmds = [ + "env -i /bin/bash --noprofile --norc\n", + "export TERM='xterm-256color'\n", + "export LC_ALL=C\n", + "export XDG_RUNTIME_DIR='/run/user/1000'\n", + "export DISPLAY=:0\n", + f"export XAUTHORITY='{settings_manager.get_home_path()}/.Xauthority'\n", + f"\nexport HOME='{settings_manager.get_home_path()}'\n", + "export PS1='\\h@\\u \\W -->: '\n", + "clear\n" + ] + + for i in startup_cmds: + self.run_command(i) + + def _commit(self, terminal, text, size): + if self.dont_process: + self.dont_process = False + return + + if not text.encode() == "\r".encode(): return + + text, attributes = self.get_text() + lines = text.strip().splitlines() + command_ran = None + + try: + command_ran = lines[-1].split("-->:")[1].strip() + except VteWidgetException as e: + logger.debud(e) + return + + if not command_ran[0:3].encode() in self.cd_cmd_prefix: + return + + target_path = command_ran.split( command_ran[0:3] )[1] + if target_path in (".", "./"): return + + if not target_path: + target_path = settings_manager.get_home_path() + + event = Event("pty_path_updated", "", target_path) + event_system.emit("handle_bridge_event", (event,)) + + def update_term_path(self, fpath): + self.dont_process = True + + cmds = [f"cd '{fpath}'\n", "clear\n"] + for i in cmds: + self.run_command(i) + + def run_command(self, cmd): + self.feed_child_binary(bytes(cmd, 'utf8')) \ No newline at end of file diff --git a/user_config/usr/share/app_name/context_path/resources/css/overrides.css b/user_config/usr/share/app_name/context_path/resources/css/overrides.css index 8501c90..950c496 100644 --- a/user_config/usr/share/app_name/context_path/resources/css/overrides.css +++ b/user_config/usr/share/app_name/context_path/resources/css/overrides.css @@ -1,6 +1,7 @@ html, body { display: block; - background-color: #32383e00; +// background-color: #32383e00; + background-color: rgba(39, 43, 52, 0.64); color: #ffffff; text-wrap: wrap; } From dd3e87f63607744f179037bfdbc3c56330fd0bdc Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sun, 22 Dec 2024 00:50:32 -0600 Subject: [PATCH 21/27] Adding call chain wrapper; cleanup; optimization --- src/__builtins__.py | 13 ++++ src/core/controllers/base_controller.py | 2 - src/core/controllers/base_controller_data.py | 4 ++ src/core/controllers/bridge_controller.py | 2 - .../widgets/controls/open_files_button.py | 2 - src/core/widgets/controls/save_as_button.py | 72 +++++++++++++++++++ 6 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 src/core/widgets/controls/save_as_button.py diff --git a/src/__builtins__.py b/src/__builtins__.py index 5bfe5a6..b1a8c6e 100644 --- a/src/__builtins__.py +++ b/src/__builtins__.py @@ -1,5 +1,6 @@ # Python imports import builtins +import traceback import threading import sys @@ -31,6 +32,17 @@ def daemon_threaded_wrapper(fn): return thread return wrapper +def call_chain_wrapper(fn): + def wrapper(*args, **kwargs): + print() + print() + for line in traceback.format_stack(): + print( line.strip() ) + print() + print() + + return fn(*args, **kwargs) + return wrapper # NOTE: Just reminding myself we can add to builtins two different ways... @@ -54,6 +66,7 @@ builtins.logger = Logger( builtins.threaded = threaded_wrapper builtins.daemon_threaded = daemon_threaded_wrapper +builtins.call_chain = call_chain_wrapper diff --git a/src/core/controllers/base_controller.py b/src/core/controllers/base_controller.py index 221a76a..5dfd377 100644 --- a/src/core/controllers/base_controller.py +++ b/src/core/controllers/base_controller.py @@ -52,8 +52,6 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): args, unknownargs = settings_manager.get_starting_args() if args.no_plugins == "false": self.plugins_controller.pre_launch_plugins() - - if args.no_plugins == "false": self.plugins_controller.post_launch_plugins() for file in settings_manager.get_starting_files(): diff --git a/src/core/controllers/base_controller_data.py b/src/core/controllers/base_controller_data.py index f070ac5..47088e4 100644 --- a/src/core/controllers/base_controller_data.py +++ b/src/core/controllers/base_controller_data.py @@ -37,10 +37,14 @@ class BaseControllerData: for arg in unknownargs + [args.new_tab,]: if os.path.isdir( arg.replace("file://", "") ): files.append( f"DIR|{arg.replace('file://', '')}" ) + continue # NOTE: If passing line number with file split against : if os.path.isfile( arg.replace("file://", "").split(":")[0] ): files.append( f"FILE|{arg.replace('file://', '')}" ) + continue + + logger.info(f"Not a File: {arg}") if len(files) > 0: settings_manager.set_is_starting_with_file(True) diff --git a/src/core/controllers/bridge_controller.py b/src/core/controllers/bridge_controller.py index 9a689c8..bc2c542 100644 --- a/src/core/controllers/bridge_controller.py +++ b/src/core/controllers/bridge_controller.py @@ -10,8 +10,6 @@ import base64 class BridgeController: def __init__(self): - self.opened_files = {} - self._setup_signals() self._subscribe_to_events() diff --git a/src/core/widgets/controls/open_files_button.py b/src/core/widgets/controls/open_files_button.py index 06e6a9f..42acf30 100644 --- a/src/core/widgets/controls/open_files_button.py +++ b/src/core/widgets/controls/open_files_button.py @@ -4,9 +4,7 @@ import os # Lib imports import gi gi.require_version('Gtk', '3.0') -gi.require_version('Gdk', '3.0') from gi.repository import Gtk -from gi.repository import Gdk from gi.repository import Gio # Application imports diff --git a/src/core/widgets/controls/save_as_button.py b/src/core/widgets/controls/save_as_button.py new file mode 100644 index 0000000..aa81ae0 --- /dev/null +++ b/src/core/widgets/controls/save_as_button.py @@ -0,0 +1,72 @@ +# Python imports +import os + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk +from gi.repository import Gio + +# Application imports + + + +class SaveAsButton(Gtk.Button): + def __init__(self): + super(SaveAsButton, self).__init__() + + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + + def _setup_styling(self): + self.set_label("Save As") + self.set_image( Gtk.Image.new_from_icon_name("gtk-save-as", 4) ) + self.set_always_show_image(True) + self.set_image_position(1) # Left - 0, Right = 1 + self.set_hexpand(False) + + def _setup_signals(self): + self.connect("released", self._save_as) + + def _subscribe_to_events(self): + event_system.subscribe("save-as", self._save_as) + + def _load_widgets(self): + ... + + def _save_as(self, widget = None, eve = None, gfile = None): + start_dir = None + _gfile = None + + chooser = Gtk.FileChooserDialog("Save File As...", None, + Gtk.FileChooserAction.SAVE, + ( + Gtk.STOCK_CANCEL, + Gtk.ResponseType.CANCEL, + Gtk.STOCK_SAVE_AS, + Gtk.ResponseType.OK + ) + ) + + # chooser.set_select_multiple(False) + + response = chooser.run() + if not response == Gtk.ResponseType.OK: + chooser.destroy() + return _gfile + + file = chooser.get_filename() + if not file: + chooser.destroy() + return _gfile + + path = file if os.path.isabs(file) else os.path.abspath(file) + _gfile = Gio.File.new_for_path(path) + + chooser.destroy() + + logger.debug(f"File To Save As: {_gfile}") + return _gfile From 18dc71dcb03f073f94562e5f44ad405c60b4f6d0 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sun, 13 Jul 2025 14:15:25 -0500 Subject: [PATCH 22/27] Adding generic doc string basecontroller --- src/core/controllers/base_controller.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/controllers/base_controller.py b/src/core/controllers/base_controller.py index 5dfd377..474e200 100644 --- a/src/core/controllers/base_controller.py +++ b/src/core/controllers/base_controller.py @@ -17,6 +17,8 @@ from .bridge_controller import BridgeController class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData): + """ docstring for BaseController. """ + def __init__(self): self._setup_controller_data() From 4cd5a1f08906c801fee415e5884c6a2190cd38fe Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sun, 13 Jul 2025 14:17:52 -0500 Subject: [PATCH 23/27] Fixing readme n requirements --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index bfb1be3..c055f2b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,4 @@ setproctitle==1.2.2 pyxdg==0.27 psutil==5.8.0 pycryptodome==3.20.0 -sqlmodel==0.0.19 \ No newline at end of file +sqlmodel==0.0.19 From 7c0d87fd2008e78ec3a138b307f49af0a388c60e Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Mon, 25 Aug 2025 00:22:42 -0500 Subject: [PATCH 24/27] Slight call start restructuring, fixing css for popover box --- src/__main__.py | 4 +++- src/app.py | 5 ++++- src/core/window.py | 14 +++++++------- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 5b387cc..b30240b 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -28,7 +28,9 @@ def main(): settings_manager.set_trace_debug(True) settings_manager.do_dirty_start_check() - Application() + + app = Application() + app.run() diff --git a/src/app.py b/src/app.py index 1570122..32f1e0b 100644 --- a/src/app.py +++ b/src/app.py @@ -26,9 +26,12 @@ class Application: self.load_ipc() self.setup_debug_hook() - Window().main() + def run(self): + win = Window() + win.start() + def load_ipc(self): args, \ unknownargs = settings_manager.get_starting_args() diff --git a/src/core/window.py b/src/core/window.py index aec77f6..684d5a2 100644 --- a/src/core/window.py +++ b/src/core/window.py @@ -56,11 +56,11 @@ class Window(Gtk.ApplicationWindow): self.connect("focus-in-event", self._on_focus_in_event) self.connect("focus-out-event", self._on_focus_out_event) - self.connect("delete-event", self._tear_down) - GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self._tear_down) + self.connect("delete-event", self.stop) + GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self.stop) def _subscribe_to_events(self): - event_system.subscribe("tear-down", self._tear_down) + event_system.subscribe("tear-down", self.stop) event_system.subscribe("load-interactive-debug", self._load_interactive_debug) def _load_widgets(self): @@ -119,7 +119,10 @@ class Window(Gtk.ApplicationWindow): self.set_interactive_debugging(True) - def _tear_down(self, widget = None, eve = None): + def start(self): + Gtk.main() + + def stop(self, widget = None, eve = None): event_system.emit("shutting-down") size = self.get_size() @@ -133,6 +136,3 @@ class Window(Gtk.ApplicationWindow): settings_manager.clear_pid() Gtk.main_quit() - - def main(self): - Gtk.main() \ No newline at end of file From 60b55da973c591bd4e8fb072f7ff8d606816c8c9 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Tue, 21 Oct 2025 22:20:06 -0500 Subject: [PATCH 25/27] Moved to use contextlib suppress pattern than empty exception blocks --- src/__builtins__.py | 2 +- src/app.py | 12 +++++------- src/core/controllers/base_controller_data.py | 17 ++++++++--------- src/core/widgets/controls/open_files_button.py | 5 ++--- src/core/widgets/vte_widget.py | 10 +++++----- src/libs/singleton.py | 12 +++++------- 6 files changed, 26 insertions(+), 32 deletions(-) diff --git a/src/__builtins__.py b/src/__builtins__.py index b1a8c6e..3642a81 100644 --- a/src/__builtins__.py +++ b/src/__builtins__.py @@ -77,4 +77,4 @@ def custom_except_hook(exc_type, exc_value, exc_traceback): logger.error("Uncaught exception", exc_info = (exc_type, exc_value, exc_traceback)) -sys.excepthook = custom_except_hook \ No newline at end of file +sys.excepthook = custom_except_hook diff --git a/src/app.py b/src/app.py index 32f1e0b..14eca5a 100644 --- a/src/app.py +++ b/src/app.py @@ -1,4 +1,5 @@ # Python imports +from contextlib import suppress import signal import os @@ -52,18 +53,15 @@ class Application: except Exception: ipc_server.send_test_ipc_message() - try: + with suppress(Exception): ipc_server.create_ipc_listener() - except Exception as e: - ... def setup_debug_hook(self): - try: + # Typically: ValueError: signal only works in main thread + with suppress(ValueError): # kill -SIGUSR2 from Linux/Unix or SIGBREAK signal from Windows signal.signal( vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR2"), debug_signal_handler ) - except ValueError: - # Typically: ValueError: signal only works in main thread - ... \ No newline at end of file + diff --git a/src/core/controllers/base_controller_data.py b/src/core/controllers/base_controller_data.py index 47088e4..966be21 100644 --- a/src/core/controllers/base_controller_data.py +++ b/src/core/controllers/base_controller_data.py @@ -46,9 +46,10 @@ class BaseControllerData: logger.info(f"Not a File: {arg}") - if len(files) > 0: - settings_manager.set_is_starting_with_file(True) - settings_manager.set_starting_files(files) + if len(files) == 0: return + + settings_manager.set_is_starting_with_file(True) + settings_manager.set_starting_files(files) def get_base_container(self): return self.base_container @@ -84,24 +85,22 @@ class BaseControllerData: widget.remove(child) def get_clipboard_data(self, encoding = "utf-8") -> str: - if which("xclip"): - command = ['xclip','-selection','clipboard'] - else: + if not which("xclip"): logger.info('xclip not found...') return + command = ['xclip','-selection','clipboard'] proc = subprocess.Popen(['xclip','-selection', 'clipboard', '-o'], stdout = subprocess.PIPE) retcode = proc.wait() data = proc.stdout.read() return data.decode(encoding).strip() def set_clipboard_data(self, data: type, encoding = "utf-8") -> None: - if which("xclip"): - command = ['xclip','-selection','clipboard'] - else: + if not which("xclip"): logger.info('xclip not found...') return + command = ['xclip','-selection','clipboard'] proc = subprocess.Popen(command, stdin = subprocess.PIPE) proc.stdin.write(data.encode(encoding)) proc.stdin.close() diff --git a/src/core/widgets/controls/open_files_button.py b/src/core/widgets/controls/open_files_button.py index 42acf30..d29eaea 100644 --- a/src/core/widgets/controls/open_files_button.py +++ b/src/core/widgets/controls/open_files_button.py @@ -1,4 +1,5 @@ # Python imports +from contextlib import suppress import os # Lib imports @@ -58,11 +59,9 @@ class OpenFilesButton(Gtk.Button): chooser.set_select_multiple(True) - try: + with suppress(Exception): folder = widget.get_current_file().get_parent() if not start_dir else start_dir chooser.set_current_folder( folder.get_path() ) - except Exception as e: - ... response = chooser.run() if not response == Gtk.ResponseType.OK: diff --git a/src/core/widgets/vte_widget.py b/src/core/widgets/vte_widget.py index 608e84a..7a5f18d 100644 --- a/src/core/widgets/vte_widget.py +++ b/src/core/widgets/vte_widget.py @@ -99,7 +99,7 @@ class VteWidget(Vte.Terminal): try: command_ran = lines[-1].split("-->:")[1].strip() except VteWidgetException as e: - logger.debud(e) + logger.debug(e) return if not command_ran[0:3].encode() in self.cd_cmd_prefix: @@ -114,12 +114,12 @@ class VteWidget(Vte.Terminal): event = Event("pty_path_updated", "", target_path) event_system.emit("handle_bridge_event", (event,)) - def update_term_path(self, fpath): + def update_term_path(self, fpath: str): self.dont_process = True cmds = [f"cd '{fpath}'\n", "clear\n"] - for i in cmds: - self.run_command(i) + for cmd in cmds: + self.run_command(cmd) - def run_command(self, cmd): + def run_command(self, cmd: str): self.feed_child_binary(bytes(cmd, 'utf8')) \ No newline at end of file diff --git a/src/libs/singleton.py b/src/libs/singleton.py index 23b7191..b484b28 100644 --- a/src/libs/singleton.py +++ b/src/libs/singleton.py @@ -12,13 +12,11 @@ class SingletonError(Exception): class Singleton: - ccount = 0 + _instance = None def __new__(cls, *args, **kwargs): - obj = super(Singleton, cls).__new__(cls) - cls.ccount += 1 + if cls._instance: + raise SingletonError(f"'{cls.__name__}' is a Singleton. Cannot create a new instance...") - if cls.ccount == 2: - raise SingletonError(f"Exceeded {cls.__name__} instantiation limit...") - - return obj + cls._instance = super(Singleton, cls).__new__(cls) + return cls._instance From 4c25ce297c9845547f37ef286a7fe87b33062b86 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Tue, 21 Oct 2025 22:21:06 -0500 Subject: [PATCH 26/27] Corrected css for popover box --- user_config/usr/share/app_name/stylesheet.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/user_config/usr/share/app_name/stylesheet.css b/user_config/usr/share/app_name/stylesheet.css index 9ad1dcc..ecac4cd 100644 --- a/user_config/usr/share/app_name/stylesheet.css +++ b/user_config/usr/share/app_name/stylesheet.css @@ -1,7 +1,6 @@ /* ---- Make most desired things base transparent ---- */ -/* ---- Make most desired things base transparent ---- */ popover, -popover > box +popover > box, .main-window, .base-container, .body-container, From 22736147e6785bef2b500822c6d7c93ce2dd6a30 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sat, 29 Nov 2025 23:22:03 -0600 Subject: [PATCH 27/27] added clock, pager, and task list widgets for ref; added footer container; added option for key combo o universally toggle window with key combo if set --- src/core/containers/base_container.py | 2 + src/core/containers/center_container.py | 4 + src/core/containers/footer_container.py | 41 +++++++ src/core/containers/header_container.py | 5 +- src/core/containers/left_container.py | 3 + src/core/containers/right_container.py | 3 + src/core/controllers/base_controller_data.py | 2 +- src/core/widgets/clock_widget.py | 110 ++++++++++++++++++ src/core/widgets/pager_widget.py | 35 ++++++ src/core/widgets/task_list_widget.py | 54 +++++++++ src/core/window.py | 63 ++++++++++ src/libs/ipc_server.py | 2 +- src/libs/settings/manager.py | 5 +- .../usr/share/app_name/key-bindings.json | 1 + user_config/usr/share/app_name/stylesheet.css | 1 + 15 files changed, 327 insertions(+), 4 deletions(-) create mode 100644 src/core/containers/footer_container.py create mode 100644 src/core/widgets/clock_widget.py create mode 100644 src/core/widgets/pager_widget.py create mode 100644 src/core/widgets/task_list_widget.py diff --git a/src/core/containers/base_container.py b/src/core/containers/base_container.py index 79ab27e..d725c88 100644 --- a/src/core/containers/base_container.py +++ b/src/core/containers/base_container.py @@ -8,6 +8,7 @@ from gi.repository import Gtk # Application imports from .header_container import HeaderContainer from .body_container import BodyContainer +from .footer_container import FooterContainer @@ -39,6 +40,7 @@ class BaseContainer(Gtk.Box): def _load_widgets(self): self.add(HeaderContainer()) self.add(BodyContainer()) + self.add(FooterContainer()) def _update_transparency(self): self.ctx.add_class(f"mw_transparency_{settings.theming.transparency}") diff --git a/src/core/containers/center_container.py b/src/core/containers/center_container.py index ae6858f..2fa8887 100644 --- a/src/core/containers/center_container.py +++ b/src/core/containers/center_container.py @@ -26,6 +26,10 @@ class CenterContainer(Gtk.Box): def _setup_styling(self): self.set_orientation(Gtk.Orientation.VERTICAL) + + self.set_hexpand(True) + self.set_vexpand(True) + ctx = self.get_style_context() ctx.add_class("center-container") diff --git a/src/core/containers/footer_container.py b/src/core/containers/footer_container.py new file mode 100644 index 0000000..4e21cea --- /dev/null +++ b/src/core/containers/footer_container.py @@ -0,0 +1,41 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports + + + +class FooterContainer(Gtk.Box): + def __init__(self): + super(FooterContainer, self).__init__() + + self.ctx = self.get_style_context() + + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + self.show() + + + def _setup_styling(self): + self.set_orientation(Gtk.Orientation.HORIZONTAL) + + self.set_hexpand(True) + + self.ctx.add_class("footer-container") + + def _setup_signals(self): + ... + + def _subscribe_to_events(self): + ... + + + def _load_widgets(self): + ... diff --git a/src/core/containers/header_container.py b/src/core/containers/header_container.py index 6463b1d..7da0a75 100644 --- a/src/core/containers/header_container.py +++ b/src/core/containers/header_container.py @@ -22,11 +22,14 @@ class HeaderContainer(Gtk.Box): self._subscribe_to_events() self._load_widgets() - self.show_all() + self.show() def _setup_styling(self): self.set_orientation(Gtk.Orientation.HORIZONTAL) + + self.set_hexpand(True) + self.ctx.add_class("header-container") def _setup_signals(self): diff --git a/src/core/containers/left_container.py b/src/core/containers/left_container.py index 4b4e564..45e6a37 100644 --- a/src/core/containers/left_container.py +++ b/src/core/containers/left_container.py @@ -23,6 +23,9 @@ class LeftContainer(Gtk.Box): def _setup_styling(self): self.set_orientation(Gtk.Orientation.VERTICAL) + + self.set_vexpand(True) + ctx = self.get_style_context() ctx.add_class("left-container") diff --git a/src/core/containers/right_container.py b/src/core/containers/right_container.py index a8c0138..6e760a7 100644 --- a/src/core/containers/right_container.py +++ b/src/core/containers/right_container.py @@ -24,6 +24,9 @@ class RightContainer(Gtk.Box): def _setup_styling(self): self.set_orientation(Gtk.Orientation.VERTICAL) + + self.set_vexpand(True) + ctx = self.get_style_context() ctx.add_class("right-container") diff --git a/src/core/controllers/base_controller_data.py b/src/core/controllers/base_controller_data.py index 966be21..8b85498 100644 --- a/src/core/controllers/base_controller_data.py +++ b/src/core/controllers/base_controller_data.py @@ -104,4 +104,4 @@ class BaseControllerData: proc = subprocess.Popen(command, stdin = subprocess.PIPE) proc.stdin.write(data.encode(encoding)) proc.stdin.close() - retcode = proc.wait() \ No newline at end of file + retcode = proc.wait() diff --git a/src/core/widgets/clock_widget.py b/src/core/widgets/clock_widget.py new file mode 100644 index 0000000..bda1842 --- /dev/null +++ b/src/core/widgets/clock_widget.py @@ -0,0 +1,110 @@ +# Python imports +from datetime import datetime + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk +from gi.repository import GObject + +# Application imports + + + +class CalendarWidget(Gtk.Popover): + def __init__(self): + super(CalendarWidget, self).__init__() + + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + + def _setup_styling(self): + ... + + def _setup_signals(self): + ... + + def _subscribe_to_events(self): + ... + + def _load_widgets(self): + self.body = Gtk.Calendar() + + self.body.show() + self.add(self.body) + + +class ClockWidget(Gtk.EventBox): + def __init__(self): + super(ClockWidget, self).__init__() + + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + self.show_all() + + + def _setup_styling(self): + self.set_size_request(180, -1) + + ctx = self.get_style_context() + ctx.add_class("clock-widget") + + def _setup_signals(self): + self.connect("button_release_event", self._toggle_cal_popover) + + + def _subscribe_to_events(self): + ... + + def _load_widgets(self): + self.calendar = CalendarWidget() + self.label = Gtk.Label() + + self.calendar.set_relative_to(self) + + self.label.set_justify(Gtk.Justification.CENTER) + self.label.set_margin_top(15) + self.label.set_margin_bottom(15) + self.label.set_margin_left(15) + self.label.set_margin_right(15) + + self._update_face() + self.add(self.label) + + GObject.timeout_add(59000, self._update_face) + + def _update_face(self): + dt_now = datetime.now() + hours_mins_sec = dt_now.strftime("%I:%M %p") + month_day_year = dt_now.strftime("%m/%d/%Y") + time_str = hours_mins_sec + "\n" + month_day_year + + self.label.set_label(time_str) + + def _toggle_cal_popover(self, widget, eve): + if (self.calendar.get_visible() == True): + self.calendar.popdown() + return + + now = datetime.now() + timeStr = now.strftime("%m/%d/%Y") + parts = timeStr.split("/") + month = int(parts[0]) - 1 + day = int(parts[1]) + year = int(parts[2]) + + self.calendar.body.select_day(day) + self.calendar.body.select_month(month, year) + + self.calendar.popup() + + + + + diff --git a/src/core/widgets/pager_widget.py b/src/core/widgets/pager_widget.py new file mode 100644 index 0000000..9736ee5 --- /dev/null +++ b/src/core/widgets/pager_widget.py @@ -0,0 +1,35 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Wnck', '3.0') +from gi.repository import Wnck + +# Application imports + + + +class PagerWidget: + def __init__(self): + super(PagerWidget, self).__init__() + + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + + def _setup_styling(self): + ... + + def _setup_signals(self): + ... + + def _subscribe_to_events(self): + ... + + def _load_widgets(self): + ... + + def get_widget(self): + return Wnck.Pager.new() diff --git a/src/core/widgets/task_list_widget.py b/src/core/widgets/task_list_widget.py new file mode 100644 index 0000000..244a092 --- /dev/null +++ b/src/core/widgets/task_list_widget.py @@ -0,0 +1,54 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('Wnck', '3.0') +from gi.repository import Gtk +from gi.repository import Wnck + +# Application imports + + + +class TaskListWidget(Gtk.ScrolledWindow): + def __init__(self): + super(TaskListWidget, self).__init__() + + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + self.show_all() + + + def _setup_styling(self): + self.set_hexpand(False) + self.set_size_request(180, -1) + + def _setup_signals(self): + ... + + def _subscribe_to_events(self): + ... + + def _load_widgets(self): + viewport = Gtk.Viewport() + task_list = Wnck.Tasklist.new() + vbox = Gtk.Box() + + vbox.set_orientation(Gtk.Orientation.VERTICAL) + + + task_list.set_scroll_enabled(False) + task_list.set_button_relief(2) # 0 = normal relief, 2 = no relief + task_list.set_grouping(1) # 0 = mever group, 1 auto group, 2 = always group + + task_list.set_vexpand(True) + task_list.set_include_all_workspaces(False) + task_list.set_orientation(1) # 0 = horizontal, 1 = vertical + + vbox.add(task_list) + viewport.add(vbox) + self.add(viewport) diff --git a/src/core/window.py b/src/core/window.py index 684d5a2..8199215 100644 --- a/src/core/window.py +++ b/src/core/window.py @@ -10,6 +10,11 @@ from gi.repository import Gtk from gi.repository import Gdk from gi.repository import GLib +try: + from gi.repository import GdkX11 +except ImportError: + logger.debug("Could not import X11 gir module...") + # Application imports from libs.status_icon import StatusIcon from core.controllers.base_controller import BaseController @@ -31,6 +36,9 @@ class Window(Gtk.ApplicationWindow): self._status_icon = None self._controller = None + self.guake_key = settings_manager.get_guake_key() + self.hidefunc = None + self._setup_styling() self._setup_signals() self._subscribe_to_events() @@ -38,6 +46,7 @@ class Window(Gtk.ApplicationWindow): self._set_window_data() self._set_size_constraints() + self._setup_window_toggle_event() self.show() @@ -45,6 +54,9 @@ class Window(Gtk.ApplicationWindow): def _setup_styling(self): self.set_title(f"{APP_NAME}") self.set_icon_from_file( settings_manager.get_window_icon() ) + self.set_decorated(True) + self.set_skip_pager_hint(False) + self.set_skip_taskbar_hint(False) self.set_gravity(5) # 5 = CENTER self.set_position(1) # 1 = CENTER, 4 = CENTER_ALWAYS @@ -74,6 +86,15 @@ class Window(Gtk.ApplicationWindow): self.add( self._controller.get_base_container() ) + def _display_manager(self): + """ Try to detect which display manager we are running under... """ + + import os + if os.environ.get('WAYLAND_DISPLAY'): + return 'WAYLAND' + + return 'X11' + def _set_size_constraints(self): _window_x = settings.config.main_window_x _window_y = settings.config.main_window_y @@ -118,6 +139,48 @@ class Window(Gtk.ApplicationWindow): def _load_interactive_debug(self): self.set_interactive_debugging(True) + def _setup_window_toggle_event(self) -> None: + hidebound = None + if not self.guake_key or not self._display_manager() == 'X11': + return + + try: + import gi + gi.require_version('Keybinder', '3.0') + from gi.repository import Keybinder + + Keybinder.init() + Keybinder.set_use_cooked_accelerators(False) + except (ImportError, ValueError) as e: + logger.warning(e) + logger.warning('Unable to load Keybinder module. This means the hide_window shortcut will be unavailable') + + return + + # Attempt to grab a global hotkey for hiding the window. + # If we fail, we'll never hide the window, iconifying instead. + try: + hidebound = Keybinder.bind(self.guake_key, self._on_toggle_window, self) + except (KeyError, NameError) as e: + logger.warning(e) + + if not hidebound: + logger.debug('Unable to bind hide_window key, another instance/window has it.') + self.hidefunc = self.iconify + else: + self.hidefunc = self.hide + + def _on_toggle_window(self, data, window): + """Handle a request to hide/show the window""" + if not window.get_property('visible'): + window.show() + # Note: Needed to properly grab widget focus when set_skip_taskbar_hint set to True + window.present() + # NOTE: Need here to enforce sticky after hide and reshow. + window.stick() + else: + self.hidefunc() + def start(self): Gtk.main() diff --git a/src/libs/ipc_server.py b/src/libs/ipc_server.py index ba412d2..eacde83 100644 --- a/src/libs/ipc_server.py +++ b/src/libs/ipc_server.py @@ -16,7 +16,7 @@ class IPCServer(Singleton): """ Create a listener so that other {APP_NAME} instances send requests back to existing instance. """ def __init__(self, ipc_address: str = '127.0.0.1', conn_type: str = "socket"): self.is_ipc_alive = False - self._ipc_port = 4848 + self._ipc_port = 0 # Use 0 to let Listener chose port self._ipc_address = ipc_address self._conn_type = conn_type self._ipc_authkey = b'' + bytes(f'{APP_NAME}-ipc', 'utf-8') diff --git a/src/libs/settings/manager.py b/src/libs/settings/manager.py index 5b77c38..e4e1c87 100644 --- a/src/libs/settings/manager.py +++ b/src/libs/settings/manager.py @@ -91,7 +91,9 @@ class SettingsManager(StartCheckMixin, Singleton): try: with open(self._KEY_BINDINGS_FILE) as file: - bindings = json.load(file)["keybindings"] + bindings = json.load(file)["keybindings"] + self._guake_key = bindings["guake_key"] + keybindings.configure(bindings) except Exception as e: print( f"Settings Manager: {self._KEY_BINDINGS_FILE}\n\t\t{repr(e)}" ) @@ -155,6 +157,7 @@ class SettingsManager(StartCheckMixin, Singleton): def get_window_icon(self) -> str: return self._WINDOW_ICON def get_home_path(self) -> str: return self._USER_HOME def get_starting_files(self) -> list: return self._starting_files + def get_guake_key(self) -> tuple: return self._guake_key def get_starting_args(self): return self.args, self.unknownargs diff --git a/user_config/usr/share/app_name/key-bindings.json b/user_config/usr/share/app_name/key-bindings.json index 8eb8187..9e47bfb 100644 --- a/user_config/usr/share/app_name/key-bindings.json +++ b/user_config/usr/share/app_name/key-bindings.json @@ -1,6 +1,7 @@ { "keybindings": { "help" : "F1", + "guake_key" : "", "rename-files" : ["F2", "e"], "open-terminal" : "F4", "refresh-tab" : ["F5", "r"], diff --git a/user_config/usr/share/app_name/stylesheet.css b/user_config/usr/share/app_name/stylesheet.css index ecac4cd..7d3c240 100644 --- a/user_config/usr/share/app_name/stylesheet.css +++ b/user_config/usr/share/app_name/stylesheet.css @@ -6,6 +6,7 @@ popover > box, .body-container, .center-container, .header-container, +.footer-container, .left-containerm, .right-container { background: rgba(0, 0, 0, 0.0);