Compare commits

...

31 Commits

Author SHA1 Message Date
849e7611ca Added code view widget and base command system; updated keybinding system 2025-12-14 03:20:03 -06:00
2c453bc621 Fixed IPC issues with passing paths back to instance 2025-12-10 20:09:32 -06:00
530fe7c3ab Updated jeybinding and restructured css 2025-11-30 19:51:04 -06:00
5e5cc50ba8 Fixed empty vte commit error 2025-11-30 00:59:37 -06:00
22736147e6 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 2025-11-29 23:22:03 -06:00
4c25ce297c Corrected css for popover box 2025-10-21 22:21:06 -05:00
60b55da973 Moved to use contextlib suppress pattern than empty exception blocks 2025-10-21 22:20:06 -05:00
7c0d87fd20 Slight call start restructuring, fixing css for popover box 2025-08-25 00:22:42 -05:00
4cd5a1f089 Fixing readme n requirements 2025-07-13 14:17:52 -05:00
18dc71dcb0 Adding generic doc string basecontroller 2025-07-13 14:15:25 -05:00
dd3e87f636 Adding call chain wrapper; cleanup; optimization 2024-12-22 00:50:32 -06:00
cca007db76 Added VTE widget; css changes; format cleanup 2024-11-08 22:46:07 -06:00
33c0827ca2 Moved args info to settings and restructured calls 2024-10-20 16:03:19 -05:00
f2b33066af Added stronger typing in settings; logging loading times; css changes to transparency 2024-10-20 15:20:18 -05:00
fafc1a985f Updated __init__ files; theming css changes, other 2024-10-14 21:57:18 -05:00
e2e9dc8c1f made default hiding transparency controls easier with restructured show calls 2024-08-31 22:27:11 -05:00
25b6b5305b update readme 2024-07-26 19:53:04 -05:00
62debf9ece extending plugins to load pre or post app start 2024-06-29 21:24:57 -05:00
cc5966dab2 Added status icon for system trays 2024-05-06 19:11:18 -05:00
e82e4fb1eb Updated a requirement 2024-05-03 01:11:52 -05:00
48bac7e791 Added a requirement; added a debug handler 2024-05-03 01:08:49 -05:00
b78fac0aa5 Fixed depricated exception type; fixed siguser type 2024-03-25 22:48:05 -05:00
bdb9c157f7 moved controls to dir; added open files button example; css transparency changes 2024-03-16 22:36:04 -05:00
a0f32a7c00 app_name --> APP_NAME 2024-02-29 18:50:34 -06:00
b1096055b7 Renamed settings folder; hyphenated event names 2024-02-25 16:19:14 -06:00
ea62eb280c Added builder wrapper due to plugin setup 2024-02-24 21:55:40 -06:00
cc8f62776d Fixed bindings; added bindings 2024-02-23 23:45:13 -06:00
2389f1d414 moved db stuff to own folder 2024-02-21 22:15:25 -06:00
d81bf3815a Removed logging item 2024-02-21 20:34:42 -06:00
1695f5bc5c Overode method to add debug logging 2024-02-16 20:43:09 -06:00
1245951da9 Cleanup of starting file collection 2024-02-16 20:13:36 -06:00
97 changed files with 2833 additions and 407 deletions

View File

@@ -3,11 +3,13 @@ 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:
@@ -20,4 +22,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,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:<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.
}
```

13
pyrightconfig.json Normal file
View File

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

View File

@@ -1,4 +1,7 @@
PyGObject
pyxdg
setproctitle
sqlmodel
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

View File

@@ -1,5 +1,6 @@
# Python imports
import builtins
import traceback
import threading
import sys
@@ -11,7 +12,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
@@ -31,11 +32,22 @@ 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()
@@ -46,12 +58,15 @@ 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
@@ -60,6 +75,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
sys.excepthook = custom_except_hook

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
# Python imports
from contextlib import suppress
import signal
import os
@@ -19,27 +20,40 @@ 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.setup_debug_hook()
Window(args, unknownargs).main()
def load_ipc(self, args, unknownargs):
ipc_server = IPCServer()
def run(self):
if not settings_manager.is_trace_debug():
if not self.load_ipc():
return
win = Window()
win.start()
def load_ipc(self):
args, \
unknownargs = settings_manager.get_starting_args()
ipc_server = IPCServer()
self.ipc_realization_check(ipc_server)
if ipc_server.is_ipc_alive:
return True
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)
logger.warning(f"{app_name} IPC Server Exists: Have sent path(s) to it and closing...")
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...")
if os.path.isdir(arg):
message = f"DIR|{arg}"
ipc_server.send_ipc_message(message)
return False
def ipc_realization_check(self, ipc_server):
try:
@@ -47,18 +61,12 @@ class Application:
except Exception:
ipc_server.send_test_ipc_message()
try:
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 <pid> 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:
# Typically: ValueError: signal only works in main thread
...

View File

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

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 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 Module
"""
Containers Package
"""

View File

@@ -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
@@ -22,7 +23,7 @@ class BaseContainer(Gtk.Box):
self._subscribe_to_events()
self._load_widgets()
self.show_all()
self.show()
def _setup_styling(self):
@@ -33,12 +34,13 @@ 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())
self.add(BodyContainer())
self.add(FooterContainer())
def _update_transparency(self):
self.ctx.add_class(f"mw_transparency_{settings.theming.transparency}")

View File

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

View File

@@ -21,9 +21,15 @@ class CenterContainer(Gtk.Box):
self._subscribe_to_events()
self._load_widgets()
self.show()
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")
@@ -31,7 +37,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):
@@ -40,6 +45,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() )

View File

@@ -0,0 +1,40 @@
# 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):
...

View File

@@ -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
@@ -21,26 +22,33 @@ 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):
...
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(TransparencyScale())
self.add( OpenFilesButton() )
self.add( TransparencyScale() )
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_all()

View File

@@ -18,9 +18,14 @@ class LeftContainer(Gtk.Box):
self._subscribe_to_events()
self._load_widgets()
self.show()
def _setup_styling(self):
self.set_orientation(Gtk.Orientation.VERTICAL)
self.set_vexpand(True)
ctx = self.get_style_context()
ctx.add_class("left-container")
@@ -28,8 +33,7 @@ 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,6 +6,7 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from ..widgets.vte_widget import VteWidget
@@ -18,9 +19,14 @@ class RightContainer(Gtk.Box):
self._subscribe_to_events()
self._load_widgets()
self.show()
def _setup_styling(self):
self.set_orientation(Gtk.Orientation.VERTICAL)
self.set_vexpand(True)
ctx = self.get_style_context()
ctx.add_class("right-container")
@@ -28,8 +34,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 Module
Controllers Package
"""

View File

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

View File

@@ -7,23 +7,49 @@ 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 = None
self.base_container = None
self.was_midified_key = False
self.ctrl_down = False
self.shift_down = False
self.alt_down = False
def _setup_controller_data(self) -> None:
self.window = settings_manager.get_main_window()
self.builder = BuilderWrapper()
self.plugins_controller = PluginsController()
self.setup_builder_and_container()
self.plugins = PluginsController()
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: return
settings_manager.set_is_starting_with_file(True)
settings_manager.set_starting_files(files)
def get_base_container(self):
return self.base_container
@@ -59,25 +85,23 @@ 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()
retcode = proc.wait()
retcode = proc.wait()

View File

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

View File

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

View File

@@ -0,0 +1,3 @@
"""
Code Package
"""

View File

@@ -0,0 +1,29 @@
# Python imports
# Lib imports
# Application imports
from .commands import *
class CommandSystem:
def __init__(self):
super(CommandSystem, self).__init__()
self.data: list = ()
def set_data(self, *args, **kwargs):
self.data = (args, kwargs)
def exec(self, command: str):
if not command in globals(): return
# method = getattr(self, command, None)
method = globals()[command]
args, kwargs = self.data
if kwargs:
method.execute(*args, kwargs)
else:
method.execute(*args)

View File

@@ -0,0 +1,12 @@
"""
Commands Package
"""
import os
__all__ = [
command.replace(".py", "") for command in os.listdir(
os.path.dirname(__file__)
) if "__init__" not in command
]

View File

@@ -0,0 +1,23 @@
# Python imports
# Lib imports
import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
# Application imports
def execute(
editor: GtkSource.View = None,
buffer: GtkSource.Buffer= None
):
logger.debug("Close File Command")
file = editor.files.new()
buffer = editor.get_buffer()
editor.set_buffer(file.buffer)
editor.files.remove_file(buffer)

View File

@@ -0,0 +1,19 @@
# Python imports
# Lib imports
import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
# Application imports
def execute(
editor: GtkSource.View = None,
buffer: GtkSource.Buffer= None
):
logger.debug("Line Up Command")
editor.emit("move-lines", True)

View File

@@ -0,0 +1,19 @@
# Python imports
# Lib imports
import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
# Application imports
def execute(
editor: GtkSource.View = None,
buffer: GtkSource.Buffer= None
):
logger.debug("Line Up Command")
editor.emit("move-lines", False)

View File

@@ -0,0 +1,26 @@
# Python imports
# Lib imports
import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
# Application imports
def execute(
editor: GtkSource.View = None,
buffer: GtkSource.Buffer= None
):
logger.debug("New File Command")
file = editor.files.new()
language = editor.language_manager \
.guess_language("file.txt", None)
file.buffer.set_language(language)
file.buffer.set_style_scheme(editor.syntax_theme)
editor.set_buffer(file.buffer)

View File

@@ -0,0 +1,36 @@
# Python imports
# Lib imports
import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
# Application imports
def execute(
editor: GtkSource.View = None,
buffer: GtkSource.Buffer= None
):
logger.debug("Open File(s) Command")
gfiles = event_system.emit_and_await("open_files")
if not gfiles: return
size = len(gfiles)
for i, gfile in enumerate(gfiles):
file = editor.files.new()
file.set_path(gfile)
language = editor.language_manager \
.guess_language(file.fname, None)
file.ftype = language
file.buffer.set_language(language)
file.buffer.set_style_scheme(editor.syntax_theme)
if i == (size - 1):
editor.set_buffer(file.buffer)

View File

@@ -0,0 +1,18 @@
# Python imports
# Lib imports
import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
# Application imports
def execute(
editor: GtkSource.View = None,
buffer: GtkSource.Buffer= None
):
logger.debug("Show Completion Command")

View File

@@ -0,0 +1,61 @@
# Python imports
# Lib imports
import gi
from gi.repository import GLib
# Application imports
from .custom_completion_providers.lsp_completion_provider import LSPCompletionProvider
class CompletionManager():
def __init__(self, completer):
super(CompletionManager, self).__init__()
self._completor = completer
self._lsp_provider = LSPCompletionProvider()
self._timeout_id = None
def request_completion(self):
if self._timeout_id:
GLib.source_remove(self._timeout_id)
self._timeout_id = GLib.timeout_add(
1000,
self._process_request_completion
)
def _process_request_completion(self):
print('hello')
self._timeout_id = None
return False
def _do_completion(self):
if self._completor.get_providers():
self._mach_completion()
else:
self._start_completion()
def _mach_completion(self):
"""
Note: Use IF providers were added to completion...
"""
self._completion.match(
self._completion.create_context()
)
def _start_completion(self):
"""
Note: Use IF NO providers have been added to completion...
"""
self._completion.start(
[
self._lsp_provider
],
self._completion.create_context()
)

View File

@@ -0,0 +1,3 @@
"""
Custom Completion Providers Module
"""

View File

@@ -0,0 +1,74 @@
# Python imports
import re
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import Gtk
from gi.repository import GtkSource
from gi.repository import GObject
# Application imports
class ExampleCompletionProvider(GObject.GObject, GtkSource.CompletionProvider):
"""
This is a custom Completion Example Provider.
# NOTE: used information from here --> https://warroom.rsmus.com/do-that-auto-complete/
"""
__gtype_name__ = 'CustomProvider'
def __init__(self):
GObject.Object.__init__(self)
def do_get_name(self):
""" Returns: a new string containing the name of the provider. """
return _('ExampleProvider')
def do_match(self, context):
""" Get whether the provider match the context of completion detailed in context. """
# NOTE: True for debugging but context needs to normally get checked for actual usage needs.
# TODO: Fix me
return True
def do_populate(self, context):
"""
In this instance, it will do 2 things:
1) always provide Hello World! (Not ideal but an option so its in the example)
2) Utilizes the Gtk.TextIter from the TextBuffer to determine if there is a jinja
example of '{{ custom.' if so it will provide you with the options of foo and bar.
If selected it will insert foo }} or bar }}, completing your syntax...
PLEASE NOTE the GtkTextIter Logic and regex are really rough and should be adjusted and tuned
"""
proposals = [
# GtkSource.CompletionItem(label='Hello World!', text = 'Hello World!', icon = None, info = None) # NOTE: Always proposed...
]
# Gtk Versions differ on get_iter responses...
end_iter = context.get_iter()
if not isinstance(end_iter, Gtk.TextIter):
_, end_iter = context.get_iter()
if end_iter:
buf = end_iter.get_buffer()
mov_iter = end_iter.copy()
if mov_iter.backward_search('{{', Gtk.TextSearchFlags.VISIBLE_ONLY):
mov_iter, _ = mov_iter.backward_search('{{', Gtk.TextSearchFlags.VISIBLE_ONLY)
left_text = buf.get_text(mov_iter, end_iter, True)
else:
left_text = ''
if re.match(r'.*\{\{\s*custom\.$', left_text):
proposals.append(
GtkSource.CompletionItem(label='foo', text='foo }}') # optionally proposed based on left search via regex
)
proposals.append(
GtkSource.CompletionItem(label='bar', text='bar }}') # optionally proposed based on left search via regex
)
context.add_proposals(self, proposals, True)

View File

@@ -0,0 +1,117 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import Gtk
from gi.repository import GtkSource
from gi.repository import GObject
# Application imports
class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider):
"""
This code is an LSP code completion plugin for Newton.
# NOTE: Some code pulled/referenced from here --> https://github.com/isamert/gedi
"""
__gtype_name__ = 'LSPProvider'
def __init__(self):
GObject.Object.__init__(self)
self._icon_theme = Gtk.IconTheme.get_default()
self.lsp_data = None
def do_get_name(self):
return "LSP Code Completion"
def get_iter_correctly(self, context):
return context.get_iter()[1] if isinstance(context.get_iter(), tuple) else context.get_iter()
def do_match(self, context):
return True
def do_get_priority(self):
return 1
def do_get_activation(self):
return GtkSource.CompletionActivation.USER_REQUESTED
def do_populate(self, context, items = []):
self.lsp_data
# def do_populate(self, context, items = []):
# if hasattr(self._source_view, "completion_items"):
# items = self._source_view.completion_items
# proposals = []
# for item in items:
# proposals.append( self.create_completion_item(item) )
# context.add_proposals(self, proposals, True)
# def get_icon_for_type(self, _type):
# try:
# return self._theme.load_icon(icon_names[_type.lower()], 16, 0)
# except:
# ...
# try:
# return self._theme.load_icon(Gtk.STOCK_ADD, 16, 0)
# except:
# ...
# return None
# def create_completion_item(self, item):
# comp_item = GtkSource.CompletionItem.new()
# keys = item.keys()
# comp_item.set_label(item["label"])
# if "insertText" in keys:
# comp_item.set_text(item["insertText"])
# if "additionalTextEdits" in keys:
# comp_item.additionalTextEdits = item["additionalTextEdits"]
# return comp_item
# def create_completion_item(self, item):
# comp_item = GtkSource.CompletionItem.new()
# comp_item.set_label(item.label)
# if item.textEdit:
# if isinstance(item.textEdit, dict):
# comp_item.set_text(item.textEdit["newText"])
# else:
# comp_item.set_text(item.textEdit)
# else:
# comp_item.set_text(item.insertText)
# comp_item.set_icon( self.get_icon_for_type(item.kind) )
# comp_item.set_info(item.documentation)
# return comp_item

View File

@@ -0,0 +1,108 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import Gtk
from gi.repository import GtkSource
from gi.repository import GObject
import jedi
from jedi.api import Script
# Application imports
# FIXME: Find real icon names...
icon_names = {
'import': '',
'module': '',
'class': '',
'function': '',
'statement': '',
'param': ''
}
class Jedi:
def get_script(file, doc_text):
return Script(code = doc_text, path = file)
class PythonCompletionProvider(GObject.Object, GtkSource.CompletionProvider):
"""
This code is A python code completion plugin for Newton.
# NOTE: Some code pulled/referenced from here --> https://github.com/isamert/gedi
"""
__gtype_name__ = 'PythonProvider'
def __init__(self, file):
GObject.Object.__init__(self)
self._theme = Gtk.IconTheme.get_default()
self._file = file
def do_get_name(self):
return "Python Code Completion"
def get_iter_correctly(self, context):
return context.get_iter()[1] if isinstance(context.get_iter(), tuple) else context.get_iter()
def do_match(self, context):
iter = self.get_iter_correctly(context)
iter.backward_char()
buffer = iter.get_buffer()
if buffer.get_context_classes_at_iter(iter) != ['no-spell-check']:
return False
ch = iter.get_char()
# NOTE: Look to re-add or apply supprting logic to use spaces
# As is it slows down the editor in certain contexts...
# if not (ch in ('_', '.', ' ') or ch.isalnum()):
if not (ch in ('_', '.') or ch.isalnum()):
return False
return True
def do_get_priority(self):
return 1
def do_get_activation(self):
return GtkSource.CompletionActivation.INTERACTIVE
def do_populate(self, context):
# TODO: Maybe convert async?
it = self.get_iter_correctly(context)
buffer = it.get_buffer()
proposals = []
doc_text = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), False)
iter_cursor = buffer.get_iter_at_mark(buffer.get_insert())
linenum = iter_cursor.get_line() + 1
charnum = iter_cursor.get_line_index()
def create_generator():
for completion in Jedi.get_script(self._file, doc_text).complete(line = linenum, column = None, fuzzy = False):
comp_item = GtkSource.CompletionItem.new()
comp_item.set_label(completion.name)
comp_item.set_text(completion.name)
comp_item.set_icon(self.get_icon_for_type(completion.type))
comp_item.set_info(completion.docstring())
yield comp_item
for item in create_generator():
proposals.append(item)
context.add_proposals(self, proposals, True)
def get_icon_for_type(self, _type):
try:
return self._theme.load_icon(icon_names[_type.lower()], 16, 0)
except:
try:
return self._theme.load_icon(Gtk.STOCK_ADD, 16, 0)
except:
return None

View File

@@ -0,0 +1,127 @@
# Python imports
import copy
import json
# Lib imports
import gi
gi.require_version('Gdk', '3.0')
from gi.repository import Gdk
# Application imports
class NoKeyState:
held: dict = {}
released: dict = {}
class CtrlKeyState:
held: dict = {}
released: dict = {}
class ShiftKeyState:
held: dict = {}
released: dict = {}
class AltKeyState:
held: dict = {}
released: dict = {}
class CtrlShiftKeyState:
held: dict = {}
released: dict = {}
class CtrlAltKeyState:
held: dict = {}
released: dict = {}
class AltShiftKeyState:
held: dict = {}
released: dict = {}
class CtrlShiftAltKeyState:
held: dict = {}
released: dict = {}
class KeyMapper:
def __init__(self):
super(KeyMapper, self).__init__()
self.state = NoKeyState
self._map = {
NoKeyState: NoKeyState(),
NoKeyState | CtrlKeyState : CtrlKeyState(),
NoKeyState | ShiftKeyState: ShiftKeyState(),
NoKeyState | AltKeyState : AltKeyState(),
NoKeyState | CtrlKeyState | ShiftKeyState : CtrlShiftKeyState(),
NoKeyState | CtrlKeyState | AltKeyState : CtrlAltKeyState(),
NoKeyState | AltKeyState | ShiftKeyState : AltShiftKeyState(),
NoKeyState | CtrlKeyState | ShiftKeyState | AltKeyState: CtrlShiftAltKeyState(),
}
self.load_map()
def load_map(self):
self.states = copy.deepcopy(self._map)
bindings_file = f"{settings_manager.get_home_config_path()}/code-key-bindings.json"
with open(bindings_file, 'r') as f:
data = json.load(f)["keybindings"]
for command in data:
press_state = "held" if "held" in data[command] else "released"
keyname = data[command][press_state]
state = NoKeyState
if "<Control>" in keyname:
state = state | CtrlKeyState
if "<Shift>" in keyname:
state = state | ShiftKeyState
if "<Alt>" in keyname:
state = state | AltKeyState
keyname = keyname.replace("<Control>", "") \
.replace("<Shift>", "") \
.replace("<Alt>", "")
getattr(self.states[state], press_state)[keyname] = command
def re_map(self):
self.states = copy.deepcopy(self._map)
def _key_press_event(self, eve):
keyname = Gdk.keyval_name(eve.keyval)
print(keyname)
self._set_key_state(eve)
if keyname in self.states[self.state].held:
return self.states[self.state].held[keyname]
def _key_release_event(self, eve):
keyname = Gdk.keyval_name(eve.keyval)
self._set_key_state(eve)
if keyname in self.states[self.state].released:
return self.states[self.state].released[keyname]
def _set_key_state(self, eve):
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
is_control = True if modifiers & Gdk.ModifierType.CONTROL_MASK else False
is_shift = True if modifiers & Gdk.ModifierType.SHIFT_MASK else False
try:
is_alt = True if modifiers & Gdk.ModifierType.ALT_MASK else False
except Exception:
is_alt = True if modifiers & Gdk.ModifierType.MOD1_MASK else False
self.state = NoKeyState
if is_control:
self.state = self.state | CtrlKeyState
if is_shift:
self.state = self.state | ShiftKeyState
if is_alt:
self.state = self.state | AltKeyState

View File

@@ -0,0 +1,40 @@
# Python imports
# Lib imports
import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
# Application imports
class SourceBuffer(GtkSource.Buffer):
def __init__(self):
super(SourceBuffer, self).__init__()
self._handler_ids = []
def set_signals(
self,
_changed,
_mark_set,
_insert_text,
_modified_changed,
):
self._handler_ids = [
self.connect("changed", _changed),
self.connect("mark-set", _mark_set),
self.connect("insert-text", _insert_text),
self.connect("modified-changed", _modified_changed)
]
def clear_signals(self):
for handle_id in self._handler_ids:
self.disconnect(handle_id)
def __del__(self):
for handle_id in self._handler_ids:
self.disconnect(handle_id)

View File

@@ -0,0 +1,77 @@
# Python imports
import os
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import Gtk
from gi.repository import GtkSource
from gi.repository import Gio
# Application imports
from .source_buffer import SourceBuffer
class SourceFile(GtkSource.File):
def __init__(self):
super(SourceFile, self).__init__()
self.encoding: str = "UTF-8"
self.fname: str = "buffer"
self.fpath: str = "buffer"
self.ftype: str = "buffer"
self.buffer: SourceBuffer = SourceBuffer()
self._set_signals()
def set_path(self, gfile: Gio.File.new_for_path):
if not gfile: return
self.set_location(gfile)
self.fpath = gfile.get_parent().get_path(),
self.fname = gfile.get_basename()
data = gfile.load_bytes()[0].get_data().decode("UTF-8")
self.buffer.insert_at_cursor(data)
def _set_signals(self):
self.buffer.set_signals(
self._changed,
self._mark_set,
self._insert_text,
self._modified_changed
)
def _insert_text(
self,
buffer: SourceBuffer,
location: Gtk.TextIter,
text: str,
length: int
):
logger.info("SourceFile._insert_text")
def _changed(self, buffer: SourceBuffer):
logger.info("SourceFile._changed")
def _mark_set(
self,
buffer: SourceBuffer,
location: Gtk.TextIter,
mark: Gtk.TextMark
):
# logger.info("SourceFile._mark_set")
...
def _modified_changed(self,buffer: SourceBuffer):
logger.info("SourceFile._modified_changed")
def close(self):
del self.buffer

View File

@@ -0,0 +1,36 @@
# Python imports
# Lib imports
# Application imports
from .source_file import SourceFile
from .source_buffer import SourceBuffer
class SourceFilesManager(list):
def __init__(self):
super(SourceFilesManager, self).__init__()
def new(self):
file = SourceFile()
super().append(file)
return file
def append(self, file: SourceFile):
if not file: return
super().append(file)
def remove_file(self, buffer: SourceBuffer):
if not buffer: return
for file in self:
if not buffer == file.buffer: continue
self.remove(file)
file.close()
del file
break

View File

@@ -0,0 +1,115 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import GtkSource
# Application imports
from .source_files_manager import SourceFilesManager
from .completion_manager import CompletionManager
from .command_system import CommandSystem
from .key_mapper import KeyMapper
class SourceView(GtkSource.View):
def __init__(self):
super(SourceView, self).__init__()
self.key_mapper = KeyMapper()
self._setup_styles()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
def _setup_styles(self):
ctx = self.get_style_context()
ctx.add_class("source-view")
self.set_vexpand(True)
self.set_show_line_marks(True)
self.set_show_line_numbers(True)
self.set_smart_backspace(True)
self.set_indent_on_tab(True)
self.set_insert_spaces_instead_of_tabs(True)
self.set_auto_indent(True)
self.set_monospace(True)
self.set_tab_width(4)
self.set_show_right_margin(True)
self.set_right_margin_position(80)
self.set_background_pattern(0) # 0 = None, 1 = Grid
self.set_highlight_current_line(True)
def _setup_signals(self):
# self.connect("show-completion", self._show_completion)
self.map_id = self.connect("map", self._init_map)
# self.connect("focus", self._on_widget_focus)
# self.connect("focus-in-event", self._focus_in_event)
# self.connect("drag-data-received", self._on_drag_data_received)
self.connect("key-press-event", self._key_press_event)
self.connect("key-release-event", self._key_release_event)
# self.connect("button-press-event", self._button_press_event)
# self.connect("button-release-event", self._button_release_event)
# self.connect("scroll-event", self._scroll_event)
def _subscribe_to_events(self):
...
def _load_widgets(self):
...
def _init_map(self, view):
def _first_show_init():
self.disconnect(self.map_id)
del self.map_id
self._handle_first_show()
return False
# GLib.timeout_add(1000, _first_show_init)
GLib.idle_add(_first_show_init)
def _handle_first_show(self):
self.language_manager = GtkSource.LanguageManager()
self.style_scheme_manager = GtkSource.StyleSchemeManager()
self.command = CommandSystem()
self.files = SourceFilesManager()
self.completion = CompletionManager(
self.get_completion()
)
self.style_scheme_manager.append_search_path(f"{settings_manager.get_home_config_path()}/code_styles")
self.syntax_theme = self.style_scheme_manager.get_scheme("penguins-in-space")
self.command.set_data(self, self.get_buffer())
self.exec_command("new_file")
def _key_press_event(self, view, eve):
command = self.key_mapper._key_press_event(eve)
if not command: return False
self.exec_command(command)
return True
def _key_release_event(self, view, eve):
command = self.key_mapper._key_release_event(eve)
if not command: return False
self.exec_command(command)
return True
def _show_completion(self, view):
self.completion.request_completion()
def exec_command(self, command: str):
self.command.exec(command)

View File

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

View File

@@ -0,0 +1,83 @@
# Python imports
from contextlib import suppress
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)
with suppress(Exception):
folder = widget.get_current_file().get_parent() if not start_dir else start_dir
chooser.set_current_folder( folder.get_path() )
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

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

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(99)
adjust.set_upper(100)
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

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

View File

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

View File

@@ -0,0 +1,128 @@
# 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()
if not text: return
lines = text.strip().splitlines()
command_ran = None
try:
command_ran = lines[-1].split("-->:")[1].strip()
except VteWidgetException as e:
logger.debug(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: str):
self.dont_process = True
cmds = [f"cd '{fpath}'\n", "clear\n"]
for cmd in cmds:
self.run_command(cmd)
def run_command(self, cmd: str):
self.feed_child_binary(bytes(cmd, 'utf8'))

View File

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

View File

@@ -9,17 +9,14 @@ 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
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 +24,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 +31,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 +47,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 +56,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}")
def run_javascript(self, script, cancellable, callback):
logger.debug(script)
super().run_javascript(script, cancellable, callback)

View File

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

View File

@@ -10,7 +10,13 @@ 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
@@ -23,26 +29,34 @@ 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)
self._controller = None
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()
self._load_widgets(args, unknownargs)
self._load_widgets()
self._set_window_data()
self._set_size_constraints()
self._setup_window_toggle_event()
self.show()
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_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
@@ -54,23 +68,33 @@ 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("load_interactive_debug", self._load_interactive_debug)
event_system.subscribe("tear-down", self.stop)
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...")
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
@@ -90,13 +114,12 @@ 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()
cssProvider.load_from_path( settings_manager.get_css_file() )
screen = Gdk.Screen.get_default()
styleContext = Gtk.StyleContext()
cssProvider.load_from_path( settings_manager.get_css_file() )
styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
def _area_draw(self, widget: Gtk.ApplicationWindow, cr: cairo.Context) -> None:
@@ -107,17 +130,62 @@ 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 _setup_window_toggle_event(self) -> None:
hidebound = None
if not self.guake_key or not self._display_manager() == 'X11':
return
def _tear_down(self, widget = None, eve = None):
event_system.emit("shutting_down")
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()
def stop(self, widget = None, eve = None):
event_system.emit("shutting-down")
size = self.get_size()
pos = self.get_position()
@@ -130,6 +198,3 @@ class Window(Gtk.ApplicationWindow):
settings_manager.clear_pid()
Gtk.main_quit()
def main(self):
Gtk.main()

View File

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

View File

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

6
src/libs/db/__init__.py Normal file
View File

@@ -0,0 +1,6 @@
"""
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 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,15 @@ 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:
import ipdb
logger.debug("\n\nStarting IPDB debugger...\n\n")
ipdb.set_trace()
return
except Exception as ex:
...
try:
@@ -42,11 +50,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...")

5
src/libs/dto/__init__.py Normal file
View File

@@ -0,0 +1,5 @@
"""
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_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')
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,36 +56,43 @@ 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()
self._handle_ipc_message(conn, start_time)
except EOFError as e:
logger.debug( repr(e) )
except Exception as e:
logger.debug( repr(e) )
finally:
conn.close()
listener.close()
def _handle_ipc_message(self, conn, start_time) -> None:
while True:
while self.is_ipc_alive:
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)
event_system.emit("handle-file-from-ipc", file)
conn.close()
break
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
if msg in ['close connection', 'close server']:
if msg in ['close connection', 'close server', 'Empty Data...']:
conn.close()
break
@@ -129,4 +136,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 @@
"""
Utils/Mixins module
Libs.Mixins Package
"""

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,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}")
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)

View File

@@ -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,13 +86,11 @@ class KeyboardSignalsMixin:
sender = ""
eve_type = mapping
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}")
self.handle_key_event_system(sender, eve_type)
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)

View File

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

View File

@@ -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:
@@ -79,7 +80,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):
@@ -90,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)}" )
@@ -102,23 +105,25 @@ 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._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):
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:
...
@@ -128,7 +133,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,29 +156,46 @@ 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_guake_key(self) -> tuple: return self._guake_key
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 call_method(self, target_class = None, _method_name = None, data = None):
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 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 @@
"""
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

View File

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

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,4 +0,0 @@
"""
Settings module
"""
from .manager import SettingsManager

View File

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

View File

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

67
src/libs/status_icon.py Normal file
View File

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

View File

@@ -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,29 @@ 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
def is_pre_launch(self):
return self._plugin.pre_launch

View File

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

View File

@@ -0,0 +1,10 @@
{
"keybindings": {
"show_completion" : { "released" : "<Control>space" },
"line_up" : { "held" : "<Control>Up" },
"line_down" : { "held" : "<Control>Down" },
"new_file" : { "released" : "<Control>t" },
"open_files" : { "released" : "<Control>o" },
"close_file" : { "released" : "<Control>w" }
}
}

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Catppuccin Gedit theme based on Oblivion theme and Cappuccin for Visual Studio Code.
-->
<style-scheme id="catppuccin_frappe" _name="Catppuccin frappe" version="1.0">
<author>sacerdos</author>
<_description>Soothing pastel theme for Gedit</_description>
<!-- Catppuccin Palette -->
<color name="frappe_rosewater" value="#f2d5cf"/>
<color name="frappe_flamingo" value="#eebebe"/>
<color name="frappe_pink" value="#f4b8e4"/>
<color name="frappe_mauve" value="#ca9ee6"/>
<color name="frappe_red" value="#e78284"/>
<color name="frappe_maroon" value="#ea999c"/>
<color name="frappe_peach" value="#ef9f76"/>
<color name="frappe_yellow" value="#e5c890"/>
<color name="frappe_green" value="#a6d189"/>
<color name="frappe_teal" value="#81c8be"/>
<color name="frappe_sky" value="#99d1db"/>
<color name="frappe_sapphire" value="#85c1dc"/>
<color name="frappe_blue" value="#8caaee"/>
<color name="frappe_lavender" value="#babbf1"/>
<color name="frappe_text" value="#c6d0f5"/>
<color name="frappe_subtext1" value="#b5bfe2"/>
<color name="frappe_subtext0" value="#a5adce"/>
<color name="frappe_overlay2" value="#949cbb"/>
<color name="frappe_overlay1" value="#838ba7"/>
<color name="frappe_overlay0" value="#737994"/>
<color name="frappe_surface2" value="#626880"/>
<color name="frappe_surface1" value="#51576d"/>
<color name="frappe_surface0" value="#51576d"/>
<color name="frappe_base" value="#303446"/>
<color name="frappe_mantle" value="#292c3c"/>
<color name="frappe_crust" value="#232634"/>
<!-- Global Settings -->
<style name="text" foreground="frappe_text" background = "frappe_base"/>
<style name="selection" foreground="frappe_text" background="frappe_surface2"/>
<style name="cursor" foreground="frappe_rosewater"/>
<style name="secondary-cursor" foreground="frappe_rosewater"/>
<style name="current-line" background="frappe_surface0"/>
<style name="line-numbers" foreground="frappe_text" background="frappe_crust"/>
<style name="draw-spaces" foreground="frappe_text"/>
<style name="background-pattern" background="frappe_base"/>
<!-- Bracket Matching -->
<style name="bracket-match" foreground="frappe_mauve"/>
<style name="bracket-mismatch" foreground="frappe_text" background="frappe_peach"/>
<!-- Right Margin -->
<style name="right-margin" foreground="frappe_text" background="frappe_crust"/>
<!-- Search Matching -->
<style name="search-match" foreground="frappe_text" background="frappe_blue"/>
<!-- Comments -->
<style name="def:comment" foreground="frappe_overlay0"/>
<style name="def:shebang" foreground="frappe_overlay0" bold="true"/>
<style name="def:doc-comment-element" italic="true"/>
<!-- Constants -->
<style name="def:constant" foreground="frappe_green"/>
<style name="def:string" foreground="frappe_green"/>
<style name="def:special-char" foreground="frappe_lavender"/>
<style name="def:special-constant" foreground="frappe_lavender"/>
<style name="def:floating-point" foreground="frappe_lavender"/>
<!-- Identifiers -->
<style name="def:identifier" foreground="frappe_blue"/>
<!-- Statements -->
<style name="def:statement" foreground="frappe_sapphire" bold="true"/>
<!-- Types -->
<style name="def:type" foreground="frappe_maroon" bold="true"/>
<!-- Markup -->
<style name="def:emphasis" italic="true"/>
<style name="def:strong-emphasis" foreground="frappe_yellow" bold="true"/>
<style name="def:inline-code" foreground="frappe_green"/>
<style name="def:insertion" underline="single"/>
<style name="def:deletion" strikethrough="true"/>
<style name="def:link-text" foreground="frappe_rosewater"/>
<style name="def:link-symbol" foreground="frappe_blue" bold="true"/>
<style name="def:link-destination" foreground="frappe_blue" italic="true" underline="single"/>
<style name="def:heading" foreground="frappe_teal" bold="true"/>
<style name="def:thematic-break" foreground="frappe_green" bold="true"/>
<style name="def:preformatted-section" foreground="frappe_green"/>
<style name="def:list-marker" foreground="frappe_teal" bold="true"/>
<!-- Others -->
<style name="def:preprocessor" foreground="frappe_teal"/>
<style name="def:error" foreground="frappe_maroon" bold="true"/>
<style name="def:warning" foreground="frappe_peach"/>
<style name="def:note" foreground="frappe_blue" bold="true"/>
<style name="def:net-address" italic="true" underline="single"/>
</style-scheme>

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Catppuccin Gedit theme based on Oblivion theme and Cappuccin for Visual Studio Code.
-->
<style-scheme id="catppuccin_latte" _name="Catppuccin latte" version="1.0">
<author>sacerdos</author>
<_description>Soothing pastel theme for Gedit</_description>
<!-- Catppuccin Palette -->
<color name="latte_rosewater" value="#dc8a78"/>
<color name="latte_flamingo" value="#dd7878"/>
<color name="latte_pink" value="#ea76cb"/>
<color name="latte_mauve" value="#8839ef"/>
<color name="latte_red" value="#d20f39"/>
<color name="latte_maroon" value="#e64553"/>
<color name="latte_peach" value="#fe640b"/>
<color name="latte_yellow" value="#df8e1d"/>
<color name="latte_green" value="#40a02b"/>
<color name="latte_teal" value="#179299"/>
<color name="latte_sky" value="#04a5e5"/>
<color name="latte_sapphire" value="#209fb5"/>
<color name="latte_blue" value="#1e66f5"/>
<color name="latte_lavender" value="#7287fd"/>
<color name="latte_text" value="#4c4f69"/>
<color name="latte_subtext1" value="#5c5f77"/>
<color name="latte_subtext0" value="#6c6f85"/>
<color name="latte_overlay2" value="#7c7f93"/>
<color name="latte_overlay1" value="#8c8fa1"/>
<color name="latte_overlay0" value="#9ca0b0"/>
<color name="latte_surface2" value="#acb0be"/>
<color name="latte_surface1" value="#bcc0cc"/>
<color name="latte_surface0" value="#ccd0da"/>
<color name="latte_base" value="#eff1f5"/>
<color name="latte_mantle" value="#e6e9ef"/>
<color name="latte_crust" value="#dce0e8"/>
<!-- Global Settings -->
<style name="text" foreground="latte_text" background = "latte_base"/>
<style name="selection" foreground="latte_text" background="latte_surface2"/>
<style name="cursor" foreground="latte_rosewater"/>
<style name="secondary-cursor" foreground="latte_rosewater"/>
<style name="current-line" background="latte_surface0"/>
<style name="line-numbers" foreground="latte_text" background="latte_crust"/>
<style name="draw-spaces" foreground="latte_text"/>
<style name="background-pattern" background="latte_base"/>
<!-- Bracket Matching -->
<style name="bracket-match" foreground="latte_mauve"/>
<style name="bracket-mismatch" foreground="latte_text" background="latte_peach"/>
<!-- Right Margin -->
<style name="right-margin" foreground="latte_text" background="latte_crust"/>
<!-- Search Matching -->
<style name="search-match" foreground="latte_text" background="latte_blue"/>
<!-- Comments -->
<style name="def:comment" foreground="latte_overlay0"/>
<style name="def:shebang" foreground="latte_overlay0" bold="true"/>
<style name="def:doc-comment-element" italic="true"/>
<!-- Constants -->
<style name="def:constant" foreground="latte_green"/>
<style name="def:string" foreground="latte_green"/>
<style name="def:special-char" foreground="latte_lavender"/>
<style name="def:special-constant" foreground="latte_lavender"/>
<style name="def:floating-point" foreground="latte_lavender"/>
<!-- Identifiers -->
<style name="def:identifier" foreground="latte_blue"/>
<!-- Statements -->
<style name="def:statement" foreground="latte_sapphire" bold="true"/>
<!-- Types -->
<style name="def:type" foreground="latte_maroon" bold="true"/>
<!-- Markup -->
<style name="def:emphasis" italic="true"/>
<style name="def:strong-emphasis" foreground="latte_yellow" bold="true"/>
<style name="def:inline-code" foreground="latte_green"/>
<style name="def:insertion" underline="single"/>
<style name="def:deletion" strikethrough="true"/>
<style name="def:link-text" foreground="latte_rosewater"/>
<style name="def:link-symbol" foreground="latte_blue" bold="true"/>
<style name="def:link-destination" foreground="latte_blue" italic="true" underline="single"/>
<style name="def:heading" foreground="latte_teal" bold="true"/>
<style name="def:thematic-break" foreground="latte_green" bold="true"/>
<style name="def:preformatted-section" foreground="latte_green"/>
<style name="def:list-marker" foreground="latte_teal" bold="true"/>
<!-- Others -->
<style name="def:preprocessor" foreground="latte_teal"/>
<style name="def:error" foreground="latte_maroon" bold="true"/>
<style name="def:warning" foreground="latte_peach"/>
<style name="def:note" foreground="latte_blue" bold="true"/>
<style name="def:net-address" italic="true" underline="single"/>
</style-scheme>

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Catppuccin Gedit theme based on Oblivion theme and Cappuccin for Visual Studio Code.
-->
<style-scheme id="catppuccin_macchiato" _name="Catppuccin macchiato" version="1.0">
<author>sacerdos</author>
<_description>Soothing pastel theme for Gedit</_description>
<!-- Catppuccin Palette -->
<color name="macchiato_rosewater" value="#f4dbd6"/>
<color name="macchiato_flamingo" value="#f0c6c6"/>
<color name="macchiato_pink" value="#f5bde6"/>
<color name="macchiato_mauve" value="#c6a0f6"/>
<color name="macchiato_red" value="#ed8796"/>
<color name="macchiato_maroon" value="#ee99a0"/>
<color name="macchiato_peach" value="#f5a97f"/>
<color name="macchiato_yellow" value="#eed49f"/>
<color name="macchiato_green" value="#a6da95"/>
<color name="macchiato_teal" value="#8bd5ca"/>
<color name="macchiato_sky" value="#91d7e3"/>
<color name="macchiato_sapphire" value="#7dc4e4"/>
<color name="macchiato_blue" value="#8aadf4"/>
<color name="macchiato_lavender" value="#b7bdf8"/>
<color name="macchiato_text" value="#cad3f5"/>
<color name="macchiato_subtext1" value="#b8c0e0"/>
<color name="macchiato_subtext0" value="#a5adcb"/>
<color name="macchiato_overlay2" value="#939ab7"/>
<color name="macchiato_overlay1" value="#8087a2"/>
<color name="macchiato_overlay0" value="#6e738d"/>
<color name="macchiato_surface2" value="#5b6078"/>
<color name="macchiato_surface1" value="#494d64"/>
<color name="macchiato_surface0" value="#363a4f"/>
<color name="macchiato_base" value="#24273a"/>
<color name="macchiato_mantle" value="#1e2030"/>
<color name="macchiato_crust" value="#181926"/>
<!-- Global Settings -->
<style name="text" foreground="macchiato_text" background = "macchiato_base"/>
<style name="selection" foreground="macchiato_text" background="macchiato_surface2"/>
<style name="cursor" foreground="macchiato_rosewater"/>
<style name="secondary-cursor" foreground="macchiato_rosewater"/>
<style name="current-line" background="macchiato_surface0"/>
<style name="line-numbers" foreground="macchiato_text" background="macchiato_crust"/>
<style name="draw-spaces" foreground="macchiato_text"/>
<style name="background-pattern" background="macchiato_mantle"/>
<!-- Bracket Matching -->
<style name="bracket-match" foreground="macchiato_mauve"/>
<style name="bracket-mismatch" foreground="macchiato_text" background="macchiato_peach"/>
<!-- Right Margin -->
<style name="right-margin" foreground="macchiato_text" background="crust"/>
<!-- Search Matching -->
<style name="search-match" foreground="macchiato_text" background="macchiato_blue"/>
<!-- Comments -->
<style name="def:comment" foreground="macchiato_overlay0"/>
<style name="def:shebang" foreground="macchiato_overlay0" bold="true"/>
<style name="def:doc-comment-element" italic="true"/>
<!-- Constants -->
<style name="def:constant" foreground="macchiato_green"/>
<style name="def:string" foreground="macchiato_green"/>
<style name="def:special-char" foreground="macchiato_lavender"/>
<style name="def:special-constant" foreground="macchiato_lavender"/>
<style name="def:floating-point" foreground="macchiato_lavender"/>
<!-- Identifiers -->
<style name="def:identifier" foreground="macchiato_blue"/>
<!-- Statements -->
<style name="def:statement" foreground="macchiato_sapphire" bold="true"/>
<!-- Types -->
<style name="def:type" foreground="macchiato_maroon" bold="true"/>
<!-- Markup -->
<style name="def:emphasis" italic="true"/>
<style name="def:strong-emphasis" foreground="macchiato_yellow" bold="true"/>
<style name="def:inline-code" foreground="macchiato_green"/>
<style name="def:insertion" underline="single"/>
<style name="def:deletion" strikethrough="true"/>
<style name="def:link-text" foreground="macchiato_rosewater"/>
<style name="def:link-symbol" foreground="macchiato_blue" bold="true"/>
<style name="def:link-destination" foreground="macchiato_blue" italic="true" underline="single"/>
<style name="def:heading" foreground="macchiato_teal" bold="true"/>
<style name="def:thematic-break" foreground="macchiato_green" bold="true"/>
<style name="def:preformatted-section" foreground="macchiato_green"/>
<style name="def:list-marker" foreground="macchiato_teal" bold="true"/>
<!-- Others -->
<style name="def:preprocessor" foreground="macchiato_teal"/>
<style name="def:error" foreground="macchiato_maroon" bold="true"/>
<style name="def:warning" foreground="macchiato_peach"/>
<style name="def:note" foreground="macchiato_blue" bold="true"/>
<style name="def:net-address" italic="true" underline="single"/>
</style-scheme>

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Catppuccin Gedit theme based on Oblivion theme and Cappuccin for Visual Studio Code.
-->
<style-scheme id="catppuccin_mocha" _name="Catppuccin Mocha" version="1.0">
<author>sacerdos</author>
<_description>Soothing pastel theme for Gedit</_description>
<!-- Tango Palette -->
<color name="mocha_rosewater" value="#f5e0dc"/>
<color name="mocha_flamingo" value="#f2cdcd"/>
<color name="mocha_pink" value="#f5c2e7"/>
<color name="mocha_mauve" value="#cba6f7"/>
<color name="mocha_red" value="#f38ba8"/>
<color name="mocha_maroon" value="#eba0ac"/>
<color name="mocha_peach" value="#fab387"/>
<color name="mocha_yellow" value="#f9e2af"/>
<color name="mocha_green" value="#a6e3a1"/>
<color name="mocha_teal" value="#94e2d5"/>
<color name="mocha_sky" value="#89dceb"/>
<color name="mocha_sapphire" value="#74c7ec"/>
<color name="mocha_blue" value="#89b4fa"/>
<color name="mocha_lavender" value="#b4befe"/>
<color name="mocha_text" value="#cdd6f4"/>
<color name="mocha_subtext1" value="#bac2de"/>
<color name="mocha_subtext0" value="#a6adc8"/>
<color name="mocha_overlay2" value="#9399b2"/>
<color name="mocha_overlay1" value="#7f849c"/>
<color name="mocha_overlay0" value="#6c7086"/>
<color name="mocha_surface2" value="#585b70"/>
<color name="mocha_surface1" value="#45475a"/>
<color name="mocha_surface0" value="#313244"/>
<color name="mocha_base" value="#1e1e2e"/>
<color name="mocha_mantle" value="#181825"/>
<color name="mocha_crust" value="#11111b"/>
<!-- Global Settings -->
<style name="text" foreground="mocha_text" background = "mocha_base"/>
<style name="selection" foreground="mocha_text" background="mocha_surface2"/>
<style name="cursor" foreground="mocha_rosewater"/>
<style name="secondary-cursor" foreground="mocha_rosewater"/>
<style name="current-line" background="mocha_surface0"/>
<style name="line-numbers" foreground="mocha_text" background="mocha_crust"/>
<style name="draw-spaces" foreground="mocha_text"/>
<style name="background-pattern" background="mocha_mantle"/>
<!-- Bracket Matching -->
<style name="bracket-match" foreground="mocha_mauve"/>
<style name="bracket-mismatch" foreground="mocha_text" background="mocha_peach"/>
<!-- Right Margin -->
<style name="right-margin" foreground="mocha_text" background="mocha_crust"/>
<!-- Search Matching -->
<style name="search-match" foreground="mocha_text" background="mocha_blue"/>
<!-- Comments -->
<style name="def:comment" foreground="mocha_overlay0"/>
<style name="def:shebang" foreground="mocha_overlay0" bold="true"/>
<style name="def:doc-comment-element" italic="true"/>
<!-- Constants -->
<style name="def:constant" foreground="mocha_green"/>
<style name="def:string" foreground="mocha_green"/>
<style name="def:special-char" foreground="mocha_lavender"/>
<style name="def:special-constant" foreground="mocha_lavender"/>
<style name="def:floating-point" foreground="mocha_lavender"/>
<!-- Identifiers -->
<style name="def:identifier" foreground="mocha_blue"/>
<!-- Statements -->
<style name="def:statement" foreground="mocha_sapphire" bold="true"/>
<!-- Types -->
<style name="def:type" foreground="mocha_maroon" bold="true"/>
<!-- Markup -->
<style name="def:emphasis" italic="true"/>
<style name="def:strong-emphasis" foreground="mocha_yellow" bold="true"/>
<style name="def:inline-code" foreground="mocha_green"/>
<style name="def:insertion" underline="single"/>
<style name="def:deletion" strikethrough="true"/>
<style name="def:link-text" foreground="mocha_rosewater"/>
<style name="def:link-symbol" foreground="mocha_blue" bold="true"/>
<style name="def:link-destination" foreground="mocha_blue" italic="true" underline="single"/>
<style name="def:heading" foreground="mocha_teal" bold="true"/>
<style name="def:thematic-break" foreground="mocha_green" bold="true"/>
<style name="def:preformatted-section" foreground="mocha_green"/>
<style name="def:list-marker" foreground="mocha_teal" bold="true"/>
<!-- Others -->
<style name="def:preprocessor" foreground="mocha_teal"/>
<style name="def:error" foreground="mocha_maroon" bold="true"/>
<style name="def:warning" foreground="mocha_peach"/>
<style name="def:note" foreground="mocha_blue" bold="true"/>
<style name="def:net-address" italic="true" underline="single"/>
</style-scheme>

View File

@@ -0,0 +1,123 @@
<style-scheme name="Peacocks In Space" id="peacocks-in-space" version="1.0">
<author> ITDominator</author>
<description>An attempted clone of Dayle Rees' Peacocks In Space theme.</description>
<style name="current-line" background="#2b303b" />
<style name="current-line-number" background="#f7b83d" />
<style name="draw-spaces" foreground="#babdb6" />
<style name="background-pattern" background="#6e7a94" />
<style name="bracket-match" foreground="#white" background="#gray" />
<style name="bracket-mismatch" foreground="#white" background="#FF5D38" />
<style name="right-margin" foreground="#dee3ec" background="#454a54" />
<style name="search-match" background="#E6DB74" />
<style name="def:comment" foreground="#8998b9" />
<style name="def:shebang" foreground="#00a8c6" bold="true" />
<style name="def:doc-comment-element" italic="true" />
<style name="def:constant" foreground="#E6DB74" />
<style name="def:special-char" foreground="#26A6A6" />
<style name="def:identifier" foreground="#FF5D38" />
<style name="def:statement" foreground="#26A6A6" bold="true" />
<style name="def:type" foreground="#E6DB74" bold="true" />
<style name="def:preprocessor" foreground="#8998b9" />
<style name="def:error" background="#FF5D38" bold="true" />
<style name="def:warning" background="#f7b83d" />
<style name="def:note" foreground="#00a8c6" background="#yellow" bold="true" />
<style name="def:underlined" italic="true" underline="true" />
<style name="diff:added-line" foreground="#008B8B" />
<style name="diff:removed-line" foreground="#6A5ACD" />
<style name="diff:changed-line" foreground="#8998b9" />
<style name="diff:special-case" foreground="#E6DB74" />
<style name="diff:location" foreground="#26A6A6" bold="true" />
<style name="diff:diff-file" foreground="#E6DB74" bold="true" />
<style name="xml:tags" foreground="#00a8c6" />
<style name="xml:attribute-name" foreground="#ff5d38" />
<style name="xml:namespace" foreground="#E6DB74" bold="true" />
<style name="js:object" foreground="#2E8B57" bold="true" />
<style name="js:constructors" foreground="#008B8B" />
<style name="latex:display-math" foreground="#6A5ACD" />
<style name="latex:command" foreground="#2E8B57" bold="true" />
<style name="latex:include" foreground="#8998b9" />
<style name="sh:variable" foreground="#6A5ACD" />
<style name="Others" foreground="#2E8B57" bold="true" />
<style name="Others 2" foreground="#008B8B" />
<style name="Others 3" foreground="#6A5ACD" />
<style name="python:builtin-object" foreground="#00a8c6" />
<style name="python:class-name" foreground="#ff5d38" />
<style name="python:function-name" foreground="#e6db74" />
<style name="python:keyword" foreground="#00a8c6" />
<style name="python:special-variable" />
<style name="python:boolean" foreground="#ff5d38" />
<style name="python:complex" foreground="#ff5d38" />
<style name="python:format" foreground="#bf3f3f" />
<style name="python:builtin-constant" foreground="#ff5d38" />
<style name="python:builtin-function" foreground="#e6db74" />
<style name="python:module-handler" foreground="#00a8c6" />
<style name="python:escaped-char" foreground="#ff5d38" />
<style name="reserved" foreground="#ff5d38" />
<style name="operator" foreground="#00a8c6" />
<style name="keyword" foreground="#00a8c6" />
<style name="line-numbers" foreground="#ffffff" />
<style name="python3:function-name" foreground="#e6db74" />
<style name="text" />
<style name="emphasis" />
<style name="function" foreground="#e6db74" />
<style name="selection-unfocused" background="#ff7800" />
<style name="html:attrib-name" foreground="#ff5d38" />
<style name="html:dtd" />
<style name="html:attrib-value" foreground="#e6db74" />
<style name="xml:element-name" foreground="#00a8c6" />
<style name="xml:attribute-value" foreground="#e6db74" />
<style name="html:comment" foreground="#8998b9" />
<style name="xml:comment" foreground="#8998b9" />
<style name="python3:builtin-function" foreground="#ff5d38" />
<style name="python3:builtin-object" foreground="#ff5d38" />
<style name="python3:class-name" foreground="#ff5d38" />
<style name="python3:builtin-constant" foreground="#ff5d38" />
<style name="python3:complex" foreground="#e6db74" />
<style name="python3:escaped-char" foreground="#ff5d38" />
<style name="python3:decimal" />
<style name="python3:format" />
<style name="python3:base-n-integer" />
<style name="php:comment" foreground="#8998b9" />
<style name="php:string" foreground="#e6db74" />
<style name="json:keyname" foreground="#ff5d38" />
<style name="json:string" foreground="#e6db74" />
<style name="json:null-value" foreground="#ff5d38" />
<style name="json:float" foreground="#e6db74" />
<style name="json:boolean" foreground="#ff5d38" />
<style name="java:reserved" foreground="#ff5d38" />
<style name="js:function-expression" />
<style name="js:identifier" />
<style name="js:object-literal" />
<style name="js:expression-statement" foreground="#e6db74" />
<style name="js:expression" />
<style name="js:label-statement" />
<style name="js:variable-declaration" />
<style name="js:rest-syntax" />
<style name="js:regex-group" />
<style name="js:keyword" foreground="#00a8c6" />
<style name="js:grouping-operator" foreground="#ed333b" />
<style name="js:grouping" foreground="#2ec27e" />
<style name="js:escape" foreground="#ff5d38" />
<style name="js:directive" />
<style name="js:class-expression" />
<style name="js:built-in-property" />
<style name="js:built-in-object" />
<style name="js:built-in-method" />
<style name="js:built-in-function" />
<style name="js:built-in-constructor" />
<style name="js:block-statement" />
<style name="js:ternary-operator" foreground="#00a8c6" />
<style name="js:throw-statement" foreground="#00a8c6" />
<style name="js:try-catch-statement" foreground="#00a8c6" />
<style name="js:spread-syntax" />
<style name="js:switch-statement" foreground="#00a8c6" />
<style name="python3:keyword" foreground="#00a8c6" />
<style name="python3:module-handler" foreground="#00a8c6" />
<style name="python3:method-calls" foreground="#e6db74" />
<style name="java:keyword" foreground="#8998b9" />
<style name="method-calls" foreground="#e6db74" />
<style name="xml:processing-instruction" />
<style name="xml:cdata-delim" foreground="#8998b9" />
<style name="gdscript:method-calls" foreground="#e6db74" />
</style-scheme>

View File

@@ -0,0 +1,119 @@
<style-scheme name="Penguins In Space" id="penguins-in-space" version="1.0">
<author> ITDominator</author>
<description>An homage to Dayle Rees' Peacocks In Space theme.</description>
<style name="current-line" background="#2b303b" />
<style name="current-line-number" background="#f7b83d" />
<style name="draw-spaces" foreground="#babdb6" />
<style name="background-pattern" background="#6e7a94" />
<style name="bracket-match" foreground="#white" background="#gray" />
<style name="bracket-mismatch" foreground="#white" background="#FF5D38" />
<style name="right-margin" foreground="#dee3ec" background="#454a54" />
<style name="search-match" background="#E6DB74" />
<style name="def:comment" foreground="#454a54" />
<style name="def:shebang" foreground="#00a8c6" bold="true" />
<style name="def:doc-comment-element" italic="true" />
<style name="def:constant" foreground="#E6DB74" />
<style name="def:special-char" foreground="#26A6A6" />
<style name="def:identifier" foreground="#FF5D38" />
<style name="def:statement" foreground="#26A6A6" bold="true" />
<style name="def:type" foreground="#E6DB74" bold="true" />
<style name="def:preprocessor" foreground="#8998b9" />
<style name="def:error" background="#FF5D38" bold="true" />
<style name="def:warning" background="#f7b83d" />
<style name="def:note" foreground="#00a8c6" background="#yellow" bold="true" />
<style name="def:underlined" italic="true" underline="true" />
<style name="diff:added-line" foreground="#008B8B" />
<style name="diff:removed-line" foreground="#6A5ACD" />
<style name="diff:changed-line" foreground="#8998b9" />
<style name="diff:special-case" foreground="#E6DB74" />
<style name="diff:location" foreground="#26A6A6" bold="true" />
<style name="diff:diff-file" foreground="#E6DB74" bold="true" />
<style name="xml:tags" foreground="#00a8c6" />
<style name="xml:attribute-name" foreground="#ff5d38" />
<style name="xml:namespace" foreground="#E6DB74" bold="true" />
<style name="js:object" foreground="#2E8B57" bold="true" />
<style name="js:constructors" foreground="#008B8B" />
<style name="latex:display-math" foreground="#6A5ACD" />
<style name="latex:command" foreground="#2E8B57" bold="true" />
<style name="latex:include" foreground="#8998b9" />
<style name="sh:variable" foreground="#6A5ACD" />
<style name="Others" foreground="#2E8B57" bold="true" />
<style name="Others 2" foreground="#008B8B" />
<style name="Others 3" foreground="#6A5ACD" />
<style name="python:builtin-object" foreground="#00a8c6" />
<style name="python:class-name" foreground="#ff5d38" />
<style name="python:function-name" foreground="#e6db74" />
<style name="python:keyword" foreground="#00a8c6" />
<style name="python:special-variable" foreground="#26a269" />
<style name="python:boolean" foreground="#ff5d38" />
<style name="python:complex" foreground="#ff5d38" />
<style name="python:format" foreground="#bf3f3f" />
<style name="python:builtin-constant" foreground="#ff5d38" />
<style name="python:builtin-function" foreground="#e6db74" />
<style name="python:module-handler" foreground="#00a8c6" />
<style name="python:escaped-char" foreground="#ff5d38" />
<style name="reserved" foreground="#ff5d38" />
<style name="operator" foreground="#00a8c6" />
<style name="keyword" foreground="#00a8c6" />
<style name="line-numbers" foreground="#ffffff" />
<style name="python3:function-name" foreground="#e6db74" />
<style name="text" />
<style name="emphasis" />
<style name="function" foreground="#e6db74" />
<style name="selection-unfocused" background="#ff7800" />
<style name="html:attrib-name" foreground="#ff5d38" />
<style name="html:dtd" />
<style name="html:attrib-value" foreground="#e6db74" />
<style name="xml:element-name" foreground="#00a8c6" />
<style name="xml:attribute-value" foreground="#e6db74" />
<style name="html:comment" foreground="#8998b9" />
<style name="xml:comment" foreground="#8998b9" />
<style name="python3:builtin-function" foreground="#ff5d38" />
<style name="python3:builtin-object" foreground="#ff5d38" />
<style name="python3:class-name" foreground="#ff5d38" />
<style name="python3:builtin-constant" foreground="#ff5d38" />
<style name="python3:complex" foreground="#e6db74" />
<style name="python3:escaped-char" foreground="#ff5d38" />
<style name="python3:decimal" />
<style name="python3:format" />
<style name="python3:base-n-integer" />
<style name="php:comment" foreground="#8998b9" />
<style name="php:string" foreground="#e6db74" />
<style name="json:keyname" foreground="#ff5d38" />
<style name="json:string" foreground="#e6db74" />
<style name="json:null-value" foreground="#e01b24" />
<style name="json:float" foreground="#00a8c6" />
<style name="json:boolean" foreground="#33d17a" />
<style name="java:reserved" foreground="#ff5d38" />
<style name="js:function-expression" />
<style name="js:identifier" />
<style name="js:object-literal" />
<style name="js:expression-statement" foreground="#e6db74" />
<style name="js:expression" />
<style name="js:label-statement" />
<style name="js:variable-declaration" />
<style name="js:rest-syntax" />
<style name="js:regex-group" />
<style name="js:keyword" foreground="#00a8c6" />
<style name="js:grouping-operator" foreground="#ed333b" />
<style name="js:grouping" foreground="#2ec27e" />
<style name="js:escape" foreground="#ff5d38" />
<style name="js:directive" />
<style name="js:class-expression" />
<style name="js:built-in-property" />
<style name="js:built-in-object" />
<style name="js:built-in-method" />
<style name="js:built-in-function" />
<style name="js:built-in-constructor" />
<style name="js:block-statement" />
<style name="js:ternary-operator" foreground="#00a8c6" />
<style name="js:throw-statement" foreground="#00a8c6" />
<style name="js:try-catch-statement" foreground="#00a8c6" />
<style name="js:spread-syntax" />
<style name="js:switch-statement" foreground="#00a8c6" />
<style name="python:multiline-string" foreground="#454a54" />
<style name="python3:method-calls" foreground="#e6db74" />
<style name="xml:cdata-delim" foreground="#8998b9" />
<style name="gdscript:method-calls" foreground="#e6db74" />
</style-scheme>

View File

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

View File

@@ -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;
}

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,23 +1,12 @@
{
"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",
"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"
"guake_key" : "",
"rename-files" : ["F2", "<Control>e"],
"open-terminal" : "F4",
"refresh-tab" : ["F5", "<Control>r"],
"load-interactive-debug" : "<Control>d",
"tggl-top-main-menubar" : "Alt_L",
"tear-down" : "<Control>q"
}
}

View File

@@ -1,3 +1,37 @@
/* ---- Make most desired things base transparent ---- */
popover,
popover > box,
notebook,
header,
stack,
scrolledwindow,
viewport {
background: rgba(0, 0, 0, 0.0);
color: rgba(255, 255, 255, 1);
}
tab {
color: rgba(255, 255, 255, 1);
}
tab:checked {
border-bottom-color: rgba(125, 125, 125, 1);
}
.main-window,
.base-container,
.body-container,
.center-container,
.header-container,
.footer-container,
.left-containerm,
.right-container {
background: rgba(0, 0, 0, 0.0);
color: rgba(255, 255, 255, 1);
}
.base-container {
margin: 10px;
}
@@ -128,3 +162,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); }