Merge pull request 'feature/lsp-integration-work' (#2) from feature/lsp-integration-work into develop

Reviewed-on: #2
This commit is contained in:
itdominator 2024-03-02 00:57:47 +00:00
commit d886ef37d4
20 changed files with 318 additions and 147 deletions

View File

@ -13,7 +13,10 @@ from .capabilities import Capabilities
class ReadPipe(threading.Thread):
def __init__(self, pipe):
threading.Thread.__init__(self)
self.pipe = pipe
self.daemon = True
self.pipe = pipe
def run(self):
line = self.pipe.readline().decode('utf-8')
@ -21,7 +24,6 @@ class ReadPipe(threading.Thread):
line = self.pipe.readline().decode('utf-8')
class LSPController:
def __init__(self, lsp_servers_config = {}):
super().__init__()
@ -29,6 +31,7 @@ class LSPController:
self.lsp_servers_config = lsp_servers_config
self.lsp_clients = {}
def _blame(self, response):
for d in response['diagnostics']:
if d['severity'] == 1:
@ -63,8 +66,10 @@ class LSPController:
if not language or not server_proc: return False
root_path = None
root_uri = 'file:///home/abaddon/Coding/Projects/Active/C_n_CPP_Projects/gtk/Newton/src/'
workspace_folders = [{'name': 'python-lsp', 'uri': root_uri}]
# root_uri = 'file:///home/abaddon/Coding/Projects/Active/Python_Projects/000_Usable/gtk/Newton_Editor/src/'
# workspace_folders = [{'name': 'python-lsp', 'uri': root_uri}]
root_uri = ''
workspace_folders = [{'name': '', 'uri': root_uri}]
lsp_client = self._generate_client(language, server_proc)
lsp_client.initialize(
@ -74,6 +79,7 @@ class LSPController:
initializationOptions = initialization_options, \
capabilities = Capabilities.data, \
trace = "off", \
# trace = "on", \
workspaceFolders = workspace_folders
)
@ -121,16 +127,17 @@ class LSPController:
return []
def do_change(self, language_id, line, start, end, text):
def do_change(self, uri, language_id, line, start, end, text):
if language_id in self.lsp_clients.keys():
start_pos = pylspclient.lsp_structs.Position(line, start.get_line_offset())
end_pos = pylspclient.lsp_structs.Position(line, end.get_line_offset())
range_info = pylspclient.lsp_structs.Range(start_pos, end_pos)
text_length = len(text)
change_event = pylspclient.lsp_structs.TextDocumentContentChangeEvent(range_info, text_length, text)
start_pos = pylspclient.lsp_structs.Position(line, start.get_line_offset())
end_pos = pylspclient.lsp_structs.Position(line, end.get_line_offset())
range_info = pylspclient.lsp_structs.Range(start_pos, end_pos)
text_length = len(text)
text_document = pylspclient.lsp_structs.TextDocumentItem(uri, language_id, 1, text)
change_event = pylspclient.lsp_structs.TextDocumentContentChangeEvent(range_info, text_length, text)
return self.lsp_clients[language_id].didChange( None, change_event )
return self.lsp_clients[language_id].didChange( text_document, change_event )
return []
@ -148,11 +155,12 @@ class LSPController:
return self.lsp_clients[language_id].completion(
pylspclient.lsp_structs.TextDocumentIdentifier(uri),
pylspclient.lsp_structs.Position(line, offset),
pylspclient.lsp_structs.CompletionContext(trigger, _char)
None
# pylspclient.lsp_structs.CompletionContext(trigger, _char)
)
return []
def load_lsp_server(self, language_id):
if not language_id in self.lsp_servers_config.keys():

View File

@ -24,7 +24,7 @@ class Plugin(PluginBase):
super().__init__()
self.name = "LSP Client" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus
# where self.name should not be needed for message comms
# where self.name should not be needed for message comms
self.lsp_config_path: str = os.path.dirname(os.path.realpath(__file__)) + "/../../lsp_servers_config.json"
self.lsp_servers_config: dict = {}
self.lsp_controller = None
@ -53,30 +53,18 @@ class Plugin(PluginBase):
def inner_subscribe_to_events(self):
self._event_system.subscribe("shutting_down", self._shutting_down)
self._event_system.subscribe("textDocument/didChange", self._buffer_changed)
self._event_system.subscribe("textDocument/didOpen", self.lsp_controller.do_open)
self._event_system.subscribe("textDocument/didSave", self.lsp_controller.do_save)
self._event_system.subscribe("textDocument/didClose", self.lsp_controller.do_close)
# self._event_system.subscribe("buffer_changed", self._buffer_changed)
self._event_system.subscribe("textDocument/didChange", self._buffer_changed)
self._event_system.subscribe("textDocument/didOpen", self.lsp_controller.do_open)
self._event_system.subscribe("textDocument/didSave", self.lsp_controller.do_save)
self._event_system.subscribe("textDocument/didClose", self.lsp_controller.do_close)
self._event_system.subscribe("textDocument/definition", self._do_goto)
self._event_system.subscribe("textDocument/completion", self.completion)
self._event_system.subscribe("textDocument/completion", self._do_completion)
def _shutting_down(self):
self.lsp_controller._shutting_down()
def cancel_timer(self):
if self.timer:
self.timer.cancel()
GLib.idle_remove_by_data(None)
def delay_completion_glib(self, source_view, context, callback):
GLib.idle_add(self._do_completion, source_view, context, callback)
def delay_completion(self, source_view, context, callback):
self.timer = threading.Timer(0.8, self.delay_completion_glib, (source_view, context, callback,))
self.timer.daemon = True
self.timer.start()
def _buffer_changed(self, language_id, buffer):
def _buffer_changed(self, file_type, buffer):
iter = buffer.get_iter_at_mark( buffer.get_insert() )
line = iter.get_line()
start = iter.copy()
@ -86,32 +74,34 @@ class Plugin(PluginBase):
start.forward_line()
end.forward_to_line_end()
text = buffer.get_text(start, end, include_hidden_chars = False)
result = self.lsp_controller.do_change(language_id, line, start, end, text)
# print(result)
text = buffer.get_text(start, end, include_hidden_chars = False)
result = self.lsp_controller.do_change(buffer.uri, buffer.language_id, line, start, end, text)
def completion(self, source_view, context, callback):
self.cancel_timer()
self.delay_completion(source_view, context, callback)
def _do_completion(self, source_view, context, callback):
filepath = source_view.get_current_file()
def _do_completion(self, source_view):
filepath = source_view.get_current_file()
if not filepath: return
uri = filepath.get_uri()
buffer = source_view.get_buffer()
iter = buffer.get_iter_at_mark( buffer.get_insert() )
line = iter.get_line() + 1
line = iter.get_line()
_char = iter.get_char()
if iter.backward_char():
_char = iter.get_char()
offset = iter.get_line_offset()
result = self.lsp_controller.do_completion(source_view.get_filetype(), uri, line, offset, _char)
callback(context, result)
result = self.lsp_controller.do_completion(
source_view.get_filetype(),
uri,
line,
offset,
_char
)
return result
def _do_goto(self, language_id, uri, line, offset):
results = self.lsp_controller.do_goto(language_id, uri, line, offset)

View File

@ -1,3 +1,8 @@
# Python imports
# Lib imports
# Application imports
from . import lsp_structs
@ -40,13 +45,13 @@ class LspClient(object):
"""
self.lsp_endpoint.start()
return self.lsp_endpoint.call_method("initialize", \
processId = processId, \
rootPath = rootPath, \
rootUri = rootUri, \
initializationOptions = initializationOptions, \
capabilities = capabilities, \
trace = trace, \
return self.lsp_endpoint.call_method("initialize",
processId = processId,
rootPath = rootPath,
rootUri = rootUri,
initializationOptions = initializationOptions,
capabilities = capabilities,
trace = trace,
workspaceFolders = workspaceFolders
)
@ -61,18 +66,12 @@ class LspClient(object):
def shutdown(self):
"""
The initialized notification is sent from the client to the server after the client received the result of the initialize request
but before the client is sending any other request or notification to the server. The server can use the initialized notification
for example to dynamically register capabilities. The initialized notification may only be sent once.
"""
return self.lsp_endpoint.call_method("shutdown")
def exit(self):
"""
The initialized notification is sent from the client to the server after the client received the result of the initialize request
but before the client is sending any other request or notification to the server. The server can use the initialized notification
for example to dynamically register capabilities. The initialized notification may only be sent once.
"""
self.lsp_endpoint.send_notification("exit")
@ -115,7 +114,7 @@ class LspClient(object):
The document change notification is sent from the client to the server to signal changes to a text document.
In 2.0 the shape of the params has changed to include proper version numbers and language ids.
:param VersionedTextDocumentIdentifier textDocument: The initial trace setting. If omitted trace is disabled ('off').
:param TextDocumentItem textDocument: The text document.
:param TextDocumentContentChangeEvent[] contentChanges: The actual content changes. The content changes describe single state changes
to the document. So if there are two content changes c1 and c2 for a document in state S then c1 move the document
to S' and c2 to S''.

View File

@ -10,9 +10,6 @@ import tracemalloc
tracemalloc.start()
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from __builtins__ import *
@ -20,34 +17,38 @@ from app import Application
def main(args, unknownargs):
setproctitle(f'{app_name}')
if args.debug == "true":
settings_manager.set_debug(True)
if args.trace_debug == "true":
settings_manager.set_trace_debug(True)
settings_manager.do_dirty_start_check()
Application(args, unknownargs)
if __name__ == "__main__":
''' Set process title, get arguments, and create GTK main thread. '''
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("--new-tab", "-nt", default="false", help="Opens a 'New Tab' if a handler is set for it.")
parser.add_argument("--new-window", "-w", default="", help="Open a file into a new window.")
# Read arguments (If any...)
args, unknownargs = parser.parse_known_args()
try:
setproctitle(f'{app_name}')
faulthandler.enable() # For better debug info
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("--new-tab", "-t", default="", help="Open a file into new tab.")
parser.add_argument("--new-window", "-w", default="", help="Open a file into a new window.")
# Read arguments (If any...)
args, unknownargs = parser.parse_known_args()
if args.debug == "true":
settings_manager.set_debug(True)
if args.trace_debug == "true":
settings_manager.set_trace_debug(True)
settings_manager.do_dirty_start_check()
Application(args, unknownargs)
Gtk.main()
main(args, unknownargs)
except Exception as e:
traceback.print_exc()
quit()

View File

@ -16,35 +16,39 @@ class AppLaunchException(Exception):
class Application(IPCServer):
class Application:
""" docstring for Application. """
def __init__(self, args, unknownargs):
super(Application, self).__init__()
if not settings_manager.is_trace_debug():
self.socket_realization_check()
if not self.is_ipc_alive:
for arg in unknownargs + [args.new_tab,]:
if os.path.isfile(arg):
message = f"FILE|{arg}"
self.send_ipc_message(message)
raise AppLaunchException(f"{app_name} IPC Server Exists: Have sent path(s) to it and closing...")
self.load_ipc(args, unknownargs)
self.setup_debug_hook()
Window(args, unknownargs)
Window(args, unknownargs).main()
def socket_realization_check(self):
def load_ipc(self, args, unknownargs):
ipc_server = IPCServer()
self.ipc_realization_check(ipc_server)
if not ipc_server.is_ipc_alive:
for arg in unknownargs + [args.new_tab,]:
if os.path.isfile(arg):
message = f"FILE|{arg}"
ipc_server.send_ipc_message(message)
raise AppLaunchException(f"{app_name} IPC Server Exists: Have sent path(s) to it and closing...")
def ipc_realization_check(self, ipc_server):
try:
self.create_ipc_listener()
ipc_server.create_ipc_listener()
except Exception:
self.send_test_ipc_message()
ipc_server.send_test_ipc_message()
try:
self.create_ipc_listener()
ipc_server.create_ipc_listener()
except Exception as e:
...

View File

@ -1,3 +0,0 @@
"""
Gtk Bound Signal Module
"""

View File

@ -14,9 +14,9 @@ from .editors_container import EditorsContainer
class CoreWidget(Gtk.Box):
class BaseContainer(Gtk.Box):
def __init__(self):
super(CoreWidget, self).__init__()
super(BaseContainer, self).__init__()
builder = settings_manager.get_builder()
self.ctx = self.get_style_context()

View File

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

View File

@ -10,13 +10,14 @@ from gi.repository import Gdk
from gi.repository import GLib
# Application imports
from .controller_data import ControllerData
from .containers.core_widget import CoreWidget
from .mixins.signals_mixins import SignalsMixins
from ..mixins.signals_mixins import SignalsMixins
from ..containers.base_container import BaseContainer
from .base_controller_data import BaseControllerData
class Controller(SignalsMixins, ControllerData):
class BaseController(SignalsMixins, BaseControllerData):
def __init__(self, args, unknownargs):
messages = []
for arg in unknownargs + [args.new_tab,]:
@ -60,7 +61,7 @@ class Controller(SignalsMixins, ControllerData):
self.builder.expose_object("main_window", self.window)
settings_manager.set_builder(self.builder)
self.core_widget = CoreWidget()
self.core_widget = BaseContainer()
settings_manager.register_signals_to_builder([self, self.core_widget])

View File

@ -9,9 +9,8 @@ from plugins.plugins_controller import PluginsController
class ControllerData:
''' ControllerData contains most of the state of the app at ay given time. It also has some support methods. '''
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()

View File

@ -39,7 +39,13 @@ class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider):
if buffer.get_context_classes_at_iter(iter) != ['no-spell-check']:
return False
event_system.emit("textDocument/completion", (self._source_view, context, self.do_populate))
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):
@ -49,7 +55,9 @@ class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider):
return GtkSource.CompletionActivation.INTERACTIVE
def do_populate(self, context, result = None):
result = event_system.emit_and_await("textDocument/completion", (self._source_view,))
proposals = []
if result:
if not result.items is None:
for item in result.items:
@ -86,6 +94,5 @@ class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider):
comp_item.set_icon( self.get_icon_for_type(item.kind) )
comp_item.set_info(item.documentation)
return comp_item
return comp_item

View File

@ -81,7 +81,7 @@ class KeyInputController:
return True
if keyname in ["z", "y", "m", "s", "h", "g", "equal", "minus", "Up", "Down"]:
if keyname in ["z", "y", "m", "s", "h", "g", "d", "k", "u", "equal", "minus", "Up", "Down"]:
if keyname == "z":
self.keyboard_undo()
if keyname == "y":
@ -94,6 +94,12 @@ class KeyInputController:
self.toggle_highlight_line()
if keyname == "g":
self.go_to_call()
if keyname == "d":
self.duplicate_line()
if keyname == "k":
self.cut_to_buffer()
if keyname == "u":
self.paste_cut_buffer()
if keyname == "equal":
self.scale_up_text()

View File

@ -6,12 +6,13 @@ 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 Gio
from gi.repository import GtkSource
# Application imports
from ..custom_completion_providers.lsp_completion_provider import LSPCompletionProvider
# from ..custom_completion_providers.lsp_completion_provider import LSPCompletionProvider
from ..custom_completion_providers.python_completion_provider import PythonCompletionProvider
class FileEventsMixin:
@ -79,7 +80,7 @@ class FileEventsMixin:
self.update_labels(gfile)
self._loading_file = False
self._file_loader.load_async(io_priority = 80,
self._file_loader.load_async(io_priority = GLib.PRIORITY_HIGH,
cancellable = None,
progress_callback = None,
progress_callback_data = None,
@ -139,19 +140,24 @@ class FileEventsMixin:
def _document_loaded(self, line: int = 0):
for provider in self._completion.get_providers():
self._completion.remove_provider(provider)
uri = self._current_file.get_uri()
buffer = self.get_buffer()
uri = self._current_file.get_uri()
buffer = self.get_buffer()
buffer.uri = uri
buffer.language_id = self._current_filetype
event_system.emit("textDocument/didOpen", (self._current_filetype, uri,))
word_completion = GtkSource.CompletionWords.new("word_completion")
word_completion.register(buffer)
self._completion.add_provider(word_completion)
lsp_completion_provider = LSPCompletionProvider(self)
self._completion.add_provider(lsp_completion_provider)
# lsp_completion_provider = LSPCompletionProvider(self)
# self._completion.add_provider(lsp_completion_provider)
# if self._current_filetype in ("python", "python3"):
# py_lsp_completion_provider = PythonCompletionProvider(uri)
# self._completion.add_provider(py_lsp_completion_provider)
self.got_to_line(buffer, line)
event_system.emit("buffer_changed_first_load", (buffer, ))

View File

@ -1,4 +1,5 @@
# Python imports
import threading
# Lib imports
import gi
@ -33,6 +34,9 @@ class SourceView(SourceViewControllerMixin, GtkSource.View):
self._current_filename: str = ""
self._current_filepath: str = None
self._current_filetype: str = "buffer"
self._cut_buffer: str = ""
self._timer: threading.Timer = None
self._idle_id: int = None
self._skip_file_load = False
self._ignore_internal_change = False
@ -95,4 +99,20 @@ class SourceView(SourceViewControllerMixin, GtkSource.View):
...
def _load_widgets(self):
self._set_up_dnd()
self._set_up_dnd()
def cancel_timer(self):
if self._timer:
self._timer.cancel()
GLib.idle_remove_by_data(self._idle_id)
def delay_cut_buffer_clear_glib(self):
self._idle_id = GLib.idle_add(self._clear_cut_buffer)
def clear_cut_buffer_delayed(self):
self._timer = threading.Timer(15, self.delay_cut_buffer_clear_glib, ())
self._timer.daemon = True
self._timer.start()
def _clear_cut_buffer(self):
self._cut_buffer = ""

View File

@ -34,6 +34,57 @@ class SourceViewControllerMixin(KeyInputController, SourceViewEvents):
event_system.emit("textDocument/definition", (self.get_filetype(), uri, line, offset,))
def duplicate_line(self, buffer = None):
buffer = self.get_buffer() if not buffer else buffer
itr = buffer.get_iter_at_mark( buffer.get_insert() )
start_itr = itr.copy()
end_itr = itr.copy()
start_line = itr.get_line() + 1
start_char = itr.get_line_offset()
start_itr.backward_visible_line()
start_itr.forward_line()
end_itr.forward_line()
end_itr.backward_char()
line_str = buffer.get_slice(start_itr, end_itr, True)
end_itr.forward_char()
buffer.insert(end_itr, f"{line_str}\n", -1)
new_itr = buffer.get_iter_at_line_offset(start_line, start_char)
buffer.place_cursor(new_itr)
def cut_to_buffer(self, buffer = None):
self.cancel_timer()
buffer = self.get_buffer() if not buffer else buffer
itr = buffer.get_iter_at_mark( buffer.get_insert() )
start_itr = itr.copy()
end_itr = itr.copy()
start_line = itr.get_line() + 1
start_char = itr.get_line_offset()
start_itr.backward_visible_line()
start_itr.forward_line()
end_itr.forward_line()
line_str = buffer.get_slice(start_itr, end_itr, True)
self._cut_buffer += f"{line_str}"
buffer.delete(start_itr, end_itr)
self.clear_cut_buffer_delayed()
def paste_cut_buffer(self, buffer = None):
self.cancel_timer()
buffer = self.get_buffer() if not buffer else buffer
itr = buffer.get_iter_at_mark( buffer.get_insert() )
insert_itr = itr.copy()
buffer.insert(insert_itr, self._cut_buffer, -1)
self.clear_cut_buffer_delayed()
def update_cursor_position(self, buffer = None):
buffer = self.get_buffer() if not buffer else buffer
@ -117,22 +168,67 @@ class SourceViewControllerMixin(KeyInputController, SourceViewEvents):
buffer.redo()
def keyboard_move_lines_up(self):
buffer = self.get_buffer()
buffer = self.get_buffer()
self.begin_user_action(buffer)
had_selection = buffer.get_has_selection()
itr = buffer.get_iter_at_mark( buffer.get_insert() )
line = itr.get_line() - 1
line_index = itr.get_line_index()
selection_bounds = None
if had_selection:
selection_bounds = buffer.get_selection_bounds()
sbounds_start = selection_bounds[0].get_line_offset()
sbounds_end = selection_bounds[1].get_line_offset()
self.emit("move-lines", *(False,))
# unindent_lines
# self.emit("move-words", *(self, 4,))
if not had_selection:
self.emit("select-all", *(False,))
line_itr = buffer.get_iter_at_line_offset(line, line_index)
self.get_buffer().place_cursor(line_itr)
else:
buffer = self.get_buffer()
sbounds = buffer.get_selection_bounds()
start_itr = buffer.get_iter_at_line_offset( sbounds[0].get_line(), sbounds_start)
end_itr = buffer.get_iter_at_line_offset( sbounds[1].get_line() - 1, sbounds_end)
self.emit("select-all", *(False,))
buffer.select_range(start_itr, end_itr)
self.end_user_action(buffer)
def keyboard_move_lines_down(self):
buffer = self.get_buffer()
buffer = self.get_buffer()
self.begin_user_action(buffer)
had_selection = buffer.get_has_selection()
itr = buffer.get_iter_at_mark( buffer.get_insert() )
line = itr.get_line() + 1
line_index = itr.get_line_index()
selection_bounds = None
sbounds_start = None
sbounds_end = None
if had_selection:
selection_bounds = buffer.get_selection_bounds()
sbounds_start = selection_bounds[0].get_line_offset()
sbounds_end = selection_bounds[1].get_line_offset()
self.emit("move-lines", *(True,))
# self.emit("move-words", *(self, -4,))
if not had_selection:
self.emit("select-all", *(False,))
line_itr = buffer.get_iter_at_line_offset(line, line_index)
self.get_buffer().place_cursor(line_itr)
else:
buffer = self.get_buffer()
sbounds = buffer.get_selection_bounds()
start_itr = buffer.get_iter_at_line_offset( sbounds[0].get_line(), sbounds_start)
end_itr = buffer.get_iter_at_line_offset( sbounds[1].get_line() - 1, sbounds_end)
self.emit("select-all", *(False,))
buffer.select_range(start_itr, end_itr)
self.end_user_action(buffer)

View File

@ -26,9 +26,8 @@ class SourceViewEvents(SourceViewDnDMixin, MarkEventsMixin, FileEventsMixin):
if not self._loading_file:
event_system.emit("buffer_changed", (buffer, ))
event_system.emit("textDocument/didChange", (file_type, buffer, ))
else:
event_system.emit("buffer_changed_first_load", (buffer, ))
# event_system.emit("textDocument/didChange", (file_type, buffer, ))
# event_system.emit("textDocument/completion", (self, ))
self.update_cursor_position(buffer)

View File

@ -1,5 +1,4 @@
# Python imports
import time
import signal
# Lib imports
@ -12,7 +11,8 @@ from gi.repository import Gdk
from gi.repository import GLib
# Application imports
from core.controller import Controller
from core.controllers.base_controller import BaseController
class ControllerStartExceptiom(Exception):
@ -20,7 +20,6 @@ class ControllerStartExceptiom(Exception):
class Window(Gtk.ApplicationWindow):
"""docstring for Window."""
@ -30,12 +29,12 @@ class Window(Gtk.ApplicationWindow):
self._controller = None
self._set_window_data()
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets(args, unknownargs)
self._set_window_data()
self._set_size_constraints()
self.show()
@ -49,21 +48,26 @@ class Window(Gtk.ApplicationWindow):
ctx = self.get_style_context()
ctx.add_class("main-window")
ctx.add_class(f"mw_transparency_{settings.theming.transparency}")
def _setup_signals(self):
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)
def _subscribe_to_events(self):
event_system.subscribe("tear_down", self._tear_down)
event_system.subscribe("load_interactive_debug", self._load_interactive_debug)
def _load_widgets(self, args, unknownargs):
if settings_manager.is_debug():
self.set_interactive_debugging(True)
self._controller = Controller(args, unknownargs)
self._controller = BaseController(args, unknownargs)
if not self._controller:
raise ControllerStartException("Controller exited and doesn't exist...")
raise ControllerStartException("BaseController exited and doesn't exist...")
self.add( self._controller.get_core_widget() )
@ -83,7 +87,7 @@ class Window(Gtk.ApplicationWindow):
screen = self.get_screen()
visual = screen.get_rgba_visual()
if visual != None and screen.is_composited():
if visual != None 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)
@ -102,6 +106,15 @@ class Window(Gtk.ApplicationWindow):
cr.set_operator(cairo.OPERATOR_OVER)
def _on_focus_in_event(self, widget, event):
event_system.emit("pause_dnd_signals")
def _on_focus_out_event(self, widget, event):
event_system.emit("listen_dnd_signals")
def _load_interactive_debug(self):
self.set_interactive_debugging(True)
def _tear_down(self, widget = None, eve = None):
event_system.emit("shutting_down")
@ -116,3 +129,6 @@ class Window(Gtk.ApplicationWindow):
settings_manager.clear_pid()
Gtk.main_quit()
def main(self):
Gtk.main()

View File

@ -70,4 +70,4 @@ class EventSystem(Singleton):
if not response in (None, ''):
break
return response
return response

View File

@ -12,13 +12,27 @@ function main() {
files=()
for f in "$@"; do
# ff=${f%:*}
# ii=${f#*:}
# target=$(readlink -f "${ff}")
target=$(readlink -f "${f}")
i="${#files[@]}"
size=$(($i + 1))
files[$size]="${target}"
# if [ -n "$ii" ]; then
# files[$size]="${target}:${ii}"
# else
# files[$size]="${target}${ii}"
# fi
done
echo "${files[@]}"
cd "/opt/"
python /opt/newton.zip "${files[@]}"
}
main "$@";
main "$@";

View File

@ -81,6 +81,11 @@ notebook > stack > scrolledwindow > textview {
color: rgba(255, 255, 255, 1);
}
textview {
padding-bottom: 50em;
}
/* any popover */
popover {
background: rgba(39, 43, 52, 0.86);