add basic plugin capability

This commit is contained in:
Chrys 2024-10-21 02:17:53 +02:00
parent 09bb9b149f
commit 8c21412b54
6 changed files with 145 additions and 20 deletions

View File

@ -28,6 +28,7 @@ Cthulhu also has the following dependencies:
* Python 3 - Python platform * Python 3 - Python platform
* pygobject-3.0 - Python bindings for the GObject library * pygobject-3.0 - Python bindings for the GObject library
* libpeas - GObject based Plugin engine
* gtk+-3.0 - GTK+ toolkit * gtk+-3.0 - GTK+ toolkit
* json-py - a JSON (<https://json.org/>) reader and writer in Python * json-py - a JSON (<https://json.org/>) reader and writer in Python
* python-speechd - Python bindings for Speech Dispatcher (optional) * python-speechd - Python bindings for Speech Dispatcher (optional)

2
TODO
View File

@ -1,6 +1,4 @@
- Add Simple Orca Plugin System as native code for Cthulhu - Add Simple Orca Plugin System as native code for Cthulhu
- Merge Chrys' plugin work.
- Merge in sleep mode. - 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. - 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. - Get rid of build systems. My hope is git clone and run so long as requirements are satisfied.

View File

@ -118,6 +118,17 @@ src/cthulhu/scripts/toolkits/GAIL/Makefile
src/cthulhu/scripts/toolkits/Qt/Makefile src/cthulhu/scripts/toolkits/Qt/Makefile
src/cthulhu/scripts/toolkits/WebKitGtk/Makefile src/cthulhu/scripts/toolkits/WebKitGtk/Makefile
src/cthulhu/scripts/toolkits/gtk/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/backends/Makefile
src/cthulhu/cthulhu_bin.py src/cthulhu/cthulhu_bin.py
src/cthulhu/cthulhu_i18n.py src/cthulhu/cthulhu_i18n.py

View File

@ -32,6 +32,7 @@ cthulhu_python_PYTHON = \
date_and_time_presenter.py \ date_and_time_presenter.py \
debug.py \ debug.py \
desktop_keyboardmap.py \ desktop_keyboardmap.py \
dynamic_api_manager.py \
event_manager.py \ event_manager.py \
find.py \ find.py \
flat_review.py \ flat_review.py \
@ -63,14 +64,18 @@ cthulhu_python_PYTHON = \
cthulhu_i18n.py \ cthulhu_i18n.py \
cthulhu_state.py \ cthulhu_state.py \
phonnames.py \ phonnames.py \
plugin.py \
cthulhu_platform.py \ cthulhu_platform.py \
plugin_system_manager.py \
pronunciation_dict.py \ pronunciation_dict.py \
punctuation_settings.py \ punctuation_settings.py \
resource_manager.py \
script.py \ script.py \
script_manager.py \ script_manager.py \
script_utilities.py \ script_utilities.py \
settings.py \ settings.py \
settings_manager.py \ settings_manager.py \
signal_manager.py \
sound.py \ sound.py \
sound_generator.py \ sound_generator.py \
speech_and_verbosity_manager.py \ speech_and_verbosity_manager.py \
@ -81,14 +86,17 @@ cthulhu_python_PYTHON = \
speechserver.py \ speechserver.py \
structural_navigation.py \ structural_navigation.py \
text_attribute_names.py \ text_attribute_names.py \
translation_context.py \
translation_manager.py \
tutorialgenerator.py \ tutorialgenerator.py \
where_am_i_presenter.py where_am_i_presenter.py
cthulhu_pythondir=$(pkgpythondir) cthulhu_pythondir=$(pkgpythondir)
SUBDIRS = \ SUBDIRS = \
backends \
scripts \ scripts \
backends plugins
ui_DATA = \ ui_DATA = \
cthulhu-find.ui \ cthulhu-find.ui \

View File

@ -42,6 +42,7 @@ gi.require_version("Atspi", "2.0")
gi.require_version("Gdk", "3.0") gi.require_version("Gdk", "3.0")
from gi.repository import Atspi from gi.repository import Atspi
from gi.repository import Gdk from gi.repository import Gdk
from gi.repository import GObject
try: try:
from gi.repository.Gio import Settings from gi.repository.Gio import Settings
@ -52,10 +53,11 @@ except Exception:
from . import braille from . import braille
from . import debug from . import debug
from . import event_manager from . import event_manager
from . import keybindings
from . import learn_mode_presenter from . import learn_mode_presenter
from . import logger from . import logger
from . import messages from . import messages
from . import mouse_review from . import notification_presenter
from . import cthulhu_state from . import cthulhu_state
from . import cthulhu_platform from . import cthulhu_platform
from . import script_manager from . import script_manager
@ -63,9 +65,24 @@ from . import settings
from . import settings_manager from . import settings_manager
from . import speech from . import speech
from . import sound from . import sound
from . import mouse_review
from .ax_object import AXObject from .ax_object import AXObject
from .ax_utilities import AXUtilities from .ax_utilities import AXUtilities
from .input_event import BrailleEvent 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() _eventManager = event_manager.getManager()
_scriptManager = script_manager.getManager() _scriptManager = script_manager.getManager()
@ -428,6 +445,7 @@ def loadUserSettings(script=None, inputEvent=None, skipReloadMessage=False):
braille.shutdown() braille.shutdown()
_scriptManager.deactivate() _scriptManager.deactivate()
cthulhuApp.getSignalManager().emitSignal('load-setting-begin')
reloaded = False reloaded = False
if _userSettings: if _userSettings:
@ -500,9 +518,14 @@ def loadUserSettings(script=None, inputEvent=None, skipReloadMessage=False):
_storeXmodmap(_cthulhuModifiers) _storeXmodmap(_cthulhuModifiers)
_createCthulhuXmodmap() _createCthulhuXmodmap()
activePlugins = list(_settingsManager.getSetting('activePlugins'))
cthulhuApp.getPluginSystemManager().setActivePlugins(activePlugins)
_scriptManager.activate() _scriptManager.activate()
_eventManager.activate() _eventManager.activate()
cthulhuApp.getSignalManager().emitSignal('load-setting-completed')
debug.printMessage(debug.LEVEL_INFO, 'ORCA: User Settings Loaded', True) debug.printMessage(debug.LEVEL_INFO, 'ORCA: User Settings Loaded', True)
return True return True
@ -721,7 +744,9 @@ def shutdown(script=None, inputEvent=None):
signal.alarm(settings.timeoutTime) signal.alarm(settings.timeoutTime)
cthulhu_state.activeScript.presentationInterrupt() 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 # 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. # 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.printMessage(debug.LEVEL_SEVERE, msg, True)
debug.printStack(debug.LEVEL_SEVERE) debug.printStack(debug.LEVEL_SEVERE)
_restoreXmodmap(_cthulhuModifiers) _restoreXmodmap(_cthulhuModifiers)
try:
cthulhu_state.activeScript.presentationInterrupt()
cthulhu_state.activeScript.presentMessage(messages.STOP_ORCA, resetStyles=False)
except Exception:
pass
sys.exit(1) sys.exit(1)
def main(): def main():
@ -847,14 +867,8 @@ def main():
init() init()
debug.printMessage(debug.LEVEL_INFO, "ORCA: Initialized.", True) 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 script = cthulhu_state.activeScript
cthulhuApp.getSignalManager().emitSignal('start-application-completed')
if script: if script:
window = script.utilities.activeWindow() window = script.utilities.activeWindow()
@ -887,5 +901,94 @@ def main():
die(EXIT_CODE_HANG) die(EXIT_CODE_HANG)
return 0 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__": if __name__ == "__main__":
sys.exit(main()) GObject.threads_init()
sys.exit(cthulhuApp.run())

View File

@ -115,6 +115,7 @@ userCustomizableSettings = [
"presentDateFormat", "presentDateFormat",
"presentTimeFormat", "presentTimeFormat",
"activeProfile", "activeProfile",
"activePlugins",
"startingProfile", "startingProfile",
"spellcheckSpellError", "spellcheckSpellError",
"spellcheckSpellSuggestion", "spellcheckSpellSuggestion",
@ -404,3 +405,6 @@ structNavInSayAll = False
enableSadPidginHack = False enableSadPidginHack = False
presentChatRoomLast = False presentChatRoomLast = False
presentLiveRegionFromInactiveTab = False presentLiveRegionFromInactiveTab = False
# Plugins
activePlugins = ['Clipboard', 'MouseReview', 'Date', 'ByeCthulhu', 'Time', 'HelloCthulhu', 'HelloWorld', 'SelfVoice', 'PluginManager']