develop #13

Merged
itdominator merged 5 commits from develop into master 2023-11-12 06:51:24 +00:00
15 changed files with 144 additions and 128 deletions
Showing only changes of commit 6fe4db7c63 - Show all commits

View File

@ -7,12 +7,12 @@ import sys
# Application imports
from utils.event_system import EventSystem
from utils.endpoint_registry import EndpointRegistry
from utils.keybindings import Keybindings
from utils.logger import Logger
from utils.settings_manager.manager import SettingsManager
# NOTE: Threads WILL NOT die with parent's destruction.
def threaded_wrapper(fn):
def wrapper(*args, **kwargs):
@ -39,7 +39,6 @@ def sizeof_fmt_def(num, suffix="B"):
builtins.app_name = "SolarFM"
builtins.keybindings = Keybindings()
builtins.event_system = EventSystem()
builtins.endpoint_registry = EndpointRegistry()
builtins.settings_manager = SettingsManager()
settings_manager.load_settings()
@ -52,7 +51,7 @@ builtins.logger = Logger(settings_manager.get_home_config_path(), \
builtins.threaded = threaded_wrapper
builtins.daemon_threaded = daemon_threaded_wrapper
builtins.sizeof_fmt = sizeof_fmt_def
builtins.event_sleep_time = 0.05
def custom_except_hook(exc_type, exc_value, exc_traceback):
@ -62,5 +61,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

View File

@ -25,7 +25,7 @@ class Application(IPCServer):
try:
self.create_ipc_listener()
except Exception:
...
self.socket_realization_check()
if not self.is_ipc_alive:
for arg in unknownargs + [args.new_tab,]:
@ -35,6 +35,16 @@ class Application(IPCServer):
raise AppLaunchException(f"{app_name} IPC Server Exists: Will send path(s) to it and close...")
self.setup_debug_hook()
Window(args, unknownargs)
def socket_realization_check(self):
self.send_test_ipc_message()
self.create_ipc_listener()
def setup_debug_hook(self):
try:
# kill -SIGUSR2 <pid> from Linux/Unix or SIGBREAK signal from Windows
signal.signal(
@ -44,5 +54,3 @@ class Application(IPCServer):
except ValueError:
# Typically: ValueError: signal only works in main thread
...
Window(args, unknownargs)

View File

@ -65,9 +65,11 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
FileSystemActions()
def _subscribe_to_events(self):
event_system.subscribe("shutting_down", self._shutting_down)
event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc)
event_system.subscribe("generate_file_views", self._generate_file_views)
event_system.subscribe("clear_notebooks", self.clear_notebooks)
event_system.subscribe("set_window_title", self._set_window_title)
event_system.subscribe("unset_selected_files_views", self._unset_selected_files_views)
event_system.subscribe("get_current_state", self.get_current_state)
@ -107,6 +109,10 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
FileExistsWidget()
SaveLoadWidget()
def _shutting_down(self):
if not settings_manager.is_trace_debug():
self.fm_controller.save_state()
def reload_plugins(self, widget=None, eve=None):
self.plugins.reload_plugins()
@ -162,28 +168,22 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
event_system.emit("tear_down")
@endpoint_registry.register(rule="go_home")
def go_home(self, widget=None, eve=None):
self.builder.get_object("go_home").released()
@endpoint_registry.register(rule="refresh_tab")
def refresh_tab(self, widget=None, eve=None):
self.builder.get_object("refresh_tab").released()
@endpoint_registry.register(rule="go_up")
def go_up(self, widget=None, eve=None):
self.builder.get_object("go_up").released()
@endpoint_registry.register(rule="grab_focus_path_entry")
def grab_focus_path_entry(self, widget=None, eve=None):
self.builder.get_object("path_entry").grab_focus()
@endpoint_registry.register(rule="tggl_top_main_menubar")
def tggl_top_main_menubar(self, widget=None, eve=None):
top_main_menubar = self.builder.get_object("top_main_menubar")
top_main_menubar.hide() if top_main_menubar.is_visible() else top_main_menubar.show()
@endpoint_registry.register(rule="open_terminal")
def open_terminal(self, widget=None, eve=None):
wid, tid = self.fm_controller.get_active_wid_and_tid()
tab = self.get_fm_window(wid).get_tab_by_id(tid)

View File

@ -1,7 +1,6 @@
# Python imports
import os
import subprocess
from dataclasses import dataclass
# Lib imports
import gi
@ -9,55 +8,13 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from .sfm_builder import SFMBuilder
from .widgets.dialogs.message_widget import MessageWidget
from .widgets.dialogs.user_pass_widget import UserPassWidget
from shellfm.windows.controller import WindowController
from utils.types.state import State
from plugins.plugins_controller import PluginsController
@dataclass(slots=True)
class State:
fm_controller: any = None
notebooks: any = None
wid: int = None
tid: int = None
tab: type = None
icon_grid: gi.overrides.Gtk.IconView = None
store: gi.overrides.Gtk.ListStore = None
uris: [] = None
uris_raw: [] = None
selected_files: [] = None
to_copy_files: [] = None
to_cut_files: [] = None
message_dialog: type = None
user_pass_dialog: type = None
class SFMBuilder(Gtk.Builder):
"""docstring for SFMBuilder."""
def __init__(self):
super(SFMBuilder, 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(SFMBuilder, 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(SFMBuilder, self).expose_object(id, object)
def dereference_object(self, id: str) -> None:
del self.objects[id]
from shellfm.windows.controller import WindowController

View File

@ -85,7 +85,7 @@ class WindowMixin(TabMixin):
self.set_window_title()
if eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 1: # l-click
if self.ctrl_down:
if eve.state & Gdk.ModifierType.CONTROL_MASK:
self.dnd_left_primed = 0
if self.single_click_open: # FIXME: need to find a way to pass the model index

View File

@ -0,0 +1,33 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
class SFMBuilder(Gtk.Builder):
"""docstring for SFMBuilder."""
def __init__(self):
super(SFMBuilder, 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(SFMBuilder, 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(SFMBuilder, self).expose_object(id, object)
def dereference_object(self, id: str) -> None:
del self.objects[id]

View File

@ -77,7 +77,7 @@ class UIMixin(PaneMixin, WindowMixin):
scroll_win = notebook.get_children()[-1]
icon_grid = scroll_win.get_children()[0]
self._focus_last_visible_notebook(icon_grid)
# self._focus_last_visible_notebook(icon_grid)
except UIMixinException as e:
logger.info("\n: The saved session might be missing window data! :\nLocation: ~/.config/solarfm/session.json\nFix: Back it up and delete it to reset.\n")
logger.debug(repr(e))

View File

@ -80,7 +80,7 @@ class WindowMixin(TabMixin):
self.set_window_title()
if eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 1: # l-click
if self.ctrl_down:
if eve.state & Gdk.ModifierType.CONTROL_MASK:
self.dnd_left_primed = 0
if self.single_click_open: # FIXME: need to find a way to pass the model index

View File

@ -20,8 +20,6 @@ class IconGridWidget(Gtk.IconView):
def __init__(self):
super(IconGridWidget, self).__init__()
# self._store = None
self._setup_styling()
self._setup_signals()
self._set_up_dnd()

View File

@ -89,10 +89,6 @@ class Window(Gtk.ApplicationWindow):
def _tear_down(self, widget = None, eve = None):
if not settings_manager.is_trace_debug():
self._controller.fm_controller.save_state()
event_system.emit("shutting_down")
settings_manager.clear_pid()
time.sleep(event_sleep_time)
Gtk.main_quit()

View File

@ -24,32 +24,12 @@ class PluginBase:
self._event_system = None
def set_fm_event_system(self, fm_event_system):
def run(self):
"""
Requests Key: 'pass_fm_events': "true"
Must define in plugin if "pass_fm_events" is set to "true" string.
Must define regardless if needed and can 'pass' if plugin doesn't need it.
Is intended to be used to setup internal signals or custom Gtk Builders/UI logic.
"""
self._event_system = fm_event_system
def set_ui_object_collection(self, ui_objects):
"""
Requests Key: "pass_ui_objects": [""]
Request reference to a UI component. Will be passed back as array to plugin.
Must define in plugin if set and an array of valid glade UI IDs is given.
"""
self._ui_objects = ui_objects
def clear_children(self, widget: type) -> None:
""" Clear children of a gtk widget. """
for child in widget.get_children():
widget.remove(child)
def subscribe_to_events(self):
self._event_system.subscribe("update_state_info_plugins", self._update_fm_state_info)
def _update_fm_state_info(self, state):
self._fm_state = state
raise PluginBaseException("Method hasn't been overriden...")
def generate_reference_ui_element(self):
"""
@ -59,12 +39,26 @@ class PluginBase:
"""
raise PluginBaseException("Method hasn't been overriden...")
def run(self):
def set_ui_object_collection(self, ui_objects):
"""
Must define regardless if needed and can 'pass' if plugin doesn't need it.
Is intended to be used to setup internal signals or custom Gtk Builders/UI logic.
Requests Key: "pass_ui_objects": [""]
Request reference to a UI component. Will be passed back as array to plugin.
Must define in plugin if set and an array of valid glade UI IDs is given.
"""
raise PluginBaseException("Method hasn't been overriden...")
self._ui_objects = ui_objects
def set_fm_event_system(self, fm_event_system):
"""
Requests Key: 'pass_fm_events': "true"
Must define in plugin if "pass_fm_events" is set to "true" string.
"""
self._event_system = fm_event_system
def subscribe_to_events(self):
self._event_system.subscribe("update_state_info_plugins", self._update_fm_state_info)
def _update_fm_state_info(self, state):
self._fm_state = state
def _connect_builder_signals(self, caller_class, builder):
classes = [caller_class]
@ -94,3 +88,9 @@ class PluginBase:
reload_package_recursive(path, module_dict[path.stem].__dict__)
reload_package_recursive(Path(plugin_path).parent, module_dict_main["module_dict_main"])
def clear_children(self, widget: type) -> None:
""" Clear children of a gtk widget. """
for child in widget.get_children():
widget.remove(child)

View File

@ -1,22 +0,0 @@
# Python imports
# Lib imports
# Application imports
from .singleton import Singleton
class EndpointRegistry(Singleton):
def __init__(self):
self._endpoints = {}
def register(self, rule, **options):
def decorator(f):
self._endpoints[rule] = f
return f
return decorator
def get_endpoints(self):
return self._endpoints

View File

@ -44,12 +44,12 @@ class IPCServer(Singleton):
os.unlink(self._ipc_address)
listener = Listener(address = self._ipc_address, family = "AF_UNIX", authkey = self._ipc_authkey)
elif "unsecured" not in self._conn_type:
listener = Listener((self._ipc_address, self._ipc_port), authkey = self._ipc_authkey)
else:
listener = Listener((self._ipc_address, self._ipc_port))
self.is_ipc_alive = True
self._run_ipc_loop(listener)
@ -61,15 +61,14 @@ class IPCServer(Singleton):
start_time = time.perf_counter()
GLib.idle_add(self._handle_ipc_message, *(conn, start_time,))
except Exception as e:
...
logger.debug( repr(e) )
listener.close()
def _handle_ipc_message(self, conn, start_time) -> None:
while True:
msg = conn.recv()
if settings_manager.is_debug():
print(msg)
logger.debug(msg)
if "FILE|" in msg:
file = msg.split("FILE|")[1].strip()
@ -103,6 +102,25 @@ class IPCServer(Singleton):
conn.send(message)
conn.close()
except ConnectionRefusedError as e:
print("Connection refused...")
logger.error("Connection refused...")
except Exception as e:
print(repr(e))
logger.error( repr(e) )
def send_test_ipc_message(self, message: str = "Empty Data...") -> None:
try:
if self._conn_type == "socket":
conn = Client(address=self._ipc_address, family="AF_UNIX", authkey=self._ipc_authkey)
elif "unsecured" not in self._conn_type:
conn = Client((self._ipc_address, self._ipc_port), authkey=self._ipc_authkey)
else:
conn = Client((self._ipc_address, self._ipc_port))
conn.send(message)
conn.close()
except ConnectionRefusedError as e:
if self._conn_type == "socket":
logger.error("IPC Socket no longer valid.... Removing.")
os.unlink(self._ipc_address)
except Exception as e:
logger.error( repr(e) )

View File

@ -0,0 +1,3 @@
"""
Utils module
"""

View File

@ -0,0 +1,27 @@
# Python imports
from dataclasses import dataclass
# Lib imports
from gi.overrides.Gtk import IconView
from gi.overrides.Gtk import ListStore
# Application imports
@dataclass(slots=True)
class State:
fm_controller: any = None
notebooks: any = None
wid: int = None
tid: int = None
tab: type = None
icon_grid: IconView = None
store: ListStore = None
uris: list = None
uris_raw: list = None
selected_files: list = None
to_copy_files: list = None
to_cut_files: list = None
message_dialog: type = None
user_pass_dialog: type = None