From 8c21412b542ee396e37fd73fb4144016f2dbbd5c Mon Sep 17 00:00:00 2001 From: Chrys Date: Mon, 21 Oct 2024 02:17:53 +0200 Subject: [PATCH] add basic plugin capability --- README.md | 3 +- TODO | 2 - configure.ac | 11 ++++ src/cthulhu/Makefile.am | 12 +++- src/cthulhu/cthulhu.py | 133 +++++++++++++++++++++++++++++++++++----- src/cthulhu/settings.py | 4 ++ 6 files changed, 145 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index ddf0ba2..77ee4a4 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Cthulhu also has the following dependencies: * Python 3 - Python platform * pygobject-3.0 - Python bindings for the GObject library +* libpeas - GObject based Plugin engine * gtk+-3.0 - GTK+ toolkit * json-py - a JSON () reader and writer in Python * python-speechd - Python bindings for Speech Dispatcher (optional) @@ -71,4 +72,4 @@ within Cthulhu as well as at: So, you want to write a script for Cthulhu? The best thing to do is start by looking at other scripts under the src/cthulhu/scripts/ hierarchy -of the source tree. \ No newline at end of file +of the source tree. diff --git a/TODO b/TODO index 5994764..46c2025 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,4 @@ - Add Simple Orca Plugin System as native code for Cthulhu -- Merge Chrys' plugin work. - Merge in sleep mode. -- Add in system for Cthulhu to have self voicing option. Probably based on socat. - Add in ocrdesktop code so that Cthulhu has native ocr support. - Get rid of build systems. My hope is git clone and run so long as requirements are satisfied. diff --git a/configure.ac b/configure.ac index f5b046a..f3c5ed7 100644 --- a/configure.ac +++ b/configure.ac @@ -118,6 +118,17 @@ src/cthulhu/scripts/toolkits/GAIL/Makefile src/cthulhu/scripts/toolkits/Qt/Makefile src/cthulhu/scripts/toolkits/WebKitGtk/Makefile src/cthulhu/scripts/toolkits/gtk/Makefile +src/cthulhu/plugins/Makefile +src/cthulhu/plugins/ByeCthulhu/Makefile +src/cthulhu/plugins/HelloCthulhu/Makefile +src/cthulhu/plugins/PluginManager/Makefile +src/cthulhu/plugins/Clipboard/Makefile +src/cthulhu/plugins/HelloWorld/Makefile +src/cthulhu/plugins/CapsLockHack/Makefile +src/cthulhu/plugins/SelfVoice/Makefile +src/cthulhu/plugins/Date/Makefile +src/cthulhu/plugins/Time/Makefile +src/cthulhu/plugins/MouseReview/Makefile src/cthulhu/backends/Makefile src/cthulhu/cthulhu_bin.py src/cthulhu/cthulhu_i18n.py diff --git a/src/cthulhu/Makefile.am b/src/cthulhu/Makefile.am index 8196786..c413610 100644 --- a/src/cthulhu/Makefile.am +++ b/src/cthulhu/Makefile.am @@ -32,6 +32,7 @@ cthulhu_python_PYTHON = \ date_and_time_presenter.py \ debug.py \ desktop_keyboardmap.py \ + dynamic_api_manager.py \ event_manager.py \ find.py \ flat_review.py \ @@ -63,14 +64,18 @@ cthulhu_python_PYTHON = \ cthulhu_i18n.py \ cthulhu_state.py \ phonnames.py \ + plugin.py \ cthulhu_platform.py \ + plugin_system_manager.py \ pronunciation_dict.py \ punctuation_settings.py \ + resource_manager.py \ script.py \ script_manager.py \ script_utilities.py \ settings.py \ settings_manager.py \ + signal_manager.py \ sound.py \ sound_generator.py \ speech_and_verbosity_manager.py \ @@ -81,14 +86,17 @@ cthulhu_python_PYTHON = \ speechserver.py \ structural_navigation.py \ text_attribute_names.py \ + translation_context.py \ + translation_manager.py \ tutorialgenerator.py \ where_am_i_presenter.py cthulhu_pythondir=$(pkgpythondir) SUBDIRS = \ - scripts \ - backends + backends \ + scripts \ + plugins ui_DATA = \ cthulhu-find.ui \ diff --git a/src/cthulhu/cthulhu.py b/src/cthulhu/cthulhu.py index 9166754..8804e86 100644 --- a/src/cthulhu/cthulhu.py +++ b/src/cthulhu/cthulhu.py @@ -42,6 +42,7 @@ gi.require_version("Atspi", "2.0") gi.require_version("Gdk", "3.0") from gi.repository import Atspi from gi.repository import Gdk +from gi.repository import GObject try: from gi.repository.Gio import Settings @@ -52,10 +53,11 @@ except Exception: from . import braille from . import debug from . import event_manager +from . import keybindings from . import learn_mode_presenter from . import logger from . import messages -from . import mouse_review +from . import notification_presenter from . import cthulhu_state from . import cthulhu_platform from . import script_manager @@ -63,9 +65,24 @@ from . import settings from . import settings_manager from . import speech from . import sound +from . import mouse_review from .ax_object import AXObject from .ax_utilities import AXUtilities from .input_event import BrailleEvent +from . import cmdnames +from . import plugin_system_manager +from . import guilabels +from . import acss +from . import text_attribute_names +from . import speechserver +from . import input_event +from . import pronunciation_dict +from . import cthulhu_gtkbuilder +from . import signal_manager +from . import dynamic_api_manager +from . import translation_manager +from . import resource_manager + _eventManager = event_manager.getManager() _scriptManager = script_manager.getManager() @@ -428,6 +445,7 @@ def loadUserSettings(script=None, inputEvent=None, skipReloadMessage=False): braille.shutdown() _scriptManager.deactivate() + cthulhuApp.getSignalManager().emitSignal('load-setting-begin') reloaded = False if _userSettings: @@ -500,9 +518,14 @@ def loadUserSettings(script=None, inputEvent=None, skipReloadMessage=False): _storeXmodmap(_cthulhuModifiers) _createCthulhuXmodmap() + activePlugins = list(_settingsManager.getSetting('activePlugins')) + cthulhuApp.getPluginSystemManager().setActivePlugins(activePlugins) + _scriptManager.activate() _eventManager.activate() + cthulhuApp.getSignalManager().emitSignal('load-setting-completed') + debug.printMessage(debug.LEVEL_INFO, 'ORCA: User Settings Loaded', True) return True @@ -721,7 +744,9 @@ def shutdown(script=None, inputEvent=None): signal.alarm(settings.timeoutTime) cthulhu_state.activeScript.presentationInterrupt() - cthulhu_state.activeScript.presentMessage(messages.STOP_ORCA, resetStyles=False) + + cthulhuApp.getSignalManager().emitSignal('stop-application-completed') + cthulhuApp.getPluginSystemManager().unloadAllPlugins(ForceAllPlugins=True) # Deactivate the event manager first so that it clears its queue and will not # accept new events. Then let the script manager unregister script event listeners. @@ -797,11 +822,6 @@ def crashOnSignal(signum, frame): debug.printMessage(debug.LEVEL_SEVERE, msg, True) debug.printStack(debug.LEVEL_SEVERE) _restoreXmodmap(_cthulhuModifiers) - try: - cthulhu_state.activeScript.presentationInterrupt() - cthulhu_state.activeScript.presentMessage(messages.STOP_ORCA, resetStyles=False) - except Exception: - pass sys.exit(1) def main(): @@ -847,14 +867,8 @@ def main(): init() debug.printMessage(debug.LEVEL_INFO, "ORCA: Initialized.", True) - try: - message = messages.START_ORCA - script = _scriptManager.getDefaultScript() - script.presentMessage(message) - except Exception: - debug.printException(debug.LEVEL_SEVERE) - script = cthulhu_state.activeScript + cthulhuApp.getSignalManager().emitSignal('start-application-completed') if script: window = script.utilities.activeWindow() @@ -887,5 +901,94 @@ def main(): die(EXIT_CODE_HANG) return 0 +class Cthulhu(GObject.Object): + # basic signals + __gsignals__ = { + "start-application-completed": (GObject.SignalFlags.RUN_LAST, None, ()), + "stop-application-completed": (GObject.SignalFlags.RUN_LAST, None, ()), + "load-setting-begin": (GObject.SignalFlags.RUN_LAST, None, ()), + "load-setting-completed": (GObject.SignalFlags.RUN_LAST, None, ()), + "setup-inputeventhandlers-completed": (GObject.SignalFlags.RUN_LAST, None, ()), # compat signal for register input event handlers + "request-cthulhu-preferences": (GObject.SignalFlags.RUN_LAST, None, ()), + "request-application-preferences": (GObject.SignalFlags.RUN_LAST, None, ()), + } + def __init__(self): + GObject.Object.__init__(self) + # add members + self.resourceManager = resource_manager.ResourceManager(self) + self.APIHelper = plugin_system_manager.APIHelper(self) + self.eventManager = _eventManager + self.settingsManager = _settingsManager + self.scriptManager = _scriptManager + self.signalManager = signal_manager.SignalManager(self) + self.dynamicApiManager = dynamic_api_manager.DynamicApiManager(self) + self.translationManager = translation_manager.TranslationManager(self) + self.debugManager = debug + self.createCompatAPI() + self.pluginSystemManager = plugin_system_manager.PluginSystemManager(self) + def getAPIHelper(self): + return self.APIHelper + def getPluginSystemManager(self): + return self.pluginSystemManager + def getDynamicApiManager(self): + return self.dynamicApiManager + def getSignalManager(self): + return self.signalManager + def getEventManager(self): + return self.eventManager + def getSettingsManager(self): + return self.settingsManager + def getScriptManager(self): + return self.scriptManager + def getDebugManager(self): + return self.debugManager + def getTranslationManager(self): + return self.translationManager + def getResourceManager(self): + return self.resourceManager + def run(self, cacheValues=True): + return main(cacheValues) + def stop(self): + pass + def createCompatAPI(self): + # for now add compatibility layer using Dynamic API + # should be removed step by step + # use clean objects, getters and setters instead + + self.getDynamicApiManager().registerAPI('Logger', _logger) + self.getDynamicApiManager().registerAPI('SettingsManager', settings_manager) + self.getDynamicApiManager().registerAPI('ScriptManager', script_manager) + self.getDynamicApiManager().registerAPI('EventManager', event_manager) + self.getDynamicApiManager().registerAPI('Speech', speech) + self.getDynamicApiManager().registerAPI('Sound', sound) + self.getDynamicApiManager().registerAPI('Braille', braille) + self.getDynamicApiManager().registerAPI('Debug', debug) + self.getDynamicApiManager().registerAPI('Messages', messages) + self.getDynamicApiManager().registerAPI('Cmdnames', cmdnames) + self.getDynamicApiManager().registerAPI('NotificationPresenter', notification_presenter) + self.getDynamicApiManager().registerAPI('CthulhuState', cthulhu_state) + self.getDynamicApiManager().registerAPI('CthulhuPlatform', cthulhu_platform) + self.getDynamicApiManager().registerAPI('Settings', settings) + self.getDynamicApiManager().registerAPI('Keybindings', keybindings) + self.getDynamicApiManager().registerAPI('GuiLabels', guilabels) + self.getDynamicApiManager().registerAPI('Acss', acss) + self.getDynamicApiManager().registerAPI('TextAttributeNames', text_attribute_names) + self.getDynamicApiManager().registerAPI('PronunciationDict', pronunciation_dict) + self.getDynamicApiManager().registerAPI('InputEvent', input_event) + self.getDynamicApiManager().registerAPI('SpeechServer', speechserver) + self.getDynamicApiManager().registerAPI('CthulhuGtkbuilder', cthulhu_gtkbuilder) + self.getDynamicApiManager().registerAPI('AXObject', AXObject) + self.getDynamicApiManager().registerAPI('AXUtilities', AXUtilities) + self.getDynamicApiManager().registerAPI('LearnModePresenter', learn_mode_presenter) + # cthulhu lets say, special compat handling.... + self.getDynamicApiManager().registerAPI('EmitRegionChanged', emitRegionChanged) + self.getDynamicApiManager().registerAPI('LoadUserSettings', loadUserSettings) + +cthulhuApp = Cthulhu() + +def getManager(): + return cthulhuApp + if __name__ == "__main__": - sys.exit(main()) + GObject.threads_init() + sys.exit(cthulhuApp.run()) diff --git a/src/cthulhu/settings.py b/src/cthulhu/settings.py index 1dd59a9..68f22d6 100644 --- a/src/cthulhu/settings.py +++ b/src/cthulhu/settings.py @@ -115,6 +115,7 @@ userCustomizableSettings = [ "presentDateFormat", "presentTimeFormat", "activeProfile", + "activePlugins", "startingProfile", "spellcheckSpellError", "spellcheckSpellSuggestion", @@ -404,3 +405,6 @@ structNavInSayAll = False enableSadPidginHack = False presentChatRoomLast = False presentLiveRegionFromInactiveTab = False + +# Plugins +activePlugins = ['Clipboard', 'MouseReview', 'Date', 'ByeCthulhu', 'Time', 'HelloCthulhu', 'HelloWorld', 'SelfVoice', 'PluginManager']