From 1b4c4916e3cd31f8fbbce6cb1a03af039392acbe Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Fri, 4 Apr 2025 16:33:53 -0400 Subject: [PATCH] Hopefully fixed an error in simple plugin system. --- .../plugins/SimplePluginSystem/plugin.py | 81 +++++++++++++++---- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/src/cthulhu/plugins/SimplePluginSystem/plugin.py b/src/cthulhu/plugins/SimplePluginSystem/plugin.py index f53c663..3ad1de9 100644 --- a/src/cthulhu/plugins/SimplePluginSystem/plugin.py +++ b/src/cthulhu/plugins/SimplePluginSystem/plugin.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 # # Copyright (c) 2024 Stormux +# Copyright (c) 2010-2012 The Orca Team +# Copyright (c) 2012 Igalia, S.L. +# Copyright (c) 2005-2010 Sun Microsystems Inc. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -17,6 +20,8 @@ # Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Boston MA 02110-1301 USA. # +# Fork of Orca Screen Reader (GNOME) +# Original source: https://gitlab.gnome.org/GNOME/orca """Simple Plugin System for Cthulhu.""" @@ -28,9 +33,13 @@ import string import _thread import logging from subprocess import Popen, PIPE +import gettext from cthulhu.plugin import Plugin, cthulhu_hookimpl +# Set up translation function +_ = gettext.gettext + logger = logging.getLogger(__name__) # Global variables for API access @@ -48,11 +57,11 @@ def outputMessage(Message): class SimplePluginSystem(Plugin): """Simple plugin system implementation for Cthulhu. - + This plugin allows loading and managing simple script-based plugins from a designated directory. """ - + def __init__(self, *args, **kwargs): """Initialize the plugin system.""" super().__init__(*args, **kwargs) @@ -68,22 +77,22 @@ class SimplePluginSystem(Plugin): # Skip if this activation call isn't for us if plugin is not None and plugin is not self: return - + logger.info("Activating SimplePluginSystem plugin") try: global settings global speech global braille global input_event - + settings = self.app.getDynamicApiManager().getAPI('Settings') speech = self.app.getDynamicApiManager().getAPI('Speech') braille = self.app.getDynamicApiManager().getAPI('Braille') input_event = self.app.getDynamicApiManager().getAPI('InputEvent') - + if not self.loaded: self.load_plugins() - + except Exception as e: logger.error(f"Error activating SimplePluginSystem plugin: {e}") @@ -93,7 +102,7 @@ class SimplePluginSystem(Plugin): # Skip if this deactivation call isn't for us if plugin is not None and plugin is not self: return - + logger.info("Deactivating SimplePluginSystem plugin") try: # Remove all registered keybindings @@ -128,7 +137,15 @@ class SimplePluginSystem(Plugin): if shortcut != '': logger.debug(f"Registering shortcut: {shortcut}") currPluginSetting['shortcut'] = shortcut - self.registerGestureByString(currPluginSetting['function'], _(currPluginSetting['pluginname']), shortcut) + try: + # Try to use the translation function, fall back to plain text if it fails + plugin_name = _(currPluginSetting['pluginname']) + except Exception: + # If translation fails, use the original name + plugin_name = currPluginSetting['pluginname'] + logger.warning(f"Translation failed for plugin: {currPluginSetting['pluginname']}") + + self.registerGestureByString(currPluginSetting['function'], plugin_name, shortcut) return currPluginSetting def id_generator(self, size=7, chars=string.ascii_letters): @@ -237,7 +254,7 @@ class SimplePluginSystem(Plugin): currPluginSetting['loadmodule'] = ('sopsproperty:loadmodule' in line.lower().replace(" ", "")) or currPluginSetting['loadmodule'] except Exception as e: logger.error(f"Error reading plugin file: {e}") - + return currPluginSetting def buildPluginSubprocess(self, currPluginSetting): @@ -298,13 +315,45 @@ class SimplePluginSystem(Plugin): currPluginSetting['functionname'] = self.id_generator() return currPluginSetting + def registerGestureByString(self, function, description, shortcut): + """Register a keyboard shortcut for a function. + + This is a compatibility wrapper for the new plugin system. + """ + try: + # Try to get the InputEventManager and register the shortcut + input_manager = self.app.getDynamicApiManager().getAPI('InputEventManager') + if input_manager: + input_manager.registerGestureByString(function, description, shortcut) + logger.debug(f"Registered shortcut {shortcut} for {description}") + else: + logger.error("Could not get InputEventManager API") + except Exception as e: + logger.error(f"Error registering shortcut {shortcut}: {e}") + + def unregisterShortcut(self, function, shortcut): + """Unregister a keyboard shortcut for a function. + + This is a compatibility wrapper for the new plugin system. + """ + try: + # Try to get the InputEventManager and unregister the shortcut + input_manager = self.app.getDynamicApiManager().getAPI('InputEventManager') + if input_manager: + input_manager.unregisterGestureByString(shortcut) + logger.debug(f"Unregistered shortcut {shortcut}") + else: + logger.error("Could not get InputEventManager API") + except Exception as e: + logger.error(f"Error unregistering shortcut {shortcut}: {e}") + def load_plugins(self): """Load and setup all plugins in the plugin repository.""" if not self.loaded: try: logger.info(f"Loading plugins from {self.plugin_repo}") self.plugin_list = glob.glob(self.plugin_repo + '*') - + for currplugin in self.plugin_list: try: currPluginSetting = self.initSettings() @@ -313,30 +362,30 @@ class SimplePluginSystem(Plugin): if not currPluginSetting['valid']: logger.debug(f"Skipping invalid plugin: {currplugin}") continue - + currPluginSetting = self.getFunctionName(currPluginSetting) - + if currPluginSetting['loadmodule']: exec(self.buildPluginExec(currPluginSetting)) # load as python module else: exec(self.buildPluginSubprocess(currPluginSetting)) # run as subprocess - + if currPluginSetting['blockcall']: currPluginSetting['function'] = globals()[currPluginSetting['functionname']] # non threaded else: currPluginSetting['function'] = globals()[currPluginSetting['functionname'] + "T"] # T = Threaded - + if currPluginSetting['exec']: # exec on load if we want currPluginSetting['function']() if not currPluginSetting['key'] == '': currPluginSetting = self.SetupShortcutAndHandle(currPluginSetting) - + logger.debug(f"Loaded plugin: {currPluginSetting['pluginname']}") self.plugin_list.append(currPluginSetting) # store in a list except Exception as e: logger.error(f"Error loading plugin {currplugin}: {e}") - + self.loaded = True logger.info(f"Loaded {len(self.plugin_list)} plugins") except Exception as e: