Compare commits

..

1 Commits

Author SHA1 Message Date
619fae8a20 Merge pull request 'develop' (#1) from develop into master
Reviewed-on: #1
2024-02-11 01:53:00 +00:00
66 changed files with 365 additions and 859 deletions

View File

@@ -3,13 +3,11 @@ 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)
### 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/<app name> can go to ~/.config folder if prefered.
* In additiion, place the plugins folder in the same app folder you moved to /usr/share/<app name> or ~/.config/<app name> .
There are a "\<change_me\>" strings and files that need to be set according to your app's name located at:
@@ -22,4 +20,4 @@ There are a "\<change_me\>" 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.
The logic follows Debian Dpkg packaging and its placement logic.

View File

@@ -1,31 +1,2 @@
### Note
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:<Control>f"],
f"{name}||do_save:<Control>s"] # Bind keys with method and key pare using list. Must pass "name" like shown with delimiter to its right.
}
```
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.

View File

@@ -1,13 +0,0 @@
{
"reportUndefinedVariable": false,
"reportUnusedVariable": false,
"reportUnusedImport": true,
"reportDuplicateImport": true,
"executionEnvironments": [
{
"root": "./src/versions/solarfm-0.0.1/solarfm"
}
],
"venvPath": ".",
"venv": ".venv"
}

View File

@@ -1,7 +1,4 @@
PyGObject==3.40.1
pygobject-stubs --no-cache-dir --config-settings=config=Gtk3,Gdk3,Soup2
setproctitle==1.2.2
pyxdg==0.27
psutil==5.8.0
pycryptodome==3.20.0
sqlmodel==0.0.19
PyGObject
pyxdg
setproctitle
sqlmodel

View File

@@ -1,6 +1,5 @@
# Python imports
import builtins
import traceback
import threading
import sys
@@ -12,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 import SettingsManager
from libs.settings_manager.manager import SettingsManager
@@ -32,22 +31,11 @@ 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...
# __builtins__.update({"event_system": Builtins()})
builtins.APP_NAME = "<change_me>"
builtins.app_name = "<change_me>"
builtins.keybindings = Keybindings()
builtins.event_system = EventSystem()
@@ -58,15 +46,12 @@ 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
builtins.call_chain = call_chain_wrapper
@@ -75,6 +60,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

View File

@@ -1,3 +1,3 @@
"""
Src Package.
"""
Start of package.
"""

View File

@@ -17,9 +17,8 @@ from app import Application
def main():
setproctitle(f'{APP_NAME}')
settings_manager.set_start_load_time()
def main(args, unknownargs):
setproctitle(f'{app_name}')
if args.debug == "true":
settings_manager.set_debug(True)
@@ -28,7 +27,7 @@ def main():
settings_manager.set_trace_debug(True)
settings_manager.do_dirty_start_check()
Application()
Application(args, unknownargs)
@@ -37,20 +36,19 @@ 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()
main(args, unknownargs)
except Exception as e:
traceback.print_exc()
quit()

View File

@@ -19,29 +19,27 @@ class AppLaunchException(Exception):
class Application:
""" docstring for Application. """
def __init__(self):
def __init__(self, args, unknownargs):
super(Application, self).__init__()
if not settings_manager.is_trace_debug():
self.load_ipc()
self.load_ipc(args, unknownargs)
self.setup_debug_hook()
Window().main()
Window(args, unknownargs).main()
def load_ipc(self):
args, \
unknownargs = settings_manager.get_starting_args()
ipc_server = IPCServer()
def load_ipc(self, args, unknownargs):
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):
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:
@@ -58,7 +56,7 @@ class Application:
try:
# kill -SIGUSR2 <pid> from Linux/Unix or SIGBREAK signal from Windows
signal.signal(
vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR2"),
vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR1"),
debug_signal_handler
)
except ValueError:

View File

@@ -1,3 +1,3 @@
"""
Core Package
Core Module
"""

View File

@@ -1,33 +0,0 @@
# 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]

View File

@@ -1,3 +1,3 @@
"""
Containers Package
"""
Containers Module
"""

View File

@@ -22,7 +22,7 @@ class BaseContainer(Gtk.Box):
self._subscribe_to_events()
self._load_widgets()
self.show()
self.show_all()
def _setup_styling(self):
@@ -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())

View File

@@ -23,7 +23,7 @@ class BodyContainer(Gtk.Box):
self._subscribe_to_events()
self._load_widgets()
self.show()
self.show_all()
def _setup_styling(self):

View File

@@ -21,8 +21,6 @@ class CenterContainer(Gtk.Box):
self._subscribe_to_events()
self._load_widgets()
self.show()
def _setup_styling(self):
self.set_orientation(Gtk.Orientation.VERTICAL)
@@ -33,6 +31,7 @@ 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):
@@ -41,9 +40,6 @@ 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() )

View File

@@ -6,8 +6,7 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from ..widgets.controls.open_files_button import OpenFilesButton
from ..widgets.controls.transparency_scale import TransparencyScale
from ..widgets.transparency_scale import TransparencyScale
@@ -33,19 +32,15 @@ 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):
button = Gtk.Button(label = "Interactive Debug")
button = Gtk.Button(label = "Interactive Debug")
button.connect("clicked", self._interactive_debug)
self.add( OpenFilesButton() )
self.add( TransparencyScale() )
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_all()
event_system.emit("load_interactive_debug")

View File

@@ -18,8 +18,6 @@ class LeftContainer(Gtk.Box):
self._subscribe_to_events()
self._load_widgets()
self.show()
def _setup_styling(self):
self.set_orientation(Gtk.Orientation.VERTICAL)
@@ -30,7 +28,8 @@ 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):
...
...

View File

@@ -6,7 +6,6 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from ..widgets.vte_widget import VteWidget
@@ -19,8 +18,6 @@ class RightContainer(Gtk.Box):
self._subscribe_to_events()
self._load_widgets()
self.show()
def _setup_styling(self):
self.set_orientation(Gtk.Orientation.VERTICAL)
@@ -31,8 +28,8 @@ 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):
vte_widget = VteWidget()
self.add( vte_widget )
...

View File

@@ -1,3 +1,3 @@
"""
Controllers Package
Controllers Module
"""

View File

@@ -1,4 +1,5 @@
# Python imports
import os
# Lib imports
import gi
@@ -17,20 +18,27 @@ from .bridge_controller import BridgeController
class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
""" docstring for BaseController. """
def __init__(self, args, unknownargs):
self.setup_controller_data()
def __init__(self):
self._setup_controller_data()
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_controllers()
self._load_plugins_and_files()
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)
logger.info(f"Made it past {self.__class__} loading...")
settings_manager.set_end_load_time()
settings_manager.log_load_time()
def _setup_styling(self):
@@ -42,28 +50,20 @@ 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()
def _load_plugins_and_files(self):
args, unknownargs = settings_manager.get_starting_args()
if args.no_plugins == "false":
self.plugins_controller.pre_launch_plugins()
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() )
def setup_builder_and_container(self):
self.builder = Gtk.Builder()
self.builder.add_from_file(settings_manager.get_glade_file())
self.builder.expose_object("main_window", self.window)
settings_manager.set_builder(self.builder)

View File

@@ -7,48 +7,23 @@ from shutil import which
# Application imports
from plugins.plugins_controller import PluginsController
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:
self.window = settings_manager.get_main_window()
self.builder = BuilderWrapper()
self.plugins_controller = PluginsController()
def setup_controller_data(self) -> None:
self.window = settings_manager.get_main_window()
self.builder = None
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._collect_files_dirs()
self._load_glade_file()
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://', '')}" )
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)
settings_manager.set_starting_files(files)
self.setup_builder_and_container()
self.plugins = PluginsController()
def get_base_container(self):
return self.base_container

View File

@@ -10,6 +10,8 @@ import base64
class BridgeController:
def __init__(self):
self.opened_files = {}
self._setup_signals()
self._subscribe_to_events()
@@ -18,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}")

View File

@@ -1,3 +1,3 @@
"""
Widgets Package
"""
Widgets Module
"""

View File

@@ -1,3 +0,0 @@
"""
Widgets.Controls Package
"""

View File

@@ -1,84 +0,0 @@
# 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 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

View File

@@ -1,72 +0,0 @@
# 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

View File

@@ -37,12 +37,12 @@ class TransparencyScale(Gtk.Scale):
def _load_widgets(self):
adjust = self.get_adjustment()
adjust.set_lower(0)
adjust.set_upper(100)
adjust.set_upper(99)
adjust.set_value(settings.theming.transparency)
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")
event_system.emit("update_transparency")

View File

@@ -1,125 +0,0 @@
# 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'))

View File

@@ -1,3 +1,3 @@
"""
WebKit2 UI Package
WebKit2 UI Module
"""

View File

@@ -9,14 +9,17 @@ from gi.repository import Gdk
from gi.repository import WebKit2
# Application imports
from libs.settings.other.webkit_ui_settings import WebkitUISettings
from libs.dto.event import Event
from libs.data_types import Event
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()
@@ -24,6 +27,10 @@ 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)
@@ -31,8 +38,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() )
@@ -47,6 +54,7 @@ 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")
@@ -56,14 +64,45 @@ 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, message, mtype):
def ui_message(self, mtype, message):
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)
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}")

View File

@@ -0,0 +1,64 @@
# 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)

View File

@@ -11,7 +11,6 @@ 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
@@ -24,17 +23,16 @@ class ControllerStartExceptiom(Exception):
class Window(Gtk.ApplicationWindow):
""" docstring for Window. """
def __init__(self):
def __init__(self, args, unknownargs):
super(Window, self).__init__()
settings_manager.set_main_window(self)
self._status_icon = None
self._controller = None
self._controller = None
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self._load_widgets(args, unknownargs)
self._set_window_data()
self._set_size_constraints()
@@ -43,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
@@ -60,15 +58,14 @@ 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):
def _load_widgets(self, args, unknownargs):
if settings_manager.is_debug():
self.set_interactive_debugging(True)
self._controller = BaseController()
self._status_icon = StatusIcon()
self._controller = BaseController(args, unknownargs)
if not self._controller:
raise ControllerStartException("BaseController exited and doesn't exist...")
@@ -93,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()
@@ -110,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()

View File

@@ -1,3 +1,3 @@
"""
Libs Package
"""
Utils module
"""

View File

@@ -0,0 +1,5 @@
"""
Dasta Class module
"""
from .event import Event

View File

@@ -1,6 +0,0 @@
"""
DB Package
"""
from .models import User
from .db import DB

View File

@@ -18,7 +18,7 @@ def debug_signal_handler(signal, frame):
rpdb2.start_embedded_debugger("foobar", True, True)
rpdb2.setbreak(depth=1)
return
except Exception:
except StandardError:
...
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 Exception as ex:
except StandardError as ex:
...
try:
@@ -34,15 +34,7 @@ def debug_signal_handler(signal, frame):
logger.debug("\n\nStarting PuDB debugger...\n\n")
set_trace(paused = True)
return
except Exception as ex:
...
try:
import ipdb
logger.debug("\n\nStarting IPDB debugger...\n\n")
ipdb.set_trace()
return
except Exception as ex:
except StandardError as ex:
...
try:
@@ -50,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 Exception as ex:
except StandardError as ex:
...
try:
import code
code.interact()
except Exception as ex:
logger.debug(f"{ex}, returning to normal program flow...")
except StandardError as ex:
logger.debug(f"{ex}, returning to normal program flow...")

View File

@@ -1,5 +0,0 @@
"""
Dasta Class Package
"""
from .event import Event

View File

@@ -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":
@@ -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:
@@ -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 self.is_ipc_alive:
while True:
try:
conn = listener.accept()
start_time = time.perf_counter()
@@ -67,22 +67,19 @@ class IPCServer(Singleton):
listener.close()
def _handle_ipc_message(self, conn, start_time) -> None:
while self.is_ipc_alive:
while True:
msg = conn.recv()
logger.debug(msg)
if "FILE|" in msg:
file = msg.split("FILE|")[1].strip()
if file:
event_system.emit("handle-file-from-ipc", file)
conn.close()
break
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
@@ -132,4 +129,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) )

View File

@@ -1,3 +1,3 @@
"""
Libs.Mixins Package
Utils/Mixins module
"""

View File

@@ -67,4 +67,4 @@ class DnDMixin:
files.append(gfile)
event_system.emit('set-pre-drop-dnd', (files,))
event_system.emit('set_pre_drop_dnd', (files,))

View File

@@ -1,8 +1,6 @@
# Python imports
# Lib imports
import gi
from gi.repository import GLib
# Application imports
@@ -10,22 +8,13 @@ from gi.repository import GLib
class IPCSignalsMixin:
""" IPCSignalsMixin handle messages from another starting {APP_NAME} process. """
""" IPCSignalsMixin handle messages from another starting solarfm process. """
def print_to_console(self, message = None):
def print_to_console(self, message=None):
logger.debug(message)
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_file_from_ipc(self, path: str) -> None:
logger.debug(f"File From IPC: {path}")
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)
def handle_dir_from_ipc(self, path: str) -> None:
logger.debug(f"Dir From IPC: {path}")

View File

@@ -68,11 +68,11 @@ class KeyboardSignalsMixin:
if mapping:
self.handle_mapped_key_event(mapping)
else:
self.handle_as_key_event_scope(keyname)
self.handle_as_key_event_scope(mapping)
def handle_mapped_key_event(self, mapping):
try:
self.handle_as_controller_scope(mapping)
self.handle_as_controller_scope()
except Exception:
self.handle_as_plugin_scope(mapping)
@@ -86,11 +86,13 @@ class KeyboardSignalsMixin:
sender = ""
eve_type = mapping
self.handle_key_event_system(sender, eve_type)
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}")
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, keyname)
self.handle_key_event_system(None, mapping)
def handle_key_event_system(self, sender, eve_type):
event_system.emit(eve_type)

View File

@@ -1,4 +0,0 @@
"""
Settings Package
"""
from .manager import SettingsManager

View File

@@ -1,3 +0,0 @@
"""
Settings.Other Package
"""

View File

@@ -0,0 +1,4 @@
"""
Settings module
"""
from .manager import SettingsManager

View File

@@ -1,6 +1,5 @@
# Python imports
import inspect
import time
import json
import zipfile
@@ -23,35 +22,35 @@ class MissingConfigError(Exception):
class SettingsManager(StartCheckMixin, Singleton):
def __init__(self):
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._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._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._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._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"
# 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"
# with zipfile.ZipFile("files.zip", mode="r", allowZip64=True) as zf:
@@ -80,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):
@@ -103,25 +102,23 @@ 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: tuple = (0, 0, 0, 0.0)
self.settings: Settings = None
self._main_window = None
self._builder = None
self.PAINT_BG_COLOR = (0, 0, 0, 0.0)
self._trace_debug: bool = False
self._debug: bool = False
self._dirty_start: bool = False
self._passed_in_file: bool = False
self._starting_files: list = []
self._trace_debug = False
self._debug = False
self._dirty_start = False
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:
...
@@ -131,6 +128,7 @@ 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 = []
@@ -154,45 +152,29 @@ 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) -> list: return self._starting_files
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
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_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 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
def set_debug(self, debug: bool):
self._debug = debug
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):
def call_method(self, target_class = None, _method_name = None, data = 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_trace_debug(self, trace_debug):
self._trace_debug = trace_debug
def set_debug(self, debug):
self._debug = debug
def load_settings(self):
if not path.exists(self._CONFIG_FILE):
self.settings = Settings()

View File

@@ -1,8 +1,8 @@
"""
Settings.Options Package
Options module
"""
from .settings import Settings
from .config import Config
from .filters import Filters
from .theming import Theming
from .debugging import Debugging
from .debugging import Debugging

View File

@@ -0,0 +1,3 @@
"""
Settings Other module
"""

View File

@@ -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}")
self.set_user_agent(f"{app_name}")

View File

@@ -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)

View File

@@ -1,67 +0,0 @@
# 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")

View File

@@ -15,14 +15,13 @@ 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
pre_launch: bool = False
path: str = None
name: str = None
author: str = None
version: str = None
support: str = None
requests:{} = None
reference: type = None
class ManifestProcessor:
@@ -47,29 +46,23 @@ 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 requests:
if "pass_events" in keys:
if requests["pass_events"] in ["true"]:
loading_data["pass_events"] = True
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 "bind_keys" in keys:
if isinstance(requests["bind_keys"], list):
loading_data["bind_keys"] = requests["bind_keys"]
if "pass_ui_objects" in keys:
if isinstance(requests["pass_ui_objects"], list):
loading_data["pass_ui_objects"] = [ self._builder.get_object(obj) for obj in requests["pass_ui_objects"] ]
return self._plugin, loading_data
def is_pre_launch(self):
return self._plugin.pre_launch

View File

@@ -10,7 +10,6 @@ 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
@@ -36,23 +35,11 @@ class PluginsController:
self._plugins_dir_watcher = None
self._plugin_collection = []
self._plugin_manifests = {}
self._load_manifests()
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
}
def launch_plugins(self) -> None:
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) \
@@ -65,47 +52,21 @@ class PluginsController:
Gio.FileMonitorEvent.MOVED_OUT]:
self.reload_plugins(file)
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:
def load_plugins(self, file: str = None) -> None:
logger.info(f"Loading plugins...")
parent_path = os.getcwd()
for key in plugin_manifests:
target_manifest = plugin_manifests[key]
path, folder, manifest = target_manifest["path"], target_manifest["folder"], target_manifest["manifest"]
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")
target = join(path, "plugin.py")
manifest = ManifestProcessor(path, self._builder)
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)
if is_pre_launch:
self.execute_plugin(module, plugin, loading_data)
else:
GLib.idle_add(self.execute_plugin, *(module, plugin, loading_data))
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())

View File

@@ -43,6 +43,6 @@
/* Other message text colors */
.error-txt { color: rgb(170, 18, 18); }
.warning-txt { color: rgb(255, 168, 0); }
.success=txt { color: rgb(136, 204, 39); }
.errorTxt { color: rgb(170, 18, 18); }
.warningTxt { color: rgb(255, 168, 0); }
.successTxt { color: rgb(136, 204, 39); }

View File

@@ -1,7 +1,6 @@
html, body {
display: block;
// background-color: #32383e00;
background-color: rgba(39, 43, 52, 0.64);
background-color: #32383e00;
color: #ffffff;
text-wrap: wrap;
}

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -1,24 +1,23 @@
{
"keybindings": {
"help" : "F1",
"rename-files" : ["F2", "<Control>e"],
"open-terminal" : "F4",
"refresh-tab" : ["F5", "<Control>r"],
"delete-files" : "Delete",
"tggl-top-main-menubar" : "Alt_L",
"tggl-top-main-menubar" : "<Control>0",
"trash-files" : "<Shift><Control>t",
"tear-down" : "<Control>q",
"go-up" : "<Control>Up",
"go-home" : "<Control>slash",
"grab-focus-path-entry" : "<Control>l",
"open-files" : "<Control>o",
"show-hide-hidden-files" : "<Control>h",
"keyboard-create-tab" : "<Control>t",
"keyboard-close-tab" : "<Control>w",
"keyboard-copy-files" : "<Control>c",
"keyboard-cut-files" : "<Control>x",
"paste-files" : "<Control>v",
"show-new-file-menu" : "<Control>n"
"rename_files" : ["F2", "<Control>e"],
"open_terminal" : "F4",
"refresh_tab" : ["F5", "<Control>r"],
"delete_files" : "Delete",
"tggl_top_main_menubar" : "Alt_L",
"trash_files" : "<Shift><Control>t",
"tear_down" : "<Control>q",
"go_up" : "<Control>Up",
"go_home" : "<Control>slash",
"grab_focus_path_entry" : "<Control>l",
"open_files" : "<Control>o",
"show_hide_hidden_files" : "<Control>h",
"keyboard_create_tab" : "<Control>t",
"keyboard_close_tab" : "<Control>w",
"keyboard_copy_files" : "<Control>c",
"keyboard_cut_files" : "<Control>x",
"paste_files" : "<Control>v",
"show_new_file_menu" : "<Control>n"
}
}

View File

@@ -1,18 +1,3 @@
/* ---- Make most desired things base transparent ---- */
/* ---- Make most desired things base transparent ---- */
popover,
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);
}
.base-container {
margin: 10px;
}
@@ -143,4 +128,3 @@ 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); }