diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/interfaces/python/LanguageHook.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/interfaces/python/LanguageHook.cpp')
-rw-r--r-- | xbmc/interfaces/python/LanguageHook.cpp | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/xbmc/interfaces/python/LanguageHook.cpp b/xbmc/interfaces/python/LanguageHook.cpp new file mode 100644 index 0000000..0d4747f --- /dev/null +++ b/xbmc/interfaces/python/LanguageHook.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + + +#include "LanguageHook.h" + +#include "CallbackHandler.h" +#include "PyContext.h" +#include "ServiceBroker.h" +#include "XBPython.h" +#include "interfaces/legacy/AddonUtils.h" +#include "utils/log.h" + +#include <mutex> + +namespace XBMCAddon +{ + namespace Python + { + static AddonClass::Ref<PythonLanguageHook> instance; + + static CCriticalSection hooksMutex; + static std::map<PyInterpreterState*,AddonClass::Ref<PythonLanguageHook> > hooks; + + // vtab instantiation + PythonLanguageHook::~PythonLanguageHook() + { + XBMC_TRACE; + XBMCAddon::LanguageHook::deallocating(); + } + + void PythonLanguageHook::MakePendingCalls() + { + XBMC_TRACE; + PythonCallbackHandler::makePendingCalls(); + } + + void PythonLanguageHook::DelayedCallOpen() + { + XBMC_TRACE; + PyGILLock::releaseGil(); + } + + void PythonLanguageHook::DelayedCallClose() + { + XBMC_TRACE; + PyGILLock::acquireGil(); + } + + void PythonLanguageHook::RegisterMe() + { + XBMC_TRACE; + std::unique_lock<CCriticalSection> lock(hooksMutex); + hooks[m_interp] = AddonClass::Ref<PythonLanguageHook>(this); + } + + void PythonLanguageHook::UnregisterMe() + { + XBMC_TRACE; + std::unique_lock<CCriticalSection> lock(hooksMutex); + hooks.erase(m_interp); + } + + static AddonClass::Ref<XBMCAddon::Python::PythonLanguageHook> g_languageHook; + + // Ok ... we're going to get it even if it doesn't exist. If it doesn't exist then + // we're going to assume we're not in control of the interpreter. This (apparently) + // can be the case. E.g. Libspotify manages to call into a script using a ctypes + // extension but under the control of an Interpreter we know nothing about. In + // cases like this we're going to use a global interpreter + AddonClass::Ref<PythonLanguageHook> PythonLanguageHook::GetIfExists(PyInterpreterState* interp) + { + XBMC_TRACE; + std::unique_lock<CCriticalSection> lock(hooksMutex); + std::map<PyInterpreterState*,AddonClass::Ref<PythonLanguageHook> >::iterator iter = hooks.find(interp); + if (iter != hooks.end()) + return iter->second; + + // if we got here then we need to use the global one. + if (g_languageHook.isNull()) + g_languageHook = new XBMCAddon::Python::PythonLanguageHook(); + + return g_languageHook; + } + + bool PythonLanguageHook::IsAddonClassInstanceRegistered(AddonClass* obj) + { + for (const auto& iter : hooks) + { + if (iter.second->HasRegisteredAddonClassInstance(obj)) + return true; + } + return false; + } + + /** + * PythonCallbackHandler expects to be instantiated PER AddonClass instance + * that is to be used as a callback. This is why this cannot be instantiated + * once. + * + * There is an expectation that this method is called from the Python thread + * that instantiated an AddonClass that has the potential for a callback. + * + * See RetardedAsyncCallbackHandler for more details. + * See PythonCallbackHandler for more details + * See PythonCallbackHandler::PythonCallbackHandler for more details + */ + XBMCAddon::CallbackHandler* PythonLanguageHook::GetCallbackHandler() + { + XBMC_TRACE; + return new PythonCallbackHandler(); + } + + String PythonLanguageHook::GetAddonId() + { + XBMC_TRACE; + + // Get a reference to the main module + // and global dictionary + PyObject* main_module = PyImport_AddModule("__main__"); + if (!main_module) + { + CLog::Log(LOGDEBUG, "PythonLanguageHook::{}: __main__ returns null", __FUNCTION__); + return ""; + } + PyObject* global_dict = PyModule_GetDict(main_module); + // Extract a reference to the function "func_name" + // from the global dictionary + PyObject* pyid = PyDict_GetItemString(global_dict, "__xbmcaddonid__"); + if (pyid) + return PyUnicode_AsUTF8(pyid); + return ""; + } + + String PythonLanguageHook::GetAddonVersion() + { + XBMC_TRACE; + // Get a reference to the main module + // and global dictionary + PyObject* main_module = PyImport_AddModule("__main__"); + if (!main_module) + { + CLog::Log(LOGDEBUG, "PythonLanguageHook::{}: __main__ returns null", __FUNCTION__); + return ""; + } + PyObject* global_dict = PyModule_GetDict(main_module); + // Extract a reference to the function "func_name" + // from the global dictionary + PyObject* pyversion = PyDict_GetItemString(global_dict, "__xbmcapiversion__"); + if (pyversion) + return PyUnicode_AsUTF8(pyversion); + return ""; + } + + long PythonLanguageHook::GetInvokerId() + { + XBMC_TRACE; + + // Get a reference to the main module + // and global dictionary + PyObject* main_module = PyImport_AddModule("__main__"); + if (!main_module) + { + CLog::Log(LOGDEBUG, "PythonLanguageHook::{}: __main__ returns null", __FUNCTION__); + return -1; + } + PyObject* global_dict = PyModule_GetDict(main_module); + // Extract a reference to the function "func_name" + // from the global dictionary + PyObject* pyid = PyDict_GetItemString(global_dict, "__xbmcinvokerid__"); + if (pyid) + return PyLong_AsLong(pyid); + return -1; + } + + void PythonLanguageHook::RegisterPlayerCallback(IPlayerCallback* player) + { + XBMC_TRACE; + CServiceBroker::GetXBPython().RegisterPythonPlayerCallBack(player); + } + void PythonLanguageHook::UnregisterPlayerCallback(IPlayerCallback* player) + { + XBMC_TRACE; + CServiceBroker::GetXBPython().UnregisterPythonPlayerCallBack(player); + } + void PythonLanguageHook::RegisterMonitorCallback(XBMCAddon::xbmc::Monitor* monitor) + { + XBMC_TRACE; + CServiceBroker::GetXBPython().RegisterPythonMonitorCallBack(monitor); + } + void PythonLanguageHook::UnregisterMonitorCallback(XBMCAddon::xbmc::Monitor* monitor) + { + XBMC_TRACE; + CServiceBroker::GetXBPython().UnregisterPythonMonitorCallBack(monitor); + } + + bool PythonLanguageHook::WaitForEvent(CEvent& hEvent, unsigned int milliseconds) + { + XBMC_TRACE; + return CServiceBroker::GetXBPython().WaitForEvent(hEvent, milliseconds); + } + + void PythonLanguageHook::RegisterAddonClassInstance(AddonClass* obj) + { + XBMC_TRACE; + std::unique_lock<CCriticalSection> l(*this); + obj->Acquire(); + currentObjects.insert(obj); + } + + void PythonLanguageHook::UnregisterAddonClassInstance(AddonClass* obj) + { + XBMC_TRACE; + std::unique_lock<CCriticalSection> l(*this); + if (currentObjects.erase(obj) > 0) + obj->Release(); + } + + bool PythonLanguageHook::HasRegisteredAddonClassInstance(AddonClass* obj) + { + XBMC_TRACE; + std::unique_lock<CCriticalSection> l(*this); + return currentObjects.find(obj) != currentObjects.end(); + } + } +} |