/*
* Copyright (C) 2005-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, see
* .
*
*/
#include "LanguageHook.h"
#include "CallbackHandler.h"
#include "XBPython.h"
#include "interfaces/legacy/AddonUtils.h"
#include "utils/GlobalsHandling.h"
#include "PyContext.h"
namespace XBMCAddon
{
namespace Python
{
static AddonClass::Ref instance;
static CCriticalSection hooksMutex;
static std::map > 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;
CSingleLock lock(hooksMutex);
hooks[m_interp] = AddonClass::Ref(this);
}
void PythonLanguageHook::UnregisterMe()
{
XBMC_TRACE;
CSingleLock lock(hooksMutex);
hooks.erase(m_interp);
}
static AddonClass::Ref 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
// extention 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::GetIfExists(PyInterpreterState* interp)
{
XBMC_TRACE;
CSingleLock lock(hooksMutex);
std::map >::iterator iter = hooks.find(interp);
if (iter != hooks.end())
return AddonClass::Ref(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 (std::map >::iterator iter = hooks.begin();
iter != hooks.end(); ++iter)
{
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 instantited
* 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 RetardedAsynchCallbackHandler 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((char*)"__main__");
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 PyString_AsString(pyid);
return "";
}
String PythonLanguageHook::GetAddonVersion()
{
XBMC_TRACE;
// Get a reference to the main module
// and global dictionary
PyObject* main_module = PyImport_AddModule((char*)"__main__");
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 PyString_AsString(pyversion);
return "";
}
void PythonLanguageHook::RegisterPlayerCallback(IPlayerCallback* player) { XBMC_TRACE; g_pythonParser.RegisterPythonPlayerCallBack(player); }
void PythonLanguageHook::UnregisterPlayerCallback(IPlayerCallback* player) { XBMC_TRACE; g_pythonParser.UnregisterPythonPlayerCallBack(player); }
void PythonLanguageHook::RegisterMonitorCallback(XBMCAddon::xbmc::Monitor* monitor) { XBMC_TRACE; g_pythonParser.RegisterPythonMonitorCallBack(monitor); }
void PythonLanguageHook::UnregisterMonitorCallback(XBMCAddon::xbmc::Monitor* monitor) { XBMC_TRACE; g_pythonParser.UnregisterPythonMonitorCallBack(monitor); }
bool PythonLanguageHook::WaitForEvent(CEvent& hEvent, unsigned int milliseconds)
{
XBMC_TRACE;
return g_pythonParser.WaitForEvent(hEvent,milliseconds);
}
void PythonLanguageHook::RegisterAddonClassInstance(AddonClass* obj)
{
XBMC_TRACE;
CSingleLock l(*this);
obj->Acquire();
currentObjects.insert(obj);
}
void PythonLanguageHook::UnregisterAddonClassInstance(AddonClass* obj)
{
XBMC_TRACE;
CSingleLock l(*this);
if (currentObjects.erase(obj) > 0)
obj->Release();
}
bool PythonLanguageHook::HasRegisteredAddonClassInstance(AddonClass* obj)
{
XBMC_TRACE;
CSingleLock l(*this);
return currentObjects.find(obj) != currentObjects.end();
}
}
}