Fixed some errors with plugins.

This commit is contained in:
Storm Dragon 2025-04-03 20:56:48 -04:00
parent d6a373c726
commit df7f4c5e62
8 changed files with 198 additions and 86 deletions

View File

@ -18,9 +18,15 @@ from enum import IntEnum
try: try:
import pluggy import pluggy
PLUGGY_AVAILABLE = True PLUGGY_AVAILABLE = True
logging.getLogger(__name__).info("Pluggy loaded successfully")
except ImportError: except ImportError:
PLUGGY_AVAILABLE = False PLUGGY_AVAILABLE = False
logging.getLogger(__name__).info("Pluggy not available, plugins will be disabled") logging.getLogger(__name__).warning("Pluggy not available (ImportError), plugins will be disabled")
except Exception as e:
PLUGGY_AVAILABLE = False
logging.getLogger(__name__).warning(f"Error loading pluggy: {str(e)}, plugins will be disabled")
import traceback
logging.getLogger(__name__).debug(traceback.format_exc())
# Set to True for more detailed plugin loading debug info # Set to True for more detailed plugin loading debug info
PLUGIN_DEBUG = True PLUGIN_DEBUG = True
@ -292,6 +298,11 @@ class PluginSystemManager:
"""Sync the active state of all plugins.""" """Sync the active state of all plugins."""
logger.info("Syncing active state of all plugins") logger.info("Syncing active state of all plugins")
# Skip if pluggy is not available
if not PLUGGY_AVAILABLE:
logger.warning("Pluggy not available, skipping plugin sync")
return
# Log plugin status before syncing # Log plugin status before syncing
if PLUGIN_DEBUG: if PLUGIN_DEBUG:
for pluginInfo in self.plugins: for pluginInfo in self.plugins:
@ -299,6 +310,7 @@ class PluginSystemManager:
is_loaded = pluginInfo.loaded is_loaded = pluginInfo.loaded
logger.debug(f"Plugin {pluginInfo.get_module_name()}: active={is_active}, loaded={is_loaded}") logger.debug(f"Plugin {pluginInfo.get_module_name()}: active={is_active}, loaded={is_loaded}")
try:
# First unload inactive plugins # First unload inactive plugins
for pluginInfo in self.plugins: for pluginInfo in self.plugins:
if not self.isPluginActive(pluginInfo) and pluginInfo.loaded: if not self.isPluginActive(pluginInfo) and pluginInfo.loaded:
@ -317,6 +329,10 @@ class PluginSystemManager:
logger.info(f"Active plugins after sync: {active_plugins}") logger.info(f"Active plugins after sync: {active_plugins}")
inactive_plugins = [p.get_module_name() for p in self.plugins if not p.loaded] inactive_plugins = [p.get_module_name() for p in self.plugins if not p.loaded]
logger.info(f"Inactive plugins after sync: {inactive_plugins}") logger.info(f"Inactive plugins after sync: {inactive_plugins}")
except Exception as e:
logger.error(f"Error syncing plugins: {e}")
import traceback
logger.error(traceback.format_exc())
def loadPlugin(self, pluginInfo): def loadPlugin(self, pluginInfo):
"""Load a plugin.""" """Load a plugin."""

View File

@ -26,13 +26,14 @@
from cthulhu import plugin from cthulhu import plugin
import gi, os import gi, os
gi.require_version('Peas', '1.0')
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Peas import logging
logger = logging.getLogger(__name__)
gi.require_version("Gtk", "3.0") gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk from gi.repository import Gtk, Gdk
class Clipboard(GObject.Object, Peas.Activatable, plugin.Plugin): class Clipboard(GObject.Object, plugin.Plugin):
#__gtype_name__ = 'Clipboard' #__gtype_name__ = 'Clipboard'
object = GObject.Property(type=GObject.Object) object = GObject.Property(type=GObject.Object)

View File

@ -26,11 +26,11 @@
from cthulhu import plugin from cthulhu import plugin
import gi, time import gi, time
gi.require_version('Peas', '1.0')
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Peas import logging
class Date(GObject.Object, Peas.Activatable, plugin.Plugin): logger = logging.getLogger(__name__)
class Date(GObject.Object, plugin.Plugin):
#__gtype_name__ = 'Date' #__gtype_name__ = 'Date'
object = GObject.Property(type=GObject.Object) object = GObject.Property(type=GObject.Object)

View File

@ -26,23 +26,41 @@
from cthulhu import plugin from cthulhu import plugin
import gi import gi
gi.require_version('Peas', '1.0')
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Peas import logging
class HelloCthulhu(GObject.Object, Peas.Activatable, plugin.Plugin): logger = logging.getLogger(__name__)
class HelloCthulhu(GObject.Object, plugin.Plugin):
#__gtype_name__ = 'HelloCthulhu' #__gtype_name__ = 'HelloCthulhu'
object = GObject.Property(type=GObject.Object) object = GObject.Property(type=GObject.Object)
def __init__(self): def __init__(self):
plugin.Plugin.__init__(self) plugin.Plugin.__init__(self)
def do_activate(self): @plugin.cthulhu_hookimpl
API = self.object def activate(self, plugin=None):
self.connectSignal("start-application-completed", self.process) # Skip if this activation call isn't for us
def do_deactivate(self): if plugin is not None and plugin is not self:
API = self.object return
def do_update_state(self):
API = self.object logger.info("Activating HelloCthulhu plugin")
try:
if self.app:
signal_manager = self.app.getSignalManager()
signal_manager.connectSignal("start-application-completed", self.process, "default")
else:
logger.error("No app reference available")
except Exception as e:
logger.error(f"Error activating HelloCthulhu plugin: {e}")
@plugin.cthulhu_hookimpl
def deactivate(self, plugin=None):
# Skip if this deactivation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Deactivating HelloCthulhu plugin")
# No specific cleanup needed
def process(self, app): def process(self, app):
messages = app.getDynamicApiManager().getAPI('Messages') messages = app.getDynamicApiManager().getAPI('Messages')
app.getDynamicApiManager().getAPI('CthulhuState').activeScript.presentMessage(messages.START_CTHULHU, resetStyles=False) app.getDynamicApiManager().getAPI('CthulhuState').activeScript.presentMessage(messages.START_CTHULHU, resetStyles=False)

View File

@ -35,9 +35,10 @@ __license__ = "LGPL"
from cthulhu import plugin from cthulhu import plugin
import gi, math, time import gi, math, time
gi.require_version('Peas', '1.0')
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Peas import logging
logger = logging.getLogger(__name__)
gi.require_version("Atspi", "2.0") gi.require_version("Atspi", "2.0")
from gi.repository import Atspi from gi.repository import Atspi
@ -68,7 +69,7 @@ AXUtilities = None
keybindings = None keybindings = None
input_event = None input_event = None
class MouseReview(GObject.Object, Peas.Activatable, plugin.Plugin): class MouseReview(GObject.Object, plugin.Plugin):
#__gtype_name__ = 'MouseReview' #__gtype_name__ = 'MouseReview'
object = GObject.Property(type=GObject.Object) object = GObject.Property(type=GObject.Object)

View File

@ -26,25 +26,43 @@
from cthulhu import plugin from cthulhu import plugin
import gi import gi
gi.require_version('Peas', '1.0')
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Peas import logging
import PluginManagerUi import PluginManagerUi
class PluginManager(GObject.Object, Peas.Activatable, plugin.Plugin): logger = logging.getLogger(__name__)
class PluginManager(GObject.Object, plugin.Plugin):
#__gtype_name__ = 'PluginManager' #__gtype_name__ = 'PluginManager'
object = GObject.Property(type=GObject.Object) object = GObject.Property(type=GObject.Object)
def __init__(self): def __init__(self):
plugin.Plugin.__init__(self) plugin.Plugin.__init__(self)
self.pluginManagerUi = None self.pluginManagerUi = None
def do_activate(self): @plugin.cthulhu_hookimpl
API = self.object def activate(self, plugin=None):
self.registerGestureByString(self.startPluginManagerUi, _('plugin manager'), 'kb:cthulhu+e') # Skip if this activation call isn't for us
if plugin is not None and plugin is not self:
return
def do_deactivate(self): logger.info("Activating PluginManager plugin")
API = self.object try:
if self.app:
self.registerGestureByString(self.startPluginManagerUi, 'plugin manager', 'kb:cthulhu+e')
else:
logger.error("No app reference available")
except Exception as e:
logger.error(f"Error activating PluginManager plugin: {e}")
@plugin.cthulhu_hookimpl
def deactivate(self, plugin=None):
# Skip if this deactivation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Deactivating PluginManager plugin")
# No specific cleanup needed
def startPluginManagerUi(self, script=None, inputEvent=None): def startPluginManagerUi(self, script=None, inputEvent=None):
self.showUI() self.showUI()

View File

@ -25,7 +25,7 @@
from cthulhu import plugin from cthulhu import plugin
from gi.repository import GObject, Peas from gi.repository import GObject
import glob import glob
import os import os
import importlib.util import importlib.util
@ -33,21 +33,23 @@ import random
import string import string
import _thread import _thread
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
import logging
logger = logging.getLogger(__name__)
settings = None settings = None
speech = None speech = None
braille = None braille = None
input_event = None input_event = None
def outputMessage( Message): def outputMessage(Message):
if (settings.enableSpeech): if (settings and settings.enableSpeech and speech):
speech.speak(Message) speech.speak(Message)
if (settings.enableBraille): if (settings and settings.enableBraille and braille):
braille.displayMessage(Message) braille.displayMessage(Message)
class SimplePluginSystem(GObject.Object, Peas.Activatable, plugin.Plugin): class SimplePluginSystem(GObject.Object, plugin.Plugin):
__gtype_name__ = 'SimplePluginSystem' __gtype_name__ = 'SimplePluginSystem'
object = GObject.Property(type=GObject.Object)
def __init__(self): def __init__(self):
plugin.Plugin.__init__(self) plugin.Plugin.__init__(self)
@ -55,27 +57,56 @@ class SimplePluginSystem(GObject.Object, Peas.Activatable, plugin.Plugin):
self.loaded = False self.loaded = False
self.plugin_repo = os.path.expanduser('~') + "/.local/share/cthulhu/simple-plugins-enabled/" self.plugin_repo = os.path.expanduser('~') + "/.local/share/cthulhu/simple-plugins-enabled/"
def do_activate(self): @plugin.cthulhu_hookimpl
API = self.object def activate(self, plugin=None):
"""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 SimplePluginSystem plugin")
try:
global settings global settings
global speech global speech
global braille global braille
global input_event global input_event
settings = API.app.getDynamicApiManager().getAPI('Settings')
speech = API.app.getDynamicApiManager().getAPI('Speech') if self.app:
braille = API.app.getDynamicApiManager().getAPI('Braille') settings = self.app.getDynamicApiManager().getAPI('Settings')
input_event = API.app.getDynamicApiManager().getAPI('InputEvent') speech = self.app.getDynamicApiManager().getAPI('Speech')
"""Required method for plugins""" braille = self.app.getDynamicApiManager().getAPI('Braille')
input_event = self.app.getDynamicApiManager().getAPI('InputEvent')
if not self.loaded: if not self.loaded:
self.load_plugins() self.load_plugins()
else:
logger.error("SimplePluginSystem: No app reference available")
except Exception as e:
logger.error(f"Error activating SimplePluginSystem plugin: {e}")
import traceback
logger.error(traceback.format_exc())
def do_deactivate(self): @plugin.cthulhu_hookimpl
"""Required method for plugins""" 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 SimplePluginSystem plugin")
try:
# Remove all registered keybindings # Remove all registered keybindings
for plugin in self.plugin_list: for plugin in self.plugin_list:
if 'function' in plugin and 'shortcut' in plugin:
self.unregisterShortcut(plugin['function'], plugin['shortcut']) self.unregisterShortcut(plugin['function'], plugin['shortcut'])
self.loaded = False self.loaded = False
self.plugin_list = [] self.plugin_list = []
except Exception as e:
logger.error(f"Error deactivating SimplePluginSystem plugin: {e}")
import traceback
logger.error(traceback.format_exc())
def SetupShortcutAndHandle(self, currPluginSetting): def SetupShortcutAndHandle(self, currPluginSetting):
shortcut = '' shortcut = ''

View File

@ -24,30 +24,57 @@
# Original source: https://gitlab.gnome.org/GNOME/orca # Original source: https://gitlab.gnome.org/GNOME/orca
import gi, time import gi, time
gi.require_version('Peas', '1.0')
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Peas import logging
from cthulhu import plugin from cthulhu import plugin
class Time(GObject.Object, Peas.Activatable, plugin.Plugin): logger = logging.getLogger(__name__)
class Time(GObject.Object, plugin.Plugin):
#__gtype_name__ = 'Time' #__gtype_name__ = 'Time'
object = GObject.Property(type=GObject.Object) object = GObject.Property(type=GObject.Object)
def __init__(self): def __init__(self):
plugin.Plugin.__init__(self) plugin.Plugin.__init__(self)
def do_activate(self): @plugin.cthulhu_hookimpl
API = self.object def activate(self, plugin=None):
self.connectSignal("setup-inputeventhandlers-completed", self.setupCompatBinding) # Skip if this activation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Activating Time plugin")
try:
if self.app:
signal_manager = self.app.getSignalManager()
signal_manager.connectSignal("setup-inputeventhandlers-completed", self.setupCompatBinding, "default")
else:
logger.error("No app reference available")
except Exception as e:
logger.error(f"Error activating Time plugin: {e}")
def setupCompatBinding(self, app): def setupCompatBinding(self, app):
try:
cmdnames = app.getDynamicApiManager().getAPI('Cmdnames') cmdnames = app.getDynamicApiManager().getAPI('Cmdnames')
inputEventHandlers = app.getDynamicApiManager().getAPI('inputEventHandlers') inputEventHandlers = app.getDynamicApiManager().getAPI('inputEventHandlers')
inputEventHandlers['presentTimeHandler'] = app.getAPIHelper().createInputEventHandler(self.presentTime, cmdnames.PRESENT_CURRENT_TIME) inputEventHandlers['presentTimeHandler'] = app.getAPIHelper().createInputEventHandler(self.presentTime, cmdnames.PRESENT_CURRENT_TIME)
def do_deactivate(self): except Exception as e:
API = self.object logger.error(f"Error setting up Time plugin: {e}")
inputEventHandlers = API.app.getDynamicApiManager().getAPI('inputEventHandlers')
@plugin.cthulhu_hookimpl
def deactivate(self, plugin=None):
# Skip if this deactivation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Deactivating Time plugin")
try:
if self.app:
inputEventHandlers = self.app.getDynamicApiManager().getAPI('inputEventHandlers')
if 'presentTimeHandler' in inputEventHandlers:
del inputEventHandlers['presentTimeHandler'] del inputEventHandlers['presentTimeHandler']
def do_update_state(self): except Exception as e:
logger.error(f"Error deactivating Time plugin: {e}")
API = self.object API = self.object
def presentTime(self, script=None, inputEvent=None): def presentTime(self, script=None, inputEvent=None):
""" Presents the current time. """ """ Presents the current time. """