2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
26 // python.h should always be included first before any other includes
32 #include "cores/DllLoader/DllLoaderContainer.h"
33 #include "GUIPassword.h"
35 #include "filesystem/File.h"
36 #include "filesystem/SpecialProtocol.h"
37 #include "guilib/GraphicContext.h"
38 #include "profiles/ProfilesManager.h"
39 #include "utils/log.h"
40 #include "pythreadstate.h"
41 #include "utils/TimeUtils.h"
43 #include "guilib/GraphicContext.h"
45 #include "utils/Environment.h"
48 #include "threads/SystemClock.h"
49 #include "addons/Addon.h"
50 #include "interfaces/AnnouncementManager.h"
52 #include "interfaces/legacy/Monitor.h"
53 #include "interfaces/legacy/AddonUtils.h"
55 using namespace ANNOUNCEMENT;
57 namespace PythonBindings {
58 void initModule_xbmcgui(void);
59 void initModule_xbmc(void);
60 void initModule_xbmcplugin(void);
61 void initModule_xbmcaddon(void);
62 void initModule_xbmcvfs(void);
65 using namespace PythonBindings;
69 m_bInitialized = false;
72 m_mainThreadState = NULL;
73 m_ThreadId = CThread::GetCurrentThreadId();
74 m_iDllScriptCounter = 0;
77 m_vecPlayerCallbackList.clear();
78 m_vecMonitorCallbackList.clear();
80 CAnnouncementManager::AddAnnouncer(this);
86 CAnnouncementManager::RemoveAnnouncer(this);
89 #define LOCK_AND_COPY(type, dest, src) \
90 if (!m_bInitialized) return; \
91 CSingleLock lock(src); \
92 src.hadSomethingRemoved = false; \
96 #define CHECK_FOR_ENTRY(l,v) \
97 (l.hadSomethingRemoved ? (std::find(l.begin(),l.end(),v) != l.end()) : true)
99 // message all registered callbacks that xbmc stopped playing
100 void XBPython::OnPlayBackEnded()
103 LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
104 for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
105 if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
106 ((IPlayerCallback*)(*it))->OnPlayBackEnded();
109 void XBPython::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
111 if (flag & VideoLibrary)
113 if (strcmp(message, "OnScanFinished") == 0)
114 OnDatabaseUpdated("video");
115 else if (strcmp(message, "OnScanStarted") == 0)
116 OnDatabaseScanStarted("video");
118 else if (flag & AudioLibrary)
120 if (strcmp(message, "OnScanFinished") == 0)
121 OnDatabaseUpdated("music");
122 else if (strcmp(message, "OnScanStarted") == 0)
123 OnDatabaseScanStarted("music");
127 if (strcmp(message, "OnScreensaverDeactivated") == 0)
128 OnScreensaverDeactivated();
129 else if (strcmp(message, "OnScreensaverActivated") == 0)
130 OnScreensaverActivated();
134 // message all registered callbacks that we started playing
135 void XBPython::OnPlayBackStarted()
138 LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
139 for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
140 if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
141 ((IPlayerCallback*)(*it))->OnPlayBackStarted();
144 // message all registered callbacks that we paused playing
145 void XBPython::OnPlayBackPaused()
148 LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
149 for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
150 if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
151 ((IPlayerCallback*)(*it))->OnPlayBackPaused();
154 // message all registered callbacks that we resumed playing
155 void XBPython::OnPlayBackResumed()
158 LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
159 for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
160 if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
161 ((IPlayerCallback*)(*it))->OnPlayBackResumed();
164 // message all registered callbacks that user stopped playing
165 void XBPython::OnPlayBackStopped()
168 LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
169 for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
170 if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
171 ((IPlayerCallback*)(*it))->OnPlayBackStopped();
174 // message all registered callbacks that playback speed changed (FF/RW)
175 void XBPython::OnPlayBackSpeedChanged(int iSpeed)
178 LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
179 for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
180 if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
181 ((IPlayerCallback*)(*it))->OnPlayBackSpeedChanged(iSpeed);
184 // message all registered callbacks that player is seeking
185 void XBPython::OnPlayBackSeek(int iTime, int seekOffset)
188 LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
189 for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
190 if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
191 ((IPlayerCallback*)(*it))->OnPlayBackSeek(iTime, seekOffset);
194 // message all registered callbacks that player chapter seeked
195 void XBPython::OnPlayBackSeekChapter(int iChapter)
198 LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
199 for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
200 if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
201 ((IPlayerCallback*)(*it))->OnPlayBackSeekChapter(iChapter);
204 // message all registered callbacks that next item has been queued
205 void XBPython::OnQueueNextItem()
208 LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
209 for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
210 if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
211 ((IPlayerCallback*)(*it))->OnQueueNextItem();
214 void XBPython::RegisterPythonPlayerCallBack(IPlayerCallback* pCallback)
217 CSingleLock lock(m_vecPlayerCallbackList);
218 m_vecPlayerCallbackList.push_back(pCallback);
221 void XBPython::UnregisterPythonPlayerCallBack(IPlayerCallback* pCallback)
224 CSingleLock lock(m_vecPlayerCallbackList);
225 PlayerCallbackList::iterator it = m_vecPlayerCallbackList.begin();
226 while (it != m_vecPlayerCallbackList.end())
228 if (*it == pCallback)
230 it = m_vecPlayerCallbackList.erase(it);
231 m_vecPlayerCallbackList.hadSomethingRemoved = true;
238 void XBPython::RegisterPythonMonitorCallBack(XBMCAddon::xbmc::Monitor* pCallback)
241 CSingleLock lock(m_vecMonitorCallbackList);
242 m_vecMonitorCallbackList.push_back(pCallback);
245 void XBPython::UnregisterPythonMonitorCallBack(XBMCAddon::xbmc::Monitor* pCallback)
248 CSingleLock lock(m_vecMonitorCallbackList);
249 MonitorCallbackList::iterator it = m_vecMonitorCallbackList.begin();
250 while (it != m_vecMonitorCallbackList.end())
252 if (*it == pCallback)
254 it = m_vecMonitorCallbackList.erase(it);
255 m_vecMonitorCallbackList.hadSomethingRemoved = true;
262 void XBPython::OnSettingsChanged(const CStdString &ID)
265 LOCK_AND_COPY(std::vector<XBMCAddon::xbmc::Monitor*>,tmp,m_vecMonitorCallbackList);
266 for (MonitorCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
267 if (CHECK_FOR_ENTRY(m_vecMonitorCallbackList,(*it)) && ((*it)->GetId() == ID))
268 (*it)->OnSettingsChanged();
271 void XBPython::OnScreensaverActivated()
274 LOCK_AND_COPY(std::vector<XBMCAddon::xbmc::Monitor*>,tmp,m_vecMonitorCallbackList);
275 for (MonitorCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
276 if (CHECK_FOR_ENTRY(m_vecMonitorCallbackList,(*it)))
277 (*it)->OnScreensaverActivated();
280 void XBPython::OnScreensaverDeactivated()
283 LOCK_AND_COPY(std::vector<XBMCAddon::xbmc::Monitor*>,tmp,m_vecMonitorCallbackList);
284 for (MonitorCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
285 if (CHECK_FOR_ENTRY(m_vecMonitorCallbackList,(*it)))
286 (*it)->OnScreensaverDeactivated();
289 void XBPython::OnDatabaseUpdated(const std::string &database)
292 LOCK_AND_COPY(std::vector<XBMCAddon::xbmc::Monitor*>,tmp,m_vecMonitorCallbackList);
293 for (MonitorCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
294 if (CHECK_FOR_ENTRY(m_vecMonitorCallbackList,(*it)))
295 (*it)->OnDatabaseUpdated(database);
298 void XBPython::OnDatabaseScanStarted(const std::string &database)
301 LOCK_AND_COPY(std::vector<XBMCAddon::xbmc::Monitor*>,tmp,m_vecMonitorCallbackList);
302 for (MonitorCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
303 if (CHECK_FOR_ENTRY(m_vecMonitorCallbackList,(*it)))
304 (*it)->OnDatabaseScanStarted(database);
307 void XBPython::OnAbortRequested(const CStdString &ID)
310 LOCK_AND_COPY(std::vector<XBMCAddon::xbmc::Monitor*>,tmp,m_vecMonitorCallbackList);
311 for (MonitorCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
313 if (CHECK_FOR_ENTRY(m_vecMonitorCallbackList,(*it)))
316 (*it)->OnAbortRequested();
317 else if ((*it)->GetId() == ID)
318 (*it)->OnAbortRequested();
324 * Check for file and print an error if needed
326 bool XBPython::FileExist(const char* strFile)
331 if (!XFILE::CFile::Exists(strFile))
333 CLog::Log(LOGERROR, "Python: Cannot find '%s'", strFile);
339 void XBPython::RegisterExtensionLib(LibraryLoader *pLib)
344 CSingleLock lock(m_critSection);
346 CLog::Log(LOGDEBUG,"%s, adding %s (%p)", __FUNCTION__, pLib->GetName(), (void*)pLib);
347 m_extensions.push_back(pLib);
350 void XBPython::UnregisterExtensionLib(LibraryLoader *pLib)
355 CSingleLock lock(m_critSection);
356 CLog::Log(LOGDEBUG,"%s, removing %s (0x%p)", __FUNCTION__, pLib->GetName(), (void *)pLib);
357 PythonExtensionLibraries::iterator iter = m_extensions.begin();
358 while (iter != m_extensions.end())
362 m_extensions.erase(iter);
369 void XBPython::UnloadExtensionLibs()
371 CLog::Log(LOGDEBUG,"%s, clearing python extension libraries", __FUNCTION__);
372 CSingleLock lock(m_critSection);
373 PythonExtensionLibraries::iterator iter = m_extensions.begin();
374 while (iter != m_extensions.end())
376 DllLoaderContainer::ReleaseModule(*iter);
379 m_extensions.clear();
382 #define MODULE "xbmc"
384 #define RUNSCRIPT_PRAMBLE \
386 "import " MODULE "\n" \
387 "xbmc.abortRequested = False\n" \
389 "\tdef __init__(self, loglevel=" MODULE ".LOGNOTICE):\n" \
390 "\t\tself.ll=loglevel\n" \
391 "\tdef write(self, data):\n" \
392 "\t\t" MODULE ".log(data,self.ll)\n" \
393 "\tdef close(self):\n" \
394 "\t\t" MODULE ".log('.')\n" \
395 "\tdef flush(self):\n" \
396 "\t\t" MODULE ".log('.')\n" \
398 "sys.stdout = xbmcout()\n" \
399 "sys.stderr = xbmcout(" MODULE ".LOGERROR)\n"
401 #define RUNSCRIPT_OVERRIDE_HACK \
404 "def getcwd_xbmc():\n" \
405 " import __main__\n" \
406 " import warnings\n" \
407 " if hasattr(__main__, \"__file__\"):\n" \
408 " warnings.warn(\"os.getcwd() currently lies to you so please use addon.getAddonInfo('path') to find the script's root directory and DO NOT make relative path accesses based on the results of 'os.getcwd.' \", DeprecationWarning, stacklevel=2)\n" \
409 " return os.path.dirname(__main__.__file__)\n" \
411 " return os.getcwd_original()\n" \
413 "def chdir_xbmc(dir):\n" \
414 " raise RuntimeError(\"os.chdir not supported in xbmc\")\n" \
416 "os_getcwd_original = os.getcwd\n" \
417 "os.getcwd = getcwd_xbmc\n" \
418 "os.chdir_orignal = os.chdir\n" \
419 "os.chdir = chdir_xbmc\n" \
422 #define RUNSCRIPT_POSTSCRIPT \
423 "print '-->Python Interpreter Initialized<--'\n" \
426 #define RUNSCRIPT_BWCOMPATIBLE \
427 RUNSCRIPT_PRAMBLE RUNSCRIPT_OVERRIDE_HACK RUNSCRIPT_POSTSCRIPT
429 #define RUNSCRIPT_COMPLIANT \
430 RUNSCRIPT_PRAMBLE RUNSCRIPT_POSTSCRIPT
432 void XBPython::InitializeInterpreter(ADDON::AddonPtr addon)
436 GilSafeSingleLock lock(m_critSection);
437 initModule_xbmcgui();
439 initModule_xbmcplugin();
440 initModule_xbmcaddon();
441 initModule_xbmcvfs();
444 CStdString addonVer = ADDON::GetXbmcApiVersionDependency(addon);
445 bool bwcompatMode = (addon.get() == NULL || (ADDON::AddonVersion(addonVer) <= ADDON::AddonVersion("1.0")));
446 const char* runscript = bwcompatMode ? RUNSCRIPT_BWCOMPATIBLE : RUNSCRIPT_COMPLIANT;
448 // redirecting default output to debug console
449 if (PyRun_SimpleString(runscript) == -1)
451 CLog::Log(LOGFATAL, "Python Initialize Error");
455 void XBPython::DeInitializeInterpreter()
461 * Should be called before executing a script
463 void XBPython::Initialize()
466 CLog::Log(LOGINFO, "initializing python engine. ");
467 CSingleLock lock(m_critSection);
468 m_iDllScriptCounter++;
471 // first we check if all necessary files are installed
473 if(!FileExist("special://xbmc/system/python/DLLs/_socket.pyd") ||
474 !FileExist("special://xbmc/system/python/DLLs/_ssl.pyd") ||
475 !FileExist("special://xbmc/system/python/DLLs/bz2.pyd") ||
476 !FileExist("special://xbmc/system/python/DLLs/pyexpat.pyd") ||
477 !FileExist("special://xbmc/system/python/DLLs/select.pyd") ||
478 !FileExist("special://xbmc/system/python/DLLs/unicodedata.pyd"))
480 CLog::Log(LOGERROR, "Python: Missing files, unable to execute script");
487 // Darwin packs .pyo files, we need PYTHONOPTIMIZE on in order to load them.
488 #if defined(TARGET_DARWIN)
489 setenv("PYTHONOPTIMIZE", "1", 1);
491 // Info about interesting python envvars available
492 // at http://docs.python.org/using/cmdline.html#environment-variables
494 #if !defined(TARGET_WINDOWS) && !defined(TARGET_ANDROID)
495 /* PYTHONOPTIMIZE is set off intentionally when using external Python.
496 Reason for this is because we cannot be sure what version of Python
497 was used to compile the various Python object files (i.e. .pyo,
499 // check if we are running as real xbmc.app or just binary
500 if (!CUtil::GetFrameworksPath(true).IsEmpty())
502 // using external python, it's build looking for xxx/lib/python2.6
503 // so point it to frameworks which is where python2.6 is located
504 setenv("PYTHONHOME", CSpecialProtocol::TranslatePath("special://frameworks").c_str(), 1);
505 setenv("PYTHONPATH", CSpecialProtocol::TranslatePath("special://frameworks").c_str(), 1);
506 CLog::Log(LOGDEBUG, "PYTHONHOME -> %s", CSpecialProtocol::TranslatePath("special://frameworks").c_str());
507 CLog::Log(LOGDEBUG, "PYTHONPATH -> %s", CSpecialProtocol::TranslatePath("special://frameworks").c_str());
509 setenv("PYTHONCASEOK", "1", 1); //This line should really be removed
510 #elif defined(TARGET_WINDOWS)
511 // because the third party build of python is compiled with vs2008 we need
512 // a hack to set the PYTHONPATH
514 buf = "PYTHONPATH=" + CSpecialProtocol::TranslatePath("special://xbmc/system/python/DLLs") + ";" + CSpecialProtocol::TranslatePath("special://xbmc/system/python/Lib");
515 CEnvironment::putenv(buf);
516 buf = "PYTHONOPTIMIZE=1";
517 CEnvironment::putenv(buf);
518 buf = "PYTHONHOME=" + CSpecialProtocol::TranslatePath("special://xbmc/system/python");
519 CEnvironment::putenv(buf);
521 CEnvironment::putenv(buf);
523 #elif defined(TARGET_ANDROID)
524 CStdString apkPath = getenv("XBMC_ANDROID_APK");
525 apkPath += "/assets/python2.6";
526 setenv("PYTHONHOME",apkPath.c_str(), 1);
527 setenv("PYTHONPATH", "", 1);
528 setenv("PYTHONOPTIMIZE","",1);
529 setenv("PYTHONNOUSERSITE","1",1);
532 if (PyEval_ThreadsInitialized())
533 PyEval_AcquireLock();
535 PyEval_InitThreads();
538 PyEval_ReleaseLock();
540 // If this is not the first time we initialize Python, the interpreter
541 // lock already exists and we need to lock it as PyEval_InitThreads
542 // would not do that in that case.
543 PyEval_AcquireLock();
544 char* python_argv[1] = { (char*)"" } ;
545 PySys_SetArgv(1, python_argv);
547 if (!(m_mainThreadState = PyThreadState_Get()))
548 CLog::Log(LOGERROR, "Python threadstate is NULL.");
549 PyEval_ReleaseLock();
551 m_bInitialized = true;
556 * Should be called when a script is finished
558 void XBPython::FinalizeScript()
561 CSingleLock lock(m_critSection);
562 // for linux - we never release the library. its loaded and stays in memory.
563 if (m_iDllScriptCounter)
564 m_iDllScriptCounter--;
566 CLog::Log(LOGERROR, "Python script counter attempted to become negative");
567 m_endtime = XbmcThreads::SystemClockMillis();
571 // Always called with the lock held on m_critSection
572 void XBPython::Finalize()
577 CLog::Log(LOGINFO, "Python, unloading python shared library because no scripts are running anymore");
579 // set the m_bInitialized flag before releasing the lock. This will prevent
580 // Other methods that rely on this flag from an incorrect interpretation.
581 m_bInitialized = false;
582 PyThreadState* curTs = (PyThreadState*)m_mainThreadState;
583 m_mainThreadState = NULL; // clear the main thread state before releasing the lock
585 CSingleExit exit(m_critSection);
586 PyEval_AcquireLock();
587 PyThreadState_Swap(curTs);
590 PyEval_ReleaseLock();
593 #if !(defined(TARGET_DARWIN) || defined(TARGET_WINDOWS))
594 UnloadExtensionLibs();
597 // first free all dlls loaded by python, after that python24.dll (this is done by UnloadPythonDlls
598 #if !(defined(TARGET_DARWIN) || defined(TARGET_WINDOWS))
599 DllLoaderContainer::UnloadPythonDlls();
601 #if defined(TARGET_POSIX) && !defined(TARGET_DARWIN) && !defined(TARGET_FREEBSD)
602 // we can't release it on windows, as this is done in UnloadPythonDlls() for win32 (see above).
603 // The implementation for linux needs looking at - UnloadPythonDlls() currently only searches for "python24.dll"
604 // The implementation for osx can never unload the python dylib.
605 DllLoaderContainer::ReleaseModule(m_pDll);
610 void XBPython::FreeResources()
612 LOCK_AND_COPY(std::vector<PyElem>,tmpvec,m_vecPyList);
614 m_vecPyList.hadSomethingRemoved = true;
616 lock.Leave(); //unlock here because the python thread might lock when it exits
618 // cleanup threads that are still running
619 tmpvec.clear(); // boost releases the XBPyThreads which, if deleted, calls FinalizeScript
622 void XBPython::Process()
628 // autoexec.py - profile
629 CStdString strAutoExecPy = CSpecialProtocol::TranslatePath("special://profile/autoexec.py");
631 if ( XFILE::CFile::Exists(strAutoExecPy) )
632 evalFile(strAutoExecPy,ADDON::AddonPtr());
634 CLog::Log(LOGDEBUG, "%s - no profile autoexec.py (%s) found, skipping", __FUNCTION__, strAutoExecPy.c_str());
637 CSingleLock lock(m_vecPyList);
642 for (PyList::iterator it = m_vecPyList.begin(); it != m_vecPyList.end();)
646 tmpvec.push_back(*it);
647 it = m_vecPyList.erase(it);
648 m_vecPyList.hadSomethingRemoved = true;
655 //delete scripts which are done
656 tmpvec.clear(); // boost releases the XBPyThreads which, if deleted, calls FinalizeScript
658 CSingleLock l2(m_critSection);
659 if(m_iDllScriptCounter == 0 && (XbmcThreads::SystemClockMillis() - m_endtime) > 10000 )
666 bool XBPython::StopScript(const CStdString &path)
669 int id = getScriptId(path);
672 /* if we are here we already know that this script is running.
673 * But we will check it again to be sure :)
684 int XBPython::evalFile(const CStdString &src, ADDON::AddonPtr addon)
686 std::vector<CStdString> argv;
687 return evalFile(src, argv, addon);
689 // execute script, returns -1 if script doesn't exist
690 int XBPython::evalFile(const CStdString &src, const std::vector<CStdString> &argv, ADDON::AddonPtr addon)
692 CSingleExit ex(g_graphicsContext);
693 // return if file doesn't exist
694 if (!XFILE::CFile::Exists(src))
696 CLog::Log(LOGERROR, "Python script \"%s\" does not exist", CSpecialProtocol::TranslatePath(src).c_str());
701 if (CProfilesManager::Get().GetCurrentProfile().programsLocked() && !g_passwordManager.IsMasterLockUnlocked(true))
704 CSingleLock lock(m_vecPyList);
707 if (!m_bInitialized) return -1;
710 boost::shared_ptr<XBPyThread> pyThread = boost::shared_ptr<XBPyThread>(new XBPyThread(this, m_nextid));
711 pyThread->setArgv(argv);
712 pyThread->setAddon(addon);
713 pyThread->evalFile(src);
718 inf.pyThread = pyThread;
720 m_vecPyList.push_back(inf);
725 void XBPython::setDone(int id)
727 CSingleLock lock(m_vecPyList);
728 PyList::iterator it = m_vecPyList.begin();
729 while (it != m_vecPyList.end())
733 if (it->pyThread->isStopping())
734 CLog::Log(LOGINFO, "Python script interrupted by user");
736 CLog::Log(LOGINFO, "Python script stopped");
743 void XBPython::stopScript(int id)
745 CSingleExit ex(g_graphicsContext);
746 CSingleLock lock(m_vecPyList);
747 PyList::iterator it = m_vecPyList.begin();
748 while (it != m_vecPyList.end())
751 CLog::Log(LOGINFO, "Stopping script with id: %i", id);
752 it->pyThread->stop();
759 void* XBPython::getMainThreadState()
761 CSingleLock lock(m_critSection);
762 return m_mainThreadState;
765 int XBPython::ScriptsSize()
767 CSingleLock lock(m_vecPyList);
768 return m_vecPyList.size();
771 const char* XBPython::getFileName(int scriptId)
773 const char* cFileName = NULL;
775 CSingleLock lock(m_vecPyList);
776 PyList::iterator it = m_vecPyList.begin();
777 while (it != m_vecPyList.end())
779 if (it->id == scriptId)
780 cFileName = it->strFile.c_str();
787 int XBPython::getScriptId(const CStdString &strFile)
791 CSingleLock lock(m_vecPyList);
793 PyList::iterator it = m_vecPyList.begin();
794 while (it != m_vecPyList.end())
796 if (it->strFile == strFile)
804 bool XBPython::isRunning(int scriptId)
806 CSingleLock lock(m_vecPyList);
808 for(PyList::iterator it = m_vecPyList.begin(); it != m_vecPyList.end(); ++it)
810 if (it->id == scriptId)
821 bool XBPython::isStopping(int scriptId)
823 bool bStopping = false;
825 CSingleLock lock(m_vecPyList);
826 PyList::iterator it = m_vecPyList.begin();
827 while (it != m_vecPyList.end())
829 if (it->id == scriptId)
830 bStopping = it->pyThread->isStopping();
837 int XBPython::GetPythonScriptId(int scriptPosition)
839 CSingleLock lock(m_vecPyList);
840 return (int)m_vecPyList[scriptPosition].id;
843 void XBPython::PulseGlobalEvent()
848 bool XBPython::WaitForEvent(CEvent& hEvent, unsigned int milliseconds)
850 // wait for either this event our our global event
851 XbmcThreads::CEventGroup eventGroup(&hEvent, &m_globalEvent, NULL);
852 CEvent* ret = eventGroup.wait(milliseconds);
854 m_globalEvent.Reset();
855 return ret == NULL ? false : true;
858 // execute script, returns -1 if script doesn't exist
859 int XBPython::evalString(const CStdString &src, const std::vector<CStdString> &argv)
861 CLog::Log(LOGDEBUG, "XBPython::evalString (python)");
862 CSingleLock lock(m_critSection);
868 CLog::Log(LOGERROR, "XBPython::evalString, python not initialized (python)");
872 // Previous implementation would create a new thread for every script
874 boost::shared_ptr<XBPyThread> pyThread = boost::shared_ptr<XBPyThread>(new XBPyThread(this, m_nextid));
875 pyThread->setArgv(argv);
876 pyThread->evalString(src);
881 inf.strFile = "<string>";
882 inf.pyThread = pyThread;
885 CSingleLock l2(m_vecPyList);
887 m_vecPyList.push_back(inf);