diff --git a/src/cthulhu/plugins/Clipboard/plugin.py b/src/cthulhu/plugins/Clipboard/plugin.py index e21e6ae..5388d87 100644 --- a/src/cthulhu/plugins/Clipboard/plugin.py +++ b/src/cthulhu/plugins/Clipboard/plugin.py @@ -20,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 """Clipboard plugin for Cthulhu.""" @@ -62,6 +64,36 @@ class Clipboard(Plugin): except Exception as e: logger.error(f"Error activating Clipboard plugin: {e}") + @cthulhu_hookimpl + def deactivate(self, plugin=None): + """Deactivate the plugin.""" + # Skip if this deactivation call isn't for us + if plugin is not None and plugin is not self: + return + + logger.info("Deactivating Clipboard plugin") + try: + # Unregister keyboard shortcut + if self.app: + api_helper = self.app.getAPIHelper() + if api_helper and hasattr(api_helper, 'unregisterShortcut'): + api_helper.unregisterShortcut('kb:cthulhu+shift+c') + logger.debug("Unregistered clipboard shortcut") + except Exception as e: + logger.error(f"Error deactivating Clipboard plugin: {e}") + """Activate the plugin.""" + # Skip if this activation call isn't for us + if plugin is not None and plugin is not self: + return + + logger.info("Activating Clipboard plugin") + try: + # Register keyboard shortcut + self.registerGestureByString(self.speakClipboard, _('clipboard'), 'kb:cthulhu+shift+c') + logger.debug("Registered shortcut for clipboard") + except Exception as e: + logger.error(f"Error activating Clipboard plugin: {e}") + @cthulhu_hookimpl def deactivate(self, plugin=None): """Deactivate the plugin.""" diff --git a/src/cthulhu/plugins/SimplePluginSystem/plugin.py b/src/cthulhu/plugins/SimplePluginSystem/plugin.py index 3ad1de9..95948ea 100644 --- a/src/cthulhu/plugins/SimplePluginSystem/plugin.py +++ b/src/cthulhu/plugins/SimplePluginSystem/plugin.py @@ -1,9 +1,6 @@ #!/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 @@ -20,8 +17,6 @@ # 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.""" @@ -57,11 +52,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) @@ -77,22 +72,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}") @@ -102,7 +97,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 @@ -144,7 +139,7 @@ class SimplePluginSystem(Plugin): # 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 @@ -254,7 +249,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): @@ -317,75 +312,95 @@ class SimplePluginSystem(Plugin): 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}") + if self.app: + api_helper = self.app.getAPIHelper() + if api_helper: + api_helper.registerGestureByString( + function, + description, + shortcut, + 'default', + 'cthulhu', + True, + contextName=self.module_name + ) + logger.debug(f"Registered shortcut {shortcut} for {description}") + return True + else: + logger.error("Could not get APIHelper") else: - logger.error("Could not get InputEventManager API") + logger.error("No app reference available") 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}") + if self.app: + api_helper = self.app.getAPIHelper() + if api_helper and hasattr(api_helper, 'unregisterShortcut'): + api_helper.unregisterShortcut(shortcut) + logger.debug(f"Unregistered shortcut {shortcut}") + return True + else: + logger.error("Could not get APIHelper or unregisterShortcut method") else: - logger.error("Could not get InputEventManager API") + logger.error("No app reference available") 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: + plugin_files = glob.glob(self.plugin_repo + '*') + self.plugin_list = [] # Reset the plugin list to avoid confusion + + for currplugin in plugin_files: try: + # Ensure currplugin is a valid path string + if not isinstance(currplugin, (str, bytes, os.PathLike)): + logger.error(f"Invalid plugin path: {type(currplugin)}") + continue + currPluginSetting = self.initSettings() currPluginSetting = self.getPluginSettings(currplugin, currPluginSetting) 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: