Another dirty hack to bypass libpeas.
This commit is contained in:
parent
8cbe387e0b
commit
262c954f02
@ -1,185 +0,0 @@
|
||||
#!/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
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the
|
||||
# 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
|
||||
|
||||
import os, inspect
|
||||
import gi
|
||||
from gi.repository import GObject
|
||||
|
||||
class Plugin():
|
||||
#__gtype_name__ = 'BasePlugin'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.API = None
|
||||
self.pluginInfo = None
|
||||
self.moduleDir = ''
|
||||
self.hidden = False
|
||||
self.moduleName = ''
|
||||
self.name = ''
|
||||
self.version = ''
|
||||
self.website = ''
|
||||
self.authors = []
|
||||
self.buildIn = False
|
||||
self.description = ''
|
||||
self.iconName = ''
|
||||
self.copyright = ''
|
||||
self.dependencies = False
|
||||
self.helpUri = ''
|
||||
self.dataDir = ''
|
||||
self.translationContext = None
|
||||
def setApp(self, app):
|
||||
self.app = app
|
||||
self.dynamicApiManager = app.getDynamicApiManager()
|
||||
self.signalManager = app.getSignalManager()
|
||||
|
||||
def getApp(self):
|
||||
return self.app
|
||||
def setPluginInfo(self, pluginInfo):
|
||||
self.pluginInfo = pluginInfo
|
||||
self.updatePluginInfoAttributes()
|
||||
def getPluginInfo(self):
|
||||
return self.pluginInfo
|
||||
def updatePluginInfoAttributes(self):
|
||||
self.moduleDir = ''
|
||||
self.hidden = False
|
||||
self.moduleName = ''
|
||||
self.name = ''
|
||||
self.version = ''
|
||||
self.website = ''
|
||||
self.authors = []
|
||||
self.buildIn = False
|
||||
self.description = ''
|
||||
self.iconName = ''
|
||||
self.copyright = ''
|
||||
self.dependencies = False
|
||||
self.helpUri = ''
|
||||
self.dataDir = ''
|
||||
pluginInfo = self.getPluginInfo()
|
||||
if pluginInfo == None:
|
||||
return
|
||||
self.moduleName = self.getApp().getPluginSystemManager().getPluginModuleName(pluginInfo)
|
||||
self.name = self.getApp().getPluginSystemManager().getPluginName(pluginInfo)
|
||||
self.version = self.getApp().getPluginSystemManager().getPluginVersion(pluginInfo)
|
||||
self.moduleDir = self.getApp().getPluginSystemManager().getPluginModuleDir(pluginInfo)
|
||||
self.buildIn = self.getApp().getPluginSystemManager().isPluginBuildIn(pluginInfo)
|
||||
self.description = self.getApp().getPluginSystemManager().getPluginDescription(pluginInfo)
|
||||
self.hidden = self.getApp().getPluginSystemManager().isPluginHidden(pluginInfo)
|
||||
self.website = self.getApp().getPluginSystemManager().getPluginWebsite(pluginInfo)
|
||||
self.authors = self.getApp().getPluginSystemManager().getPluginAuthors(pluginInfo)
|
||||
self.iconName = self.getApp().getPluginSystemManager().getPluginIconName(pluginInfo)
|
||||
self.copyright = self.getApp().getPluginSystemManager().getPluginCopyright(pluginInfo)
|
||||
self.dependencies = self.getApp().getPluginSystemManager().getPluginDependencies(pluginInfo)
|
||||
|
||||
#settings = self.getApp().getPluginSystemManager().getPluginSettings(pluginInfo)
|
||||
#hasDependencies = self.getApp().getPluginSystemManager().hasPluginDependency(pluginInfo)
|
||||
|
||||
#externalData = self.getApp().getPluginSystemManager().getPluginExternalData(pluginInfo)
|
||||
self.helpUri = self.getApp().getPluginSystemManager().getPlugingetHelpUri(pluginInfo)
|
||||
self.dataDir = self.getApp().getPluginSystemManager().getPluginDataDir(pluginInfo)
|
||||
self.updateTranslationContext()
|
||||
|
||||
def updateTranslationContext(self, domain = None, localeDir = None, language = None, fallbackToCthulhuTranslation = True):
|
||||
self.translationContext = None
|
||||
useLocaleDir = '{}/locale/'.format(self.getModuleDir())
|
||||
if localeDir:
|
||||
if os.path.isdir(localeDir):
|
||||
useLocaleDir = localeDir
|
||||
useName = self.getModuleName()
|
||||
useDomain = useName
|
||||
if domain:
|
||||
useDomain = domain
|
||||
useLanguage = None
|
||||
if language:
|
||||
useLanguage = language
|
||||
self.translationContext = self.getApp().getTranslationManager().initTranslation(useName, domain=useDomain, localeDir=useLocaleDir, language=useLanguage, fallbackToCthulhuTranslation=fallbackToCthulhuTranslation)
|
||||
# Point _ to the translation object in the globals namespace of the caller frame
|
||||
try:
|
||||
callerFrame = inspect.currentframe().f_back
|
||||
# Install our gettext and ngettext function to the upper frame
|
||||
callerFrame.f_globals['_'] = self.translationContext.gettext
|
||||
callerFrame.f_globals['ngettext'] = self.translationContext.ngettext
|
||||
finally:
|
||||
del callerFrame # Avoid reference problems with frames (per python docs)
|
||||
def getTranslationContext(self):
|
||||
return self.translationContext
|
||||
def isPluginBuildIn(self):
|
||||
return self.buildIn
|
||||
def isPluginHidden(self):
|
||||
return self.hidden
|
||||
def getAuthors(self):
|
||||
return self.authors
|
||||
def getCopyright(self):
|
||||
return self.copyright
|
||||
def getDataDir(self):
|
||||
return self.dataDir
|
||||
def getDependencies(self):
|
||||
return self.dependencies
|
||||
def getDescription(self):
|
||||
return self.description
|
||||
def getgetHelpUri(self):
|
||||
return self.helpUri
|
||||
def getIconName(self):
|
||||
return self.iconName
|
||||
def getModuleDir(self):
|
||||
return self.moduleDir
|
||||
def getModuleName(self):
|
||||
return self.moduleName
|
||||
def getName(self):
|
||||
return self.name
|
||||
def getVersion(self):
|
||||
return self.version
|
||||
def getWebsite(self):
|
||||
return self.website
|
||||
def getSetting(key):
|
||||
#self.getModuleName())
|
||||
return None
|
||||
def setSetting(key, value):
|
||||
#self.getModuleName())
|
||||
pass
|
||||
def registerGestureByString(self, function, name, gestureString, learnModeEnabled = True):
|
||||
keybinding = self.getApp().getAPIHelper().registerGestureByString(function, name, gestureString, 'default', 'cthulhu', learnModeEnabled, contextName = self.getModuleName())
|
||||
return keybinding
|
||||
def unregisterShortcut(self, function, name, gestureString, learnModeEnabled = True):
|
||||
ok = self.getApp().getAPIHelper().unregisterShortcut(keybinding, contextName = self.getModuleName())
|
||||
return ok
|
||||
def registerSignal(self, signalName, signalFlag = GObject.SignalFlags.RUN_LAST, closure = GObject.TYPE_NONE, accumulator=()):
|
||||
ok = self.signalManager.registerSignal(signalName, signalFlag, closure, accumulator, contextName = self.getModuleName())
|
||||
return ok
|
||||
def unregisterSignal(self, signalName):
|
||||
# how to unregister?
|
||||
pass
|
||||
|
||||
def connectSignal(self, signalName, function, param = None):
|
||||
signalID = self.signalManager.connectSignal(signalName, function, param, contextName = self.getModuleName())
|
||||
return signalID
|
||||
def disconnectSignalByFunction(self, function):
|
||||
# need get mapped function
|
||||
mappedFunction = function
|
||||
self.signalManager.disconnectSignalByFunction(mappedFunction, contextName = self.getModuleName())
|
||||
|
||||
def registerAPI(self, key, value, application = ''):
|
||||
ok = self.dynamicApiManager.registerAPI(key, value, application = application, contextName = self.getModuleName())
|
||||
return ok
|
||||
def unregisterAPI(self, key, application = ''):
|
||||
self.dynamicApiManager.unregisterAPI(key, application = application, contextName = self.getModuleName())
|
@ -1,544 +0,0 @@
|
||||
#!/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
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the
|
||||
# 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
|
||||
|
||||
"""PluginManager for loading cthulhu plugins."""
|
||||
import os, inspect, sys, tarfile, shutil
|
||||
|
||||
from enum import IntEnum
|
||||
|
||||
version = sys.version[:3] # we only need major.minor version.
|
||||
if version in ["3.3","3.4"]:
|
||||
from importlib.machinery import SourceFileLoader
|
||||
else: # Python 3.5+, no support for python < 3.3.
|
||||
import importlib.util
|
||||
|
||||
import gi
|
||||
gi.require_version('Peas', '1.0')
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Peas
|
||||
|
||||
gi.require_version('Atspi', '2.0')
|
||||
from gi.repository import Atspi
|
||||
|
||||
from cthulhu import resource_manager
|
||||
|
||||
class API(GObject.GObject):
|
||||
"""Interface that gives access to all the objects of Cthulhu."""
|
||||
def __init__(self, app):
|
||||
GObject.GObject.__init__(self)
|
||||
self.app = app
|
||||
|
||||
class PluginType(IntEnum):
|
||||
"""Types of plugins we support, depending on their directory location."""
|
||||
# pylint: disable=comparison-with-callable,inconsistent-return-statements,no-else-return
|
||||
# SYSTEM: provides system wide plugins
|
||||
SYSTEM = 1
|
||||
# USER: provides per user plugin
|
||||
USER = 2
|
||||
|
||||
def __str__(self):
|
||||
if self.value == PluginType.SYSTEM:
|
||||
return _("System plugin")
|
||||
elif self.value == PluginType.USER:
|
||||
return _("User plugin")
|
||||
|
||||
def get_root_dir(self):
|
||||
"""Returns the directory where this type of plugins can be found."""
|
||||
if self.value == PluginType.SYSTEM:
|
||||
return os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe())))) + '/plugins'
|
||||
elif self.value == PluginType.USER:
|
||||
return os.path.expanduser('~') + '/.local/share/cthulhu/plugins'
|
||||
|
||||
|
||||
class PluginSystemManager():
|
||||
"""Cthulhu Plugin Manager to handle a set of plugins.
|
||||
Attributes:
|
||||
DEFAULT_LOADERS (tuple): Default loaders used by the plugin manager. For
|
||||
possible values see
|
||||
https://developer.gnome.org/libpeas/stable/PeasEngine.html#peas-engine-enable-loader
|
||||
"""
|
||||
DEFAULT_LOADERS = ("python3", )
|
||||
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.engine = Peas.Engine.get_default()
|
||||
|
||||
for loader in self.DEFAULT_LOADERS:
|
||||
self.engine.enable_loader(loader)
|
||||
|
||||
self._setupPluginsDir()
|
||||
self._setupExtensionSet()
|
||||
|
||||
if self.app:
|
||||
self.gsettingsManager = self.app.getSettingsManager()
|
||||
# settings else:
|
||||
# settings self.gsettingsManager = gsettings_manager.getSettingsManager(self.app)
|
||||
self._activePlugins = []
|
||||
self._ignorePluginModulePath = []
|
||||
@property
|
||||
def plugins(self):
|
||||
"""Gets the engine's plugin list."""
|
||||
return self.engine.get_plugin_list()
|
||||
@classmethod
|
||||
def getPluginType(cls, pluginInfo):
|
||||
"""Gets the PluginType for the specified Peas.PluginInfo."""
|
||||
paths = [pluginInfo.get_data_dir(), PluginType.SYSTEM.get_root_dir()]
|
||||
if os.path.commonprefix(paths) == PluginType.SYSTEM.get_root_dir():
|
||||
return PluginType.SYSTEM
|
||||
return PluginType.USER
|
||||
|
||||
def getExtension(self, pluginInfo):
|
||||
if not pluginInfo:
|
||||
return None
|
||||
|
||||
return self.extension_set.get_extension(pluginInfo)
|
||||
def rescanPlugins(self):
|
||||
self.engine.garbage_collect()
|
||||
self.engine.rescan_plugins()
|
||||
def getApp(self):
|
||||
return self.app
|
||||
def getPluginInfoByName(self, pluginName, pluginType=PluginType.USER):
|
||||
"""Gets the plugin info for the specified plugin name.
|
||||
Args:
|
||||
pluginName (str): The name from the .plugin file of the module.
|
||||
Returns:
|
||||
Peas.PluginInfo: The plugin info if it exists. Otherwise, `None`.
|
||||
"""
|
||||
for pluginInfo in self.plugins:
|
||||
if pluginInfo.get_module_name() == pluginName and PluginSystemManager.getPluginType(pluginInfo) == pluginType:
|
||||
return pluginInfo
|
||||
return None
|
||||
def getActivePlugins(self):
|
||||
return self._activePlugins
|
||||
def setActivePlugins(self, activePlugins):
|
||||
self._activePlugins = activePlugins
|
||||
self.syncAllPluginsActive()
|
||||
def isPluginBuildIn(self, pluginInfo):
|
||||
return pluginInfo.is_builtin()
|
||||
def isPluginHidden(self, pluginInfo):
|
||||
return pluginInfo.is_hidden()
|
||||
def getPluginAuthors(self, pluginInfo):
|
||||
return pluginInfo.get_authors()
|
||||
def getPluginCopyright(self, pluginInfo):
|
||||
return pluginInfo.get_copyright()
|
||||
def getPluginDataDir(self, pluginInfo):
|
||||
return pluginInfo.get_data_dir()
|
||||
def getPluginDependencies(self, pluginInfo):
|
||||
return pluginInfo.get_dependencies()
|
||||
def getPluginDescription(self, pluginInfo):
|
||||
return pluginInfo.get_description()
|
||||
def getPlugingetHelpUri(self, pluginInfo):
|
||||
return pluginInfo.get_help_uri()
|
||||
def getPluginIconName(self, pluginInfo):
|
||||
return pluginInfo.get_icon_name()
|
||||
def getPluginModuleDir(self, pluginInfo):
|
||||
return pluginInfo.get_module_dir()
|
||||
def getPluginModuleName(self, pluginInfo):
|
||||
return pluginInfo.get_module_name()
|
||||
def getPluginName(self, pluginInfo):
|
||||
return pluginInfo.get_name()
|
||||
def getPluginSettings(self, pluginInfo):
|
||||
return pluginInfo.get_settings()
|
||||
def getPluginVersion(self, pluginInfo):
|
||||
return pluginInfo.get_version()
|
||||
def getPluginWebsite(self, pluginInfo):
|
||||
return pluginInfo.get_website()
|
||||
# has_dependency and get_external_data seems broken-> takes exactly 2 arguments (1 given) but documentation doesnt say any parameter
|
||||
#def hasPluginDependency(self, pluginInfo):
|
||||
# return pluginInfo.has_dependency()
|
||||
#def getPluginExternalData(self, pluginInfo):
|
||||
# return pluginInfo.get_external_data()
|
||||
def isPluginAvailable(self, pluginInfo):
|
||||
try:
|
||||
return pluginInfo.is_available()
|
||||
except:
|
||||
return False
|
||||
def isPluginLoaded(self, pluginInfo):
|
||||
try:
|
||||
return pluginInfo.is_loaded()
|
||||
except:
|
||||
return False
|
||||
|
||||
def getIgnoredPlugins(self):
|
||||
return self._ignorePluginModulePath
|
||||
def setIgnoredPlugins(self, pluginModulePath, ignored):
|
||||
if pluginModulePath.endswith('/'):
|
||||
pluginModulePath = pluginModulePath[:-1]
|
||||
if ignored:
|
||||
if not pluginModulePath in self.getIgnoredPlugins():
|
||||
self._ignorePluginModulePath.append(pluginModulePath)
|
||||
else:
|
||||
if pluginModulePath in self.getIgnoredPlugins():
|
||||
self._ignorePluginModulePath.remove(pluginModulePath)
|
||||
|
||||
def setPluginActive(self, pluginInfo, active):
|
||||
if self.isPluginBuildIn(pluginInfo):
|
||||
active = True
|
||||
pluginName = self.getPluginModuleName(pluginInfo)
|
||||
if active:
|
||||
if not pluginName in self.getActivePlugins():
|
||||
if self.loadPlugin(pluginInfo):
|
||||
self._activePlugins.append(pluginName )
|
||||
else:
|
||||
if pluginName in self.getActivePlugins():
|
||||
if self.unloadPlugin(pluginInfo):
|
||||
self._activePlugins.remove(pluginName )
|
||||
def isPluginActive(self, pluginInfo):
|
||||
if self.isPluginBuildIn(pluginInfo):
|
||||
return True
|
||||
if self.isPluginLoaded(pluginInfo):
|
||||
return True
|
||||
active_plugin_names = self.getActivePlugins()
|
||||
return self.getPluginModuleName(pluginInfo) in active_plugin_names
|
||||
def syncAllPluginsActive(self, ForceAllPlugins=False):
|
||||
self.unloadAllPlugins(ForceAllPlugins)
|
||||
self.loadAllPlugins(ForceAllPlugins)
|
||||
|
||||
def loadAllPlugins(self, ForceAllPlugins=False):
|
||||
"""Loads plugins from settings."""
|
||||
for pluginInfo in self.plugins:
|
||||
if self.isPluginActive(pluginInfo) or ForceAllPlugins:
|
||||
self.loadPlugin(pluginInfo)
|
||||
|
||||
def loadPlugin(self, pluginInfo):
|
||||
resourceManager = self.getApp().getResourceManager()
|
||||
moduleName = pluginInfo.get_module_name()
|
||||
try:
|
||||
if pluginInfo not in self.plugins:
|
||||
print("Plugin missing: {}".format(moduleName))
|
||||
return False
|
||||
resourceManager.addResourceContext(moduleName)
|
||||
self.engine.load_plugin(pluginInfo)
|
||||
except Exception as e:
|
||||
print('loadPlugin:',e)
|
||||
return False
|
||||
return True
|
||||
|
||||
def unloadAllPlugins(self, ForceAllPlugins=False):
|
||||
"""Loads plugins from settings."""
|
||||
for pluginInfo in self.plugins:
|
||||
if not self.isPluginActive(pluginInfo) or ForceAllPlugins:
|
||||
self.unloadPlugin(pluginInfo)
|
||||
|
||||
def unloadPlugin(self, pluginInfo):
|
||||
resourceManager = self.getApp().getResourceManager()
|
||||
moduleName = pluginInfo.get_module_name()
|
||||
try:
|
||||
if pluginInfo not in self.plugins:
|
||||
print("Plugin missing: {}".format(moduleName))
|
||||
return False
|
||||
if self.isPluginBuildIn(pluginInfo):
|
||||
return False
|
||||
self.engine.unload_plugin(pluginInfo)
|
||||
self.getApp().getResourceManager().removeResourceContext(moduleName)
|
||||
self.engine.garbage_collect()
|
||||
except Exception as e:
|
||||
print('unloadPlugin:',e)
|
||||
return False
|
||||
return True
|
||||
def installPlugin(self, pluginFilePath, pluginType=PluginType.USER):
|
||||
if not self.isValidPluginFile(pluginFilePath):
|
||||
return False
|
||||
pluginFolder = pluginType.get_root_dir()
|
||||
if not pluginFolder.endswith('/'):
|
||||
pluginFolder += '/'
|
||||
if not os.path.exists(pluginFolder):
|
||||
os.mkdir(pluginFolder)
|
||||
else:
|
||||
if not os.path.isdir(pluginFolder):
|
||||
return False
|
||||
try:
|
||||
with tarfile.open(pluginFilePath) as tar:
|
||||
tar.extractall(path=pluginFolder)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
pluginModulePath = self.getModuleDirByPluginFile(pluginFilePath)
|
||||
if pluginModulePath != '':
|
||||
pluginModulePath = pluginFolder + pluginModulePath
|
||||
self.setIgnoredPlugins(pluginModulePath[:-1], False) # without ending /
|
||||
print('install', pluginFilePath)
|
||||
self.callPackageTriggers(pluginModulePath, 'onPostInstall')
|
||||
self.rescanPlugins()
|
||||
|
||||
return True
|
||||
def getModuleDirByPluginFile(self, pluginFilePath):
|
||||
if not isinstance(pluginFilePath, str):
|
||||
return ''
|
||||
if pluginFilePath == '':
|
||||
return ''
|
||||
if not os.path.exists(pluginFilePath):
|
||||
return ''
|
||||
try:
|
||||
with tarfile.open(pluginFilePath) as tar:
|
||||
tarMembers = tar.getmembers()
|
||||
for tarMember in tarMembers:
|
||||
if tarMember.isdir():
|
||||
return tarMember.name
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return ''
|
||||
def isValidPluginFile(self, pluginFilePath):
|
||||
if not isinstance(pluginFilePath, str):
|
||||
return False
|
||||
if pluginFilePath == '':
|
||||
return False
|
||||
if not os.path.exists(pluginFilePath):
|
||||
return False
|
||||
pluginFolder = ''
|
||||
pluginFileExists = False
|
||||
packageFileExists = False
|
||||
try:
|
||||
with tarfile.open(pluginFilePath) as tar:
|
||||
tarMembers = tar.getmembers()
|
||||
for tarMember in tarMembers:
|
||||
if tarMember.isdir():
|
||||
if pluginFolder == '':
|
||||
pluginFolder = tarMember.name
|
||||
if tarMember.isfile():
|
||||
if tarMember.name.endswith('.plugin'):
|
||||
pluginFileExists = True
|
||||
if tarMember.name.endswith('package.py'):
|
||||
pluginFileExists = True
|
||||
if not tarMember.name.startswith(pluginFolder):
|
||||
return False
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
return pluginFileExists
|
||||
def uninstallPlugin(self, pluginInfo):
|
||||
if self.isPluginBuildIn(pluginInfo):
|
||||
return False
|
||||
# do we want to allow removing system plugins?
|
||||
if PluginSystemManager.getPluginType(pluginInfo) == PluginType.SYSTEM:
|
||||
return False
|
||||
pluginFolder = pluginInfo.get_data_dir()
|
||||
if not pluginFolder.endswith('/'):
|
||||
pluginFolder += '/'
|
||||
if not os.path.isdir(pluginFolder):
|
||||
return False
|
||||
if self.isPluginActive(pluginInfo):
|
||||
self.setPluginActive(pluginInfo, False)
|
||||
SettingsManager = self.app.getSettingsManager()
|
||||
# TODO SettingsManager.set_settings_value_list('active-plugins', self.getActivePlugins())
|
||||
self.callPackageTriggers(pluginFolder, 'onPreUninstall')
|
||||
|
||||
try:
|
||||
shutil.rmtree(pluginFolder, ignore_errors=True)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
self.setIgnoredPlugins(pluginFolder, True)
|
||||
self.rescanPlugins()
|
||||
|
||||
return True
|
||||
def callPackageTriggers(self, pluginPath, trigger):
|
||||
if not os.path.exists(pluginPath):
|
||||
return
|
||||
if not pluginPath.endswith('/'):
|
||||
pluginPath += '/'
|
||||
packageModulePath = pluginPath + 'package.py'
|
||||
if not os.path.isfile(packageModulePath):
|
||||
return
|
||||
if not os.access(packageModulePath, os.R_OK):
|
||||
return
|
||||
package = self.getApp().getAPIHelper().importModule('package', packageModulePath)
|
||||
|
||||
if trigger == 'onPostInstall':
|
||||
try:
|
||||
package.onPostInstall(pluginPath, self.getApp())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
elif trigger == 'onPreUninstall':
|
||||
try:
|
||||
package.onPreUninstall(pluginPath, self.getApp())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def _setupExtensionSet(self):
|
||||
plugin_iface = API(self.getApp())
|
||||
self.extension_set = Peas.ExtensionSet.new(self.engine,
|
||||
Peas.Activatable,
|
||||
["object"],
|
||||
[plugin_iface])
|
||||
self.extension_set.connect("extension-removed",
|
||||
self.__extensionRemoved)
|
||||
self.extension_set.connect("extension-added",
|
||||
self.__extensionAdded)
|
||||
|
||||
def _setupPluginsDir(self):
|
||||
system_plugins_dir = PluginType.SYSTEM.get_root_dir()
|
||||
user_plugins_dir = PluginType.USER.get_root_dir()
|
||||
if os.path.exists(user_plugins_dir):
|
||||
self.engine.add_search_path(user_plugins_dir)
|
||||
if os.path.exists(system_plugins_dir):
|
||||
self.engine.add_search_path(system_plugins_dir)
|
||||
|
||||
def __extensionRemoved(self, unusedSet, pluginInfo, extension):
|
||||
extension.deactivate()
|
||||
|
||||
def __extensionAdded(self, unusedSet, pluginInfo, extension):
|
||||
extension.setApp(self.getApp())
|
||||
extension.setPluginInfo(pluginInfo)
|
||||
extension.activate()
|
||||
def __loadedPlugins(self, engine, unusedSet):
|
||||
"""Handles the changing of the loaded plugin list."""
|
||||
self.getApp().settings.ActivePlugins = engine.get_property("loaded-plugins")
|
||||
|
||||
class APIHelper():
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.cthulhuKeyBindings = None
|
||||
|
||||
'''
|
||||
_pluginAPIManager.seCthulhuAPI('Logger', _logger)
|
||||
_pluginAPIManager.setCthulhuAPI('SettingsManager', _settingsManager)
|
||||
_pluginAPIManager.setCthulhuAPI('ScriptManager', _scriptManager)
|
||||
_pluginAPIManager.setCthulhuAPI('EventManager', _eventManager)
|
||||
_pluginAPIManager.setCthulhuAPI('Speech', speech)
|
||||
_pluginAPIManager.setCthulhuAPI('Sound', sound)
|
||||
_pluginAPIManager.setCthulhuAPI('Braille', braille)
|
||||
_pluginAPIManager.setCthulhuAPI('Debug', debug)
|
||||
_pluginAPIManager.setCthulhuAPI('Messages', messages)
|
||||
_pluginAPIManager.setCthulhuAPI('MouseReview', mouse_review)
|
||||
_pluginAPIManager.setCthulhuAPI('NotificationMessages', notification_messages)
|
||||
_pluginAPIManager.setCthulhuAPI('CthulhuState', cthulhu_state)
|
||||
_pluginAPIManager.setCthulhuAPI('CthulhuPlatform', cthulhu_platform)
|
||||
_pluginAPIManager.setCthulhuAPI('Settings', settings)
|
||||
_pluginAPIManager.setCthulhuAPI('Keybindings', keybindings)
|
||||
'''
|
||||
def outputMessage(self, Message, interrupt=False):
|
||||
settings = self.app.getDynamicApiManager().getAPI('Settings')
|
||||
braille = self.app.getDynamicApiManager().getAPI('Braille')
|
||||
speech = self.app.getDynamicApiManager().getAPI('Speech')
|
||||
if speech != None:
|
||||
if (settings.enableSpeech):
|
||||
if interrupt:
|
||||
speech.cancel()
|
||||
if Message != '':
|
||||
speech.speak(Message)
|
||||
if braille != None:
|
||||
if (settings.enableBraille):
|
||||
braille.displayMessage(Message)
|
||||
def createInputEventHandler(self, function, name, learnModeEnabled=True):
|
||||
EventManager = self.app.getDynamicApiManager().getAPI('EventManager')
|
||||
newInputEventHandler = EventManager.input_event.InputEventHandler(function, name, learnModeEnabled)
|
||||
return newInputEventHandler
|
||||
def registerGestureByString(self, function, name, gestureString, profile, application, learnModeEnabled = True, contextName = None):
|
||||
gestureList = gestureString.split(',')
|
||||
registeredGestures = []
|
||||
for gesture in gestureList:
|
||||
if gesture.startswith('kb:'):
|
||||
shortcutString = gesture[3:]
|
||||
registuredGesture = self.registerShortcutByString(function, name, shortcutString, profile, application, learnModeEnabled, contextName=contextName)
|
||||
if registuredGesture:
|
||||
registeredGestures.append(registuredGesture)
|
||||
return registeredGestures
|
||||
def registerShortcutByString(self, function, name, shortcutString, profile, application, learnModeEnabled = True, contextName = None):
|
||||
keybindings = self.app.getDynamicApiManager().getAPI('Keybindings')
|
||||
settings = self.app.getDynamicApiManager().getAPI('Settings')
|
||||
resourceManager = self.app.getResourceManager()
|
||||
|
||||
clickCount = 0
|
||||
cthulhuKey = False
|
||||
shiftKey = False
|
||||
ctrlKey = False
|
||||
altKey = False
|
||||
key = ''
|
||||
shortcutList = shortcutString.split('+')
|
||||
for shortcutElement in shortcutList:
|
||||
shortcutElementLower = shortcutElement.lower()
|
||||
if shortcutElementLower == 'press':
|
||||
clickCount += 1
|
||||
elif shortcutElement == 'cthulhu':
|
||||
cthulhuKey = True
|
||||
elif shortcutElementLower == 'shift':
|
||||
shiftKey = True
|
||||
elif shortcutElementLower == 'control':
|
||||
ctrlKey = True
|
||||
elif shortcutElementLower == 'alt':
|
||||
altKey = True
|
||||
else:
|
||||
key = shortcutElementLower
|
||||
if clickCount == 0:
|
||||
clickCount = 1
|
||||
|
||||
if self.cthulhuKeyBindings == None:
|
||||
self.cthulhuKeyBindings = keybindings.KeyBindings()
|
||||
|
||||
tryFunction = resource_manager.TryFunction(function)
|
||||
newInputEventHandler = self.createInputEventHandler(tryFunction.runInputEvent, name, learnModeEnabled)
|
||||
|
||||
currModifierMask = keybindings.NO_MODIFIER_MASK
|
||||
if cthulhuKey:
|
||||
currModifierMask = currModifierMask | 1 << keybindings.MODIFIER_CTHULHU
|
||||
if shiftKey:
|
||||
currModifierMask = currModifierMask | 1 << Atspi.ModifierType.SHIFT
|
||||
if altKey:
|
||||
currModifierMask = currModifierMask | 1 << Atspi.ModifierType.ALT
|
||||
if ctrlKey:
|
||||
currModifierMask = currModifierMask | 1 << Atspi.ModifierType.CONTROL
|
||||
|
||||
newKeyBinding = keybindings.KeyBinding(key, keybindings.defaultModifierMask, currModifierMask, newInputEventHandler, clickCount)
|
||||
self.cthulhuKeyBindings.add(newKeyBinding)
|
||||
|
||||
settings.keyBindingsMap["default"] = self.cthulhuKeyBindings
|
||||
|
||||
if contextName:
|
||||
resourceContext = resourceManager.getResourceContext(contextName)
|
||||
if resourceContext:
|
||||
resourceEntry = resource_manager.ResourceEntry('keyboard', newKeyBinding, function, tryFunction, shortcutString)
|
||||
resourceContext.addGesture(profile, application, newKeyBinding, resourceEntry)
|
||||
|
||||
return newKeyBinding
|
||||
|
||||
def unregisterShortcut(self, KeyBindingToRemove, contextName = None):
|
||||
ok = False
|
||||
keybindings = self.app.getDynamicApiManager().getAPI('Keybindings')
|
||||
settings = self.app.getDynamicApiManager().getAPI('Settings')
|
||||
resourceManager = self.app.getResourceManager()
|
||||
|
||||
if self.cthulhuKeyBindings == None:
|
||||
self.cthulhuKeyBindings = keybindings.KeyBindings()
|
||||
try:
|
||||
self.cthulhuKeyBindings.remove(KeyBindingToRemove)
|
||||
settings.keyBindingsMap["default"] = self.cthulhuKeyBindings
|
||||
ok = True
|
||||
except KeyError:
|
||||
pass
|
||||
if contextName:
|
||||
resourceContext = resourceManager.getResourceContext(contextName)
|
||||
if resourceContext:
|
||||
resourceContext.removeGesture(KeyBindingToRemove)
|
||||
|
||||
return ok
|
||||
def importModule(self, moduleName, moduleLocation):
|
||||
if version in ["3.3","3.4"]:
|
||||
return SourceFileLoader(moduleName, moduleLocation).load_module()
|
||||
else:
|
||||
spec = importlib.util.spec_from_file_location(moduleName, moduleLocation)
|
||||
driver_mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(driver_mod)
|
||||
return driver_mod
|
Loading…
x
Reference in New Issue
Block a user