xbmc/filesystem/filesystem.a \
xbmc/guilib/guilib.a \
xbmc/input/input.a \
+ xbmc/interfaces/generic/interfaces-generic.a \
xbmc/interfaces/info/info.a \
xbmc/interfaces/interfaces.a \
xbmc/interfaces/json-rpc/json-rpc.a \
DF402A64164461B9001C56B8 /* LanguageHook.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F502BFE4160F34DC00C96C76 /* LanguageHook.cpp */; };
DF402A65164461B9001C56B8 /* swig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F502BFF0160F36AD00C96C76 /* swig.cpp */; };
DF402A66164461B9001C56B8 /* XBPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F502BFE6160F34FE00C96C76 /* XBPython.cpp */; };
- DF402A67164461B9001C56B8 /* XBPyThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F502BFE8160F34FE00C96C76 /* XBPyThread.cpp */; };
DF404A3916B9896C00D8023E /* cximage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF404A3416B9896C00D8023E /* cximage.cpp */; };
DF404A3A16B9896C00D8023E /* imagefactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF404A3716B9896C00D8023E /* imagefactory.cpp */; };
+ DF40BC1E178B4BEC009DB567 /* PythonInvoker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF40BC1C178B4BEC009DB567 /* PythonInvoker.cpp */; };
+ DF40BC1F178B4BEC009DB567 /* PythonInvoker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF40BC1C178B4BEC009DB567 /* PythonInvoker.cpp */; };
+ DF40BC20178B4BEC009DB567 /* PythonInvoker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF40BC1C178B4BEC009DB567 /* PythonInvoker.cpp */; };
+ DF40BC29178B4C07009DB567 /* LanguageInvokerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF40BC24178B4C07009DB567 /* LanguageInvokerThread.cpp */; };
+ DF40BC2B178B4C07009DB567 /* ScriptInvocationManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF40BC27178B4C07009DB567 /* ScriptInvocationManager.cpp */; };
+ DF40BC2C178B4C07009DB567 /* LanguageInvokerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF40BC24178B4C07009DB567 /* LanguageInvokerThread.cpp */; };
+ DF40BC2E178B4C07009DB567 /* ScriptInvocationManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF40BC27178B4C07009DB567 /* ScriptInvocationManager.cpp */; };
+ DF40BC2F178B4C07009DB567 /* LanguageInvokerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF40BC24178B4C07009DB567 /* LanguageInvokerThread.cpp */; };
+ DF40BC31178B4C07009DB567 /* ScriptInvocationManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF40BC27178B4C07009DB567 /* ScriptInvocationManager.cpp */; };
DF448457140048A60069344B /* AirTunesServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF448455140048A60069344B /* AirTunesServer.cpp */; };
DF44845E140048C80069344B /* PipesManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF44845B140048C80069344B /* PipesManager.cpp */; };
DF52566D1732C1890094A464 /* DVDDemuxCDDA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF52566B1732C1890094A464 /* DVDDemuxCDDA.cpp */; };
DFF0F2E417528350002DA3A4 /* PyContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB02DE816629DBA00F37752 /* PyContext.cpp */; };
DFF0F2E517528350002DA3A4 /* swig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F502BFF0160F36AD00C96C76 /* swig.cpp */; };
DFF0F2E617528350002DA3A4 /* XBPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F502BFE6160F34FE00C96C76 /* XBPython.cpp */; };
- DFF0F2E717528350002DA3A4 /* XBPyThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F502BFE8160F34FE00C96C76 /* XBPyThread.cpp */; };
DFF0F2E817528350002DA3A4 /* AnnouncementManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5A7A700112893E50059D6AA /* AnnouncementManager.cpp */; };
DFF0F2E917528350002DA3A4 /* Builtins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CCF7F1B1069F3AE00992676 /* Builtins.cpp */; };
DFF0F2EA17528350002DA3A4 /* ConvUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38E1D6A0D25F9FD00618676 /* ConvUtils.cpp */; };
E4991365174E5EEF00741B6D /* PyContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB02DE816629DBA00F37752 /* PyContext.cpp */; };
E4991366174E5EEF00741B6D /* swig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F502BFF0160F36AD00C96C76 /* swig.cpp */; };
E4991367174E5EEF00741B6D /* XBPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F502BFE6160F34FE00C96C76 /* XBPython.cpp */; };
- E4991368174E5EEF00741B6D /* XBPyThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F502BFE8160F34FE00C96C76 /* XBPyThread.cpp */; };
E4991369174E5EEF00741B6D /* AnnouncementManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5A7A700112893E50059D6AA /* AnnouncementManager.cpp */; };
E499136A174E5EEF00741B6D /* Builtins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CCF7F1B1069F3AE00992676 /* Builtins.cpp */; };
E499136B174E5EF700741B6D /* ConvUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38E1D6A0D25F9FD00618676 /* ConvUtils.cpp */; };
DF404A3616B9896C00D8023E /* iimage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iimage.h; sourceTree = "<group>"; };
DF404A3716B9896C00D8023E /* imagefactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imagefactory.cpp; sourceTree = "<group>"; };
DF404A3816B9896C00D8023E /* imagefactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imagefactory.h; sourceTree = "<group>"; };
+ DF40BC1C178B4BEC009DB567 /* PythonInvoker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PythonInvoker.cpp; path = python/PythonInvoker.cpp; sourceTree = "<group>"; };
+ DF40BC1D178B4BEC009DB567 /* PythonInvoker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PythonInvoker.h; path = python/PythonInvoker.h; sourceTree = "<group>"; };
+ DF40BC22178B4C07009DB567 /* ILanguageInvocationHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ILanguageInvocationHandler.h; sourceTree = "<group>"; };
+ DF40BC23178B4C07009DB567 /* ILanguageInvoker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ILanguageInvoker.h; sourceTree = "<group>"; };
+ DF40BC24178B4C07009DB567 /* LanguageInvokerThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LanguageInvokerThread.cpp; sourceTree = "<group>"; };
+ DF40BC25178B4C07009DB567 /* LanguageInvokerThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LanguageInvokerThread.h; sourceTree = "<group>"; };
+ DF40BC27178B4C07009DB567 /* ScriptInvocationManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptInvocationManager.cpp; sourceTree = "<group>"; };
+ DF40BC28178B4C07009DB567 /* ScriptInvocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptInvocationManager.h; sourceTree = "<group>"; };
DF448455140048A60069344B /* AirTunesServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AirTunesServer.cpp; sourceTree = "<group>"; };
DF448456140048A60069344B /* AirTunesServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AirTunesServer.h; sourceTree = "<group>"; };
DF44845B140048C80069344B /* PipesManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PipesManager.cpp; sourceTree = "<group>"; };
F502BFE5160F34DC00C96C76 /* LanguageHook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LanguageHook.h; path = python/LanguageHook.h; sourceTree = "<group>"; };
F502BFE6160F34FE00C96C76 /* XBPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = XBPython.cpp; path = python/XBPython.cpp; sourceTree = "<group>"; };
F502BFE7160F34FE00C96C76 /* XBPython.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XBPython.h; path = python/XBPython.h; sourceTree = "<group>"; };
- F502BFE8160F34FE00C96C76 /* XBPyThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = XBPyThread.cpp; path = python/XBPyThread.cpp; sourceTree = "<group>"; };
- F502BFE9160F34FE00C96C76 /* XBPyThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XBPyThread.h; path = python/XBPyThread.h; sourceTree = "<group>"; };
F502BFF0160F36AD00C96C76 /* swig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = swig.cpp; path = python/swig.cpp; sourceTree = "<group>"; };
F502BFF1160F36AD00C96C76 /* swig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = swig.h; path = python/swig.h; sourceTree = "<group>"; };
F50629780E57B9680066625A /* MultiPathFile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MultiPathFile.cpp; sourceTree = "<group>"; };
4367217312D6640E002508E6 /* interfaces */ = {
isa = PBXGroup;
children = (
+ DF40BC21178B4C07009DB567 /* generic */,
7C89674213C03B21003631FE /* info */,
F5AE407F13415D9E0004BD79 /* json-rpc */,
DF1AD17B15FCE77900E10810 /* legacy */,
F502BFE5160F34DC00C96C76 /* LanguageHook.h */,
DFB02DE816629DBA00F37752 /* PyContext.cpp */,
DFB02DE916629DBA00F37752 /* PyContext.h */,
+ DF40BC1C178B4BEC009DB567 /* PythonInvoker.cpp */,
+ DF40BC1D178B4BEC009DB567 /* PythonInvoker.h */,
F502BFF0160F36AD00C96C76 /* swig.cpp */,
F502BFF1160F36AD00C96C76 /* swig.h */,
F502BFE6160F34FE00C96C76 /* XBPython.cpp */,
F502BFE7160F34FE00C96C76 /* XBPython.h */,
- F502BFE8160F34FE00C96C76 /* XBPyThread.cpp */,
- F502BFE9160F34FE00C96C76 /* XBPyThread.h */,
);
name = python;
sourceTree = "<group>";
path = windows;
sourceTree = "<group>";
};
+ DF40BC21178B4C07009DB567 /* generic */ = {
+ isa = PBXGroup;
+ children = (
+ DF40BC22178B4C07009DB567 /* ILanguageInvocationHandler.h */,
+ DF40BC23178B4C07009DB567 /* ILanguageInvoker.h */,
+ DF40BC24178B4C07009DB567 /* LanguageInvokerThread.cpp */,
+ DF40BC25178B4C07009DB567 /* LanguageInvokerThread.h */,
+ DF40BC27178B4C07009DB567 /* ScriptInvocationManager.cpp */,
+ DF40BC28178B4C07009DB567 /* ScriptInvocationManager.h */,
+ );
+ path = generic;
+ sourceTree = "<group>";
+ };
DF527729151BAF4C00B5B63B /* websocket */ = {
isa = PBXGroup;
children = (
DF402A64164461B9001C56B8 /* LanguageHook.cpp in Sources */,
DF402A65164461B9001C56B8 /* swig.cpp in Sources */,
DF402A66164461B9001C56B8 /* XBPython.cpp in Sources */,
- DF402A67164461B9001C56B8 /* XBPyThread.cpp in Sources */,
F5EDC48C1651A6F900B852D8 /* GroupUtils.cpp in Sources */,
7C7CEAF1165629530059C9EB /* AELimiter.cpp in Sources */,
DFB02DEA16629DBA00F37752 /* PyContext.cpp in Sources */,
DFE4095B17417FDF00473BD9 /* LegacyPathTranslation.cpp in Sources */,
0E3036EC1760F68A00D93596 /* FavouritesDirectory.cpp in Sources */,
551C3A45175A12010051AAAD /* VDA.cpp in Sources */,
+ DF40BC20178B4BEC009DB567 /* PythonInvoker.cpp in Sources */,
+ DF40BC2F178B4C07009DB567 /* LanguageInvokerThread.cpp in Sources */,
+ DF40BC31178B4C07009DB567 /* ScriptInvocationManager.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DFF0F2E417528350002DA3A4 /* PyContext.cpp in Sources */,
DFF0F2E517528350002DA3A4 /* swig.cpp in Sources */,
DFF0F2E617528350002DA3A4 /* XBPython.cpp in Sources */,
- DFF0F2E717528350002DA3A4 /* XBPyThread.cpp in Sources */,
DFF0F2E817528350002DA3A4 /* AnnouncementManager.cpp in Sources */,
DFF0F2E917528350002DA3A4 /* Builtins.cpp in Sources */,
DFF0F2EA17528350002DA3A4 /* ConvUtils.cpp in Sources */,
DF3C3C0F1752A7EE000989C3 /* IOSExternalTouchController.mm in Sources */,
DF3C3C101752A7EE000989C3 /* IOSScreenManager.mm in Sources */,
0E3036EE1760F68A00D93596 /* FavouritesDirectory.cpp in Sources */,
+ DF40BC1F178B4BEC009DB567 /* PythonInvoker.cpp in Sources */,
+ DF40BC2C178B4C07009DB567 /* LanguageInvokerThread.cpp in Sources */,
+ DF40BC2E178B4C07009DB567 /* ScriptInvocationManager.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
E4991365174E5EEF00741B6D /* PyContext.cpp in Sources */,
E4991366174E5EEF00741B6D /* swig.cpp in Sources */,
E4991367174E5EEF00741B6D /* XBPython.cpp in Sources */,
- E4991368174E5EEF00741B6D /* XBPyThread.cpp in Sources */,
E4991369174E5EEF00741B6D /* AnnouncementManager.cpp in Sources */,
E499136A174E5EEF00741B6D /* Builtins.cpp in Sources */,
E499136B174E5EF700741B6D /* ConvUtils.cpp in Sources */,
E4991593174E707400741B6D /* cc_decoder.c in Sources */,
E4991596174E70BF00741B6D /* yuv2rgb.neon.S in Sources */,
0E3036ED1760F68A00D93596 /* FavouritesDirectory.cpp in Sources */,
+ DF40BC1E178B4BEC009DB567 /* PythonInvoker.cpp in Sources */,
+ DF40BC29178B4C07009DB567 /* LanguageInvokerThread.cpp in Sources */,
+ DF40BC2B178B4C07009DB567 /* ScriptInvocationManager.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
<ClCompile Include="..\..\xbmc\input\XBMC_keytable.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\AnnouncementManager.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\Builtins.cpp" />
+ <ClCompile Include="..\..\xbmc\interfaces\generic\LanguageInvokerThread.cpp" />
+ <ClCompile Include="..\..\xbmc\interfaces\generic\ScriptInvocationManager.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\info\InfoBool.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\info\SkinVariable.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\json-rpc\AddonsOperations.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\python\generated\AddonModuleXbmcvfs.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\python\LanguageHook.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\python\PyContext.cpp" />
+ <ClCompile Include="..\..\xbmc\interfaces\python\PythonInvoker.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\python\swig.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\python\test\TestSwig.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug (DirectX)|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\xbmc\interfaces\python\XBPython.cpp" />
- <ClCompile Include="..\..\xbmc\interfaces\python\XBPyThread.cpp" />
<ClCompile Include="..\..\xbmc\LangInfo.cpp" />
<ClCompile Include="..\..\xbmc\MediaSource.cpp" />
<ClCompile Include="..\..\xbmc\music\Album.cpp" />
<ClInclude Include="..\..\xbmc\input\touch\ITouchInputHandling.h" />
<ClInclude Include="..\..\xbmc\input\touch\TouchTypes.h" />
<ClInclude Include="..\..\xbmc\input\windows\WINJoystick.h" />
+ <ClInclude Include="..\..\xbmc\interfaces\generic\ILanguageInvocationHandler.h" />
+ <ClInclude Include="..\..\xbmc\interfaces\generic\ILanguageInvoker.h" />
+ <ClInclude Include="..\..\xbmc\interfaces\generic\LanguageInvokerThread.h" />
+ <ClInclude Include="..\..\xbmc\interfaces\generic\ScriptInvocationManager.h" />
<ClInclude Include="..\..\xbmc\interfaces\json-rpc\FavouritesOperations.h" />
<ClInclude Include="..\..\xbmc\interfaces\json-rpc\PVROperations.h" />
<ClInclude Include="..\..\xbmc\interfaces\legacy\Addon.h" />
<ClInclude Include="..\..\xbmc\interfaces\python\LanguageHook.h" />
<ClInclude Include="..\..\xbmc\interfaces\python\preamble.h" />
<ClInclude Include="..\..\xbmc\interfaces\python\PyContext.h" />
+ <ClInclude Include="..\..\xbmc\interfaces\python\PythonInvoker.h" />
<ClInclude Include="..\..\xbmc\interfaces\python\pythreadstate.h" />
<ClInclude Include="..\..\xbmc\music\karaoke\karaokevideobackground.h" />
<ClInclude Include="..\..\xbmc\network\NetworkServices.h" />
<ClInclude Include="..\..\xbmc\video\FFmpegVideoDecoder.h" />
<ClInclude Include="..\..\xbmc\interfaces\python\swig.h" />
<ClInclude Include="..\..\xbmc\interfaces\python\XBPython.h" />
- <ClInclude Include="..\..\xbmc\interfaces\python\XBPyThread.h" />
<ClInclude Include="..\..\xbmc\music\MusicDbUrl.h" />
<ClInclude Include="..\..\xbmc\music\tags\MusicInfoTagLoaderWav.h" />
<ClInclude Include="..\..\xbmc\music\tags\TagLibVFSStream.h" />
<Filter Include="network\mdns">
<UniqueIdentifier>{4deb3d70-7772-42be-8884-4a550c1ff666}</UniqueIdentifier>
</Filter>
+ <Filter Include="interfaces\generic">
+ <UniqueIdentifier>{4286258a-45d7-45e8-9e56-ebf18fea53ec}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\xbmc\win32\pch.cpp">
<ClCompile Include="..\..\xbmc\interfaces\python\XBPython.cpp">
<Filter>interfaces\python</Filter>
</ClCompile>
- <ClCompile Include="..\..\xbmc\interfaces\python\XBPyThread.cpp">
- <Filter>interfaces\python</Filter>
- </ClCompile>
<ClCompile Include="..\..\xbmc\interfaces\python\generated\AddonModuleXbmc.cpp">
<Filter>interfaces\python\generated</Filter>
</ClCompile>
<ClCompile Include="..\..\xbmc\utils\LegacyPathTranslation.cpp">
<Filter>utils</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\interfaces\generic\LanguageInvokerThread.cpp">
+ <Filter>interfaces\generic</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\xbmc\interfaces\generic\ScriptInvocationManager.cpp">
+ <Filter>interfaces\generic</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\xbmc\interfaces\python\PythonInvoker.cpp">
+ <Filter>interfaces\python</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\xbmc\win32\pch.h">
<ClInclude Include="..\..\xbmc\interfaces\python\XBPython.h">
<Filter>interfaces\python</Filter>
</ClInclude>
- <ClInclude Include="..\..\xbmc\interfaces\python\XBPyThread.h">
- <Filter>interfaces\python</Filter>
- </ClInclude>
<ClInclude Include="..\..\xbmc\music\tags\TagLibVFSStream.h">
<Filter>music\tags</Filter>
</ClInclude>
<ClInclude Include="..\..\xbmc\utils\LegacyPathTranslation.h">
<Filter>utils</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\interfaces\generic\ILanguageInvoker.h">
+ <Filter>interfaces\generic</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\interfaces\generic\LanguageInvokerThread.h">
+ <Filter>interfaces\generic</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\interfaces\generic\ScriptInvocationManager.h">
+ <Filter>interfaces\generic</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\interfaces\python\PythonInvoker.h">
+ <Filter>interfaces\python</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\interfaces\generic\ILanguageInvocationHandler.h">
+ <Filter>interfaces\generic</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\xbmc\win32\XBMC_PC.rc">
#include "guilib/GUIColorManager.h"
#include "guilib/GUITextLayout.h"
#include "addons/Skin.h"
+#include "interfaces/generic/ScriptInvocationManager.h"
#ifdef HAS_PYTHON
#include "interfaces/python/XBPython.h"
#endif
m_bPlaybackStarting = false;
m_ePlayState = PLAY_STATE_NONE;
m_skinReloading = false;
+ m_loggingIn = false;
#ifdef HAS_GLX
XInitThreads();
delete m_seekHandler;
delete m_playerController;
delete m_pInertialScrollingHandler;
-
}
bool CApplication::OnEvent(XBMC_Event& newEvent)
// initialize the addon database (must be before the addon manager is init'd)
CDatabaseManager::Get().Initialize(true);
+#ifdef HAS_PYTHON
+ CScriptInvocationManager::Get().RegisterLanguageInvocationHandler(&g_pythonParser, ".py");
+#endif // HAS_PYTHON
+
// start-up Addons Framework
// currently bails out if either cpluff Dll is unavailable or system dir can not be scanned
if (!CAddonMgr::Get().Init())
if (!CProfilesManager::Get().UsingLoginScreen())
{
UpdateLibraries();
-#ifdef HAS_PYTHON
- g_pythonParser.m_bLogin = true;
-#endif
+ SetLoggingIn(true);
}
m_slowTimer.StartZero();
CCrystalHD::RemoveInstance();
#endif
- g_mediaManager.Stop();
+ g_mediaManager.Stop();
- // Stop services before unloading Python
- CAddonMgr::Get().StopServices(false);
+ // Stop services before unloading Python
+ CAddonMgr::Get().StopServices(false);
+
+ // stop all remaining scripts; must be done after skin has been unloaded,
+ // not before some windows still need it when deinitializing during skin
+ // unloading
+ CScriptInvocationManager::Get().Uninitialize();
-/* Python resource freeing must be done after skin has been unloaded, not before
- some windows still need it when deinitializing during skin unloading. */
-#ifdef HAS_PYTHON
- CLog::Log(LOGNOTICE, "stop python");
- g_pythonParser.FreeResources();
-#endif
g_Windowing.DestroyRenderSystem();
g_Windowing.DestroyWindow();
g_Windowing.DestroyWindowSystem();
#ifdef HAS_PYTHON
if (item.IsPythonScript())
{ // a python script
- g_pythonParser.evalFile(item.GetPath().c_str(),ADDON::AddonPtr());
+ CScriptInvocationManager::Get().Execute(item.GetPath());
}
else
#endif
// (this can only be done after g_windowManager.Render())
CApplicationMessenger::Get().ProcessWindowMessages();
-#ifdef HAS_PYTHON
- // process any Python scripts
- g_pythonParser.Process();
-#endif
+ if (m_loggingIn)
+ {
+ m_loggingIn = false;
+
+ // autoexec.py - profile
+ CStdString strAutoExecPy = CSpecialProtocol::TranslatePath("special://profile/autoexec.py");
+
+ if (XFILE::CFile::Exists(strAutoExecPy))
+ CScriptInvocationManager::Get().Execute(strAutoExecPy);
+ else
+ CLog::Log(LOGDEBUG, "no profile autoexec.py (%s) found, skipping", strAutoExecPy.c_str());
+ }
+
+ // handle any active scripts
+ CScriptInvocationManager::Get().Process();
// process messages, even if a movie is playing
CApplicationMessenger::Get().ProcessMessages();
bool SetLanguage(const CStdString &strLanguage);
ReplayGainSettings& GetReplayGainSettings() { return m_replayGainSettings; }
+
+ void SetLoggingIn(bool loggingIn) { m_loggingIn = loggingIn; }
+
protected:
virtual bool OnSettingsSaving() const;
bool m_skinReloading; // if true we disallow LoadSkin until ReloadSkin is called
+ bool m_loggingIn;
+
#if defined(TARGET_DARWIN_IOS)
friend class CWinEventsIOS;
#endif
#include "LangInfo.h"
#include "PlayListPlayer.h"
#include "Util.h"
-#ifdef HAS_PYTHON
-#include "interfaces/python/XBPython.h"
-#endif
#include "pictures/GUIWindowSlideShow.h"
#include "interfaces/Builtins.h"
+#include "interfaces/generic/ScriptInvocationManager.h"
#include "network/Network.h"
#include "utils/log.h"
#include "utils/URIUtils.h"
break;
case TMSG_EXECUTE_SCRIPT:
-#ifdef HAS_PYTHON
- g_pythonParser.evalFile(pMsg->strParam.c_str(),ADDON::AddonPtr());
-#endif
+ CScriptInvocationManager::Get().Execute(pMsg->strParam);
break;
case TMSG_EXECUTE_BUILT_IN:
*
*/
#include "ScreenSaver.h"
+#include "interfaces/generic/ScriptInvocationManager.h"
#include "settings/DisplaySettings.h"
-#include "windowing/WindowingFactory.h"
-
-#ifdef HAS_PYTHON
-#include "interfaces/python/XBPython.h"
#include "utils/AlarmClock.h"
+#include "windowing/WindowingFactory.h"
// What sound does a python screensaver make?
-#define PYTHON_ALARM "sssssscreensaver"
+#define SCRIPT_ALARM "sssssscreensaver"
-#define PYTHON_SCRIPT_TIMEOUT 5 // seconds
-#endif
+#define SCRIPT_TIMEOUT 5 // seconds
namespace ADDON
{
bool CScreenSaver::CreateScreenSaver()
{
-#ifdef HAS_PYTHON
- if (URIUtils::HasExtension(LibPath(), ".py"))
+ if (CScriptInvocationManager::Get().HasLanguageInvoker(LibPath()))
{
// Don't allow a previously-scheduled alarm to kill our new screensaver
- g_alarmClock.Stop(PYTHON_ALARM, true);
+ g_alarmClock.Stop(SCRIPT_ALARM, true);
- if (!g_pythonParser.StopScript(LibPath()))
- g_pythonParser.evalFile(LibPath(), AddonPtr(new CScreenSaver(Props())));
+ if (!CScriptInvocationManager::Get().Stop(LibPath()))
+ CScriptInvocationManager::Get().Execute(LibPath(), AddonPtr(new CScreenSaver(Props())));
return true;
}
-#endif
// pass it the screen width,height
// and the name of the screensaver
int iWidth = g_graphicsContext.GetWidth();
#ifdef HAS_PYTHON
if (URIUtils::HasExtension(LibPath(), ".py"))
{
- g_alarmClock.Start(PYTHON_ALARM, PYTHON_SCRIPT_TIMEOUT, "StopScript(" + LibPath() + ")", true, false);
+ g_alarmClock.Start(SCRIPT_ALARM, SCRIPT_TIMEOUT, "StopScript(" + LibPath() + ")", true, false);
return;
}
#endif
*/
#include "Service.h"
#include "AddonManager.h"
+#include "interfaces/generic/ScriptInvocationManager.h"
#include "utils/log.h"
-#ifdef HAS_PYTHON
-#include "interfaces/python/XBPython.h"
-#endif
using namespace std;
{
#ifdef HAS_PYTHON
case PYTHON:
- ret = (g_pythonParser.evalFile(LibPath(), this->shared_from_this()) != -1);
+ ret = (CScriptInvocationManager::Get().Execute(LibPath(), this->shared_from_this()) != -1);
break;
#endif
{
#ifdef HAS_PYTHON
case PYTHON:
- ret = g_pythonParser.StopScript(LibPath());
+ ret = CScriptInvocationManager::Get().Stop(LibPath());
break;
#endif
#include "addons/AddonManager.h"
#include "addons/AddonInstaller.h"
#include "addons/IAddon.h"
-#ifdef HAS_PYTHON
-#include "interfaces/python/XBPython.h"
-#endif
+#include "interfaces/generic/ScriptInvocationManager.h"
#include "threads/SingleLock.h"
#include "guilib/GUIWindowManager.h"
#include "dialogs/GUIDialogProgress.h"
// setup our parameters to send the script
CStdString strHandle;
strHandle.Format("%i", handle);
- vector<CStdString> argv;
+ vector<string> argv;
argv.push_back(basePath);
argv.push_back(strHandle);
argv.push_back(options);
// run the script
CLog::Log(LOGDEBUG, "%s - calling plugin %s('%s','%s','%s')", __FUNCTION__, m_addon->Name().c_str(), argv[0].c_str(), argv[1].c_str(), argv[2].c_str());
bool success = false;
-#ifdef HAS_PYTHON
CStdString file = m_addon->LibPath();
- int id = g_pythonParser.evalFile(file, argv,m_addon);
+ int id = CScriptInvocationManager::Get().Execute(file, m_addon, argv);
if (id >= 0)
{ // wait for our script to finish
CStdString scriptName = m_addon->Name();
success = WaitOnScriptResult(file, id, scriptName, retrievingDir);
}
else
-#endif
CLog::Log(LOGERROR, "Unable to run plugin %s", m_addon->Name().c_str());
// free our handle
// setup our parameters to send the script
CStdString strHandle;
strHandle.Format("%i", -1);
- vector<CStdString> argv;
+ vector<string> argv;
argv.push_back(basePath);
argv.push_back(strHandle);
argv.push_back(options);
// run the script
-#ifdef HAS_PYTHON
CLog::Log(LOGDEBUG, "%s - calling plugin %s('%s','%s','%s')", __FUNCTION__, addon->Name().c_str(), argv[0].c_str(), argv[1].c_str(), argv[2].c_str());
- if (g_pythonParser.evalFile(addon->LibPath(), argv,addon) >= 0)
+ if (CScriptInvocationManager::Get().Execute(addon->LibPath(), addon, argv) >= 0)
return true;
else
-#endif
CLog::Log(LOGERROR, "Unable to run plugin %s", addon->Name().c_str());
return false;
}
}
// check our script is still running
-#ifdef HAS_PYTHON
- if (!g_pythonParser.isRunning(scriptId))
-#endif
+ if (!CScriptInvocationManager::Get().IsRunning(scriptId))
{ // check whether we exited normally
if (!m_fetchComplete.WaitMSec(0))
{ // python didn't return correctly
}
if (cancelled && XbmcThreads::SystemClockMillis() - startTime > timeToKillScript)
{ // cancel our script
-#ifdef HAS_PYTHON
- if (scriptId != -1 && g_pythonParser.isRunning(scriptId))
+ if (scriptId != -1 && CScriptInvocationManager::Get().IsRunning(scriptId))
{
CLog::Log(LOGDEBUG, "%s- cancelling plugin %s (id=%d)", __FUNCTION__, scriptName.c_str(), scriptId);
- g_pythonParser.stopScript(scriptId);
+ CScriptInvocationManager::Get().Stop(scriptId);
break;
}
-#endif
}
}
#include "addons/AddonInstaller.h"
#include "addons/AddonManager.h"
#include "addons/PluginSource.h"
+#include "interfaces/generic/ScriptInvocationManager.h"
#include "network/NetworkServices.h"
#include "utils/log.h"
#include "storage/MediaManager.h"
#endif
-#ifdef HAS_PYTHON
-#include "interfaces/python/XBPython.h"
-#endif
-
#if defined(TARGET_DARWIN)
#include "filesystem/SpecialProtocol.h"
#include "osx/CocoaInterface.h"
else
#endif
{
-#ifdef HAS_PYTHON
- vector<CStdString> argv = params;
+ vector<string> argv;
+ for (vector<CStdString>::const_iterator param = params.begin(); param != params.end(); ++param)
+ argv.push_back(*param);
vector<CStdString> path;
//split the path up to find the filename
if (CAddonMgr::Get().GetAddon(params[0], script))
scriptpath = script->LibPath();
- g_pythonParser.evalFile(scriptpath, argv,script);
-#endif
+ CScriptInvocationManager::Get().Execute(scriptpath, script, argv);
}
}
#if defined(TARGET_DARWIN_OSX)
#endif
else if (execute.Equals("stopscript"))
{
-#ifdef HAS_PYTHON
CStdString scriptpath(params[0]);
// Test to see if the param is an addon ID
if (CAddonMgr::Get().GetAddon(params[0], script))
scriptpath = script->LibPath();
- g_pythonParser.StopScript(scriptpath);
-#endif
+ CScriptInvocationManager::Get().Stop(scriptpath);
}
else if (execute.Equals("system.exec"))
{
--- /dev/null
+#pragma once
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+class ILanguageInvoker;
+
+class ILanguageInvocationHandler
+{
+public:
+ ILanguageInvocationHandler() { }
+ virtual ~ILanguageInvocationHandler() { }
+
+ virtual bool Initialize() { return true; }
+ virtual void Process() { }
+ virtual void Uninitialize() { }
+
+ virtual void OnScriptStarted(ILanguageInvoker *invoker) { }
+ virtual void OnScriptEnded(ILanguageInvoker *invoker) { }
+
+ virtual ILanguageInvoker* CreateInvoker() = 0;
+};
--- /dev/null
+#pragma once
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <string>
+#include <vector>
+
+#include "ILanguageInvocationHandler.h"
+#include "addons/IAddon.h"
+
+class CLanguageInvokerThread;
+
+typedef enum {
+ InvokerStateUninitialized,
+ InvokerStateInitialized,
+ InvokerStateRunning,
+ InvokerStateStopping,
+ InvokerStateDone,
+ InvokerStateFailed
+} InvokerState;
+
+class ILanguageInvoker
+{
+public:
+ ILanguageInvoker(ILanguageInvocationHandler *invocationHandler)
+ : m_id(-1), m_state(InvokerStateUninitialized),
+ m_invocationHandler(invocationHandler)
+ { }
+ virtual ~ILanguageInvoker() { }
+
+ virtual bool Execute(const std::string &script, const std::vector<std::string> &arguments = std::vector<std::string>())
+ {
+ if (m_invocationHandler)
+ m_invocationHandler->OnScriptStarted(this);
+
+ return execute(script, arguments);
+ }
+ virtual bool Stop(bool abort = false) { return stop(abort); }
+
+ void SetId(int id) { m_id = id; }
+ int GetId() const { return m_id; }
+ void SetAddon(const ADDON::AddonPtr &addon) { m_addon = addon; }
+ InvokerState GetState() const { return m_state; }
+ bool IsActive() const { return GetState() > InvokerStateUninitialized && GetState() < InvokerStateDone; }
+ bool IsRunning() const { return GetState() == InvokerStateRunning; }
+ virtual bool IsStopping() const { return GetState() == InvokerStateStopping; }
+
+protected:
+ friend class CLanguageInvokerThread;
+
+ virtual bool execute(const std::string &script, const std::vector<std::string> &arguments) = 0;
+ virtual bool stop(bool abort) = 0;
+
+ virtual void onError()
+ {
+ if (m_invocationHandler)
+ m_invocationHandler->OnScriptEnded(this);
+ }
+ virtual void onDone()
+ {
+ if (m_invocationHandler)
+ m_invocationHandler->OnScriptEnded(this);
+ }
+
+ void setState(InvokerState state)
+ {
+ if (state <= m_state)
+ return;
+
+ m_state = state;
+ }
+
+ ADDON::AddonPtr m_addon;
+
+private:
+ int m_id;
+ InvokerState m_state;
+ ILanguageInvocationHandler *m_invocationHandler;
+};
--- /dev/null
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "LanguageInvokerThread.h"
+#include "ScriptInvocationManager.h"
+
+CLanguageInvokerThread::CLanguageInvokerThread(ILanguageInvoker *invoker, CScriptInvocationManager *invocationManager)
+ : ILanguageInvoker(NULL),
+ CThread("LanguageInvoker"),
+ m_invoker(invoker),
+ m_invocationManager(invocationManager)
+{ }
+
+CLanguageInvokerThread::~CLanguageInvokerThread()
+{
+ Stop(true);
+ delete m_invoker;
+}
+
+InvokerState CLanguageInvokerThread::GetState()
+{
+ if (m_invoker == NULL)
+ return InvokerStateFailed;
+
+ return m_invoker->GetState();
+}
+
+bool CLanguageInvokerThread::execute(const std::string &script, const std::vector<std::string> &arguments)
+{
+ if (m_invoker == NULL || script.empty())
+ return false;
+
+ m_script = script;
+ m_args = arguments;
+
+ Create();
+ return true;
+}
+
+bool CLanguageInvokerThread::stop(bool wait)
+{
+ if (m_invoker == NULL)
+ return false;
+
+ if (!CThread::IsRunning())
+ return false;
+
+ bool result = true;
+ if (m_invoker->GetState() < InvokerStateDone)
+ {
+ // stop the language-specific invoker
+ result = m_invoker->Stop(wait);
+ // stop the thread
+ CThread::StopThread(wait);
+ }
+
+ return result;
+}
+
+void CLanguageInvokerThread::OnStartup()
+{
+ if (m_invoker == NULL)
+ return;
+
+ m_invoker->SetId(GetId());
+ if (m_addon != NULL)
+ m_invoker->SetAddon(m_addon);
+}
+
+void CLanguageInvokerThread::Process()
+{
+ if (m_invoker == NULL)
+ return;
+
+ m_invoker->Execute(m_script, m_args);
+}
+
+void CLanguageInvokerThread::OnExit()
+{
+ if (m_invoker == NULL)
+ return;
+
+ m_invoker->onDone();
+ m_invocationManager->OnScriptEnded(GetId());
+}
+
+void CLanguageInvokerThread::OnException()
+{
+ if (m_invoker == NULL)
+ return;
+
+ m_invoker->onError();
+ m_invocationManager->OnScriptEnded(GetId());
+}
\ No newline at end of file
--- /dev/null
+#pragma once
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "ILanguageInvoker.h"
+#include "threads/Thread.h"
+
+class CScriptInvocationManager;
+
+class CLanguageInvokerThread : public ILanguageInvoker, protected CThread
+{
+public:
+ CLanguageInvokerThread(ILanguageInvoker *invoker, CScriptInvocationManager *invocationManager);
+ ~CLanguageInvokerThread();
+
+ virtual InvokerState GetState();
+
+protected:
+ virtual bool execute(const std::string &script, const std::vector<std::string> &arguments);
+ virtual bool stop(bool wait);
+
+ virtual void OnStartup();
+ virtual void Process();
+ virtual void OnExit();
+ virtual void OnException();
+
+private:
+ ILanguageInvoker *m_invoker;
+ CScriptInvocationManager *m_invocationManager;
+ std::string m_script;
+ std::vector<std::string> m_args;
+};
\ No newline at end of file
--- /dev/null
+SRCS=LanguageInvokerThread.cpp \
+ ScriptInvocationManager.cpp \
+
+LIB=interfaces-generic.a
+
+include ../../../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
--- /dev/null
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <vector>
+
+#include "ScriptInvocationManager.h"
+#include "ILanguageInvocationHandler.h"
+#include "ILanguageInvoker.h"
+#include "LanguageInvokerThread.h"
+#include "filesystem/File.h"
+#include "threads/SingleLock.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+
+using namespace std;
+using namespace XFILE;
+
+CScriptInvocationManager::CScriptInvocationManager()
+ : m_nextId(0)
+{ }
+
+CScriptInvocationManager::~CScriptInvocationManager()
+{
+ Uninitialize();
+}
+
+CScriptInvocationManager& CScriptInvocationManager::Get()
+{
+ static CScriptInvocationManager s_instance;
+ return s_instance;
+}
+
+void CScriptInvocationManager::Process()
+{
+ CSingleLock lock(m_critSection);
+ // go through all active threads and find and remove all which are done
+ vector<LanguageInvokerThread> tempList;
+ for (LanguageInvokerThreadMap::iterator it = m_scripts.begin(); it != m_scripts.end(); )
+ {
+ if (it->second.done)
+ {
+ tempList.push_back(it->second);
+ m_scripts.erase(it++);
+ }
+ else
+ ++it;
+ }
+
+ // remove the finished scripts from the script path map as well
+ for (vector<LanguageInvokerThread>::const_iterator it = tempList.begin(); it != tempList.end(); ++it)
+ m_scriptPaths.erase(it->script);
+
+ // we can leave the lock now
+ lock.Leave();
+
+ // finally remove the finished threads but we do it outside of any locks in
+ // case of any callbacks from the destruction of the CLanguageInvokerThread
+ tempList.clear();
+
+ // let the invocation handlers do their processing
+ for (LanguageInvocationHandlerMap::iterator it = m_invocationHandlers.begin(); it != m_invocationHandlers.end(); ++it)
+ it->second->Process();
+}
+
+void CScriptInvocationManager::Uninitialize()
+{
+ CSingleLock lock(m_critSection);
+
+ // execute Process() once more to handle the remaining scripts
+ Process();
+
+ // make sure all scripts are done
+ vector<LanguageInvokerThread> tempList;
+ for (LanguageInvokerThreadMap::iterator script = m_scripts.begin(); script != m_scripts.end(); ++script)
+ tempList.push_back(script->second);
+
+ m_scripts.clear();
+ m_scriptPaths.clear();
+
+ // we can leave the lock now
+ lock.Leave();
+
+ // finally stop and remove the finished threads but we do it outside of any
+ // locks in case of any callbacks from the stop or destruction logic of
+ // CLanguageInvokerThread or the ILanguageInvoker implementation
+ for (vector<LanguageInvokerThread>::iterator it = tempList.begin(); it != tempList.end(); ++it)
+ {
+ if (!it->done)
+ it->thread->Stop(true);
+ }
+ tempList.clear();
+
+ lock.Enter();
+ // uninitialize all invocation handlers and then remove them
+ for (LanguageInvocationHandlerMap::iterator it = m_invocationHandlers.begin(); it != m_invocationHandlers.end(); ++it)
+ it->second->Uninitialize();
+
+ m_invocationHandlers.clear();
+}
+
+void CScriptInvocationManager::RegisterLanguageInvocationHandler(ILanguageInvocationHandler *invocationHandler, const std::string &extension)
+{
+ if (invocationHandler == NULL || extension.empty())
+ return;
+
+ string ext = extension;
+ StringUtils::ToLower(ext);
+ if (!StringUtils::StartsWith(ext, "."))
+ ext = "." + ext;
+
+ CSingleLock lock(m_critSection);
+ if (m_invocationHandlers.find(ext) != m_invocationHandlers.end())
+ return;
+
+ m_invocationHandlers.insert(make_pair(extension, invocationHandler));
+
+ bool known = false;
+ for (std::map<std::string, ILanguageInvocationHandler*>::const_iterator it = m_invocationHandlers.begin(); it != m_invocationHandlers.end(); ++it)
+ {
+ if (it->second == invocationHandler)
+ {
+ known = true;
+ break;
+ }
+ }
+
+ // automatically initialize the invocation handler if it's a new one
+ if (!known)
+ invocationHandler->Initialize();
+}
+
+void CScriptInvocationManager::RegisterLanguageInvocationHandler(ILanguageInvocationHandler *invocationHandler, const std::set<std::string> &extensions)
+{
+ if (invocationHandler == NULL || extensions.empty())
+ return;
+
+ for (set<string>::const_iterator extension = extensions.begin(); extension != extensions.end(); ++extension)
+ RegisterLanguageInvocationHandler(invocationHandler, *extension);
+}
+
+void CScriptInvocationManager::UnregisterLanguageInvocationHandler(ILanguageInvocationHandler *invocationHandler)
+{
+ if (invocationHandler == NULL)
+ return;
+
+ CSingleLock lock(m_critSection);
+ // get all extensions of the given language invoker
+ for (map<string, ILanguageInvocationHandler*>::iterator it = m_invocationHandlers.begin(); it != m_invocationHandlers.end(); )
+ {
+ if (it->second == invocationHandler)
+ m_invocationHandlers.erase(it++);
+ else
+ ++it;
+ }
+
+ // automatically uninitialize the invocation handler
+ invocationHandler->Uninitialize();
+}
+
+bool CScriptInvocationManager::HasLanguageInvoker(const std::string &script) const
+{
+ std::string extension = URIUtils::GetExtension(script);
+ StringUtils::ToLower(extension);
+
+ CSingleLock lock(m_critSection);
+ map<string, ILanguageInvocationHandler*>::const_iterator it = m_invocationHandlers.find(extension);
+ return it != m_invocationHandlers.end() && it->second != NULL;
+}
+
+ILanguageInvoker* CScriptInvocationManager::GetLanguageInvoker(const std::string &script) const
+{
+ std::string extension = URIUtils::GetExtension(script);
+ StringUtils::ToLower(extension);
+
+ CSingleLock lock(m_critSection);
+ map<string, ILanguageInvocationHandler*>::const_iterator it = m_invocationHandlers.find(extension);
+ if (it != m_invocationHandlers.end() && it->second != NULL)
+ return it->second->CreateInvoker();
+
+ return NULL;
+}
+
+int CScriptInvocationManager::Execute(const std::string &script, const ADDON::AddonPtr &addon /* = ADDON::AddonPtr() */, const std::vector<std::string> &arguments /* = std::vector<std::string>() */)
+{
+ if (script.empty() || !CFile::Exists(script, false))
+ return -1;
+
+ ILanguageInvoker *invoker = GetLanguageInvoker(script);
+ if (invoker == NULL)
+ return -1;
+
+ CLanguageInvokerThreadPtr invokerThread = CLanguageInvokerThreadPtr(new CLanguageInvokerThread(invoker, this));
+ if (invokerThread == NULL)
+ return -1;
+
+ if (addon != NULL)
+ invokerThread->SetAddon(addon);
+
+ CSingleLock lock(m_critSection);
+ invokerThread->SetId(m_nextId++);
+ lock.Leave();
+
+ LanguageInvokerThread thread = { invokerThread, script, false };
+ m_scripts.insert(make_pair(invokerThread->GetId(), thread));
+ m_scriptPaths.insert(make_pair(script, invokerThread->GetId()));
+ invokerThread->Execute(script, arguments);
+
+ return invokerThread->GetId();
+}
+
+bool CScriptInvocationManager::Stop(int scriptId, bool wait /* = false */)
+{
+ if (scriptId < 0)
+ return false;
+
+ CSingleLock lock(m_critSection);
+ CLanguageInvokerThreadPtr invokerThread = getInvokerThread(scriptId).thread;
+ if (invokerThread == NULL)
+ return false;
+
+ return invokerThread->Stop(wait);
+}
+
+bool CScriptInvocationManager::Stop(const std::string &scriptPath, bool wait /* = false */)
+{
+ if (scriptPath.empty())
+ return false;
+
+ CSingleLock lock(m_critSection);
+ std::map<std::string, int>::const_iterator script = m_scriptPaths.find(scriptPath);
+ if (script == m_scriptPaths.end())
+ return false;
+
+ return Stop(script->second, wait);
+}
+
+bool CScriptInvocationManager::IsRunning(int scriptId) const
+{
+ CSingleLock lock(m_critSection);
+ LanguageInvokerThread invokerThread = getInvokerThread(scriptId);
+ if (invokerThread.thread == NULL)
+ return false;
+
+ return !invokerThread.done;
+}
+
+void CScriptInvocationManager::OnScriptEnded(int scriptId)
+{
+ if (scriptId < 0)
+ return;
+
+ CSingleLock lock(m_critSection);
+ LanguageInvokerThreadMap::iterator script = m_scripts.find(scriptId);
+ if (script != m_scripts.end())
+ script->second.done = true;
+}
+
+CScriptInvocationManager::LanguageInvokerThread CScriptInvocationManager::getInvokerThread(int scriptId) const
+{
+ if (scriptId < 0)
+ return LanguageInvokerThread();
+
+ LanguageInvokerThreadMap::const_iterator script = m_scripts.find(scriptId);
+ if (script == m_scripts.end())
+ return LanguageInvokerThread();
+
+ return script->second;
+}
--- /dev/null
+#pragma once
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <map>
+#include <set>
+#include <boost/shared_ptr.hpp>
+
+#include "addons/IAddon.h"
+#include "threads/CriticalSection.h"
+
+class ILanguageInvocationHandler;
+class ILanguageInvoker;
+class CLanguageInvokerThread;
+typedef boost::shared_ptr<CLanguageInvokerThread> CLanguageInvokerThreadPtr;
+
+class CScriptInvocationManager
+{
+public:
+ static CScriptInvocationManager& Get();
+
+ void Process();
+ void Uninitialize();
+
+ void RegisterLanguageInvocationHandler(ILanguageInvocationHandler *invocationHandler, const std::string &extension);
+ void RegisterLanguageInvocationHandler(ILanguageInvocationHandler *invocationHandler, const std::set<std::string> &extensions);
+ void UnregisterLanguageInvocationHandler(ILanguageInvocationHandler *invocationHandler);
+ bool HasLanguageInvoker(const std::string &script) const;
+ ILanguageInvoker* GetLanguageInvoker(const std::string &script) const;
+
+ int Execute(const std::string &script, const ADDON::AddonPtr &addon = ADDON::AddonPtr(), const std::vector<std::string> &arguments = std::vector<std::string>());
+ bool Stop(int scriptId, bool wait = false);
+ bool Stop(const std::string &scriptPath, bool wait = false);
+
+ bool IsRunning(int scriptId) const;
+
+protected:
+ friend class CLanguageInvokerThread;
+
+ void OnScriptEnded(int scriptId);
+
+private:
+ CScriptInvocationManager();
+ CScriptInvocationManager(const CScriptInvocationManager&);
+ CScriptInvocationManager const& operator=(CScriptInvocationManager const&);
+ virtual ~CScriptInvocationManager();
+
+ typedef struct {
+ CLanguageInvokerThreadPtr thread;
+ std::string script;
+ bool done;
+ } LanguageInvokerThread;
+ typedef std::map<int, LanguageInvokerThread> LanguageInvokerThreadMap;
+ typedef std::map<std::string, ILanguageInvocationHandler*> LanguageInvocationHandlerMap;
+
+ LanguageInvokerThread getInvokerThread(int scriptId) const;
+
+ LanguageInvocationHandlerMap m_invocationHandlers;
+ LanguageInvokerThreadMap m_scripts;
+ std::map<std::string, int> m_scriptPaths;
+ int m_nextId;
+ CCriticalSection m_critSection;
+};
\ No newline at end of file
include ../../../codegenerator.mk
SRCS= CallbackHandler.cpp LanguageHook.cpp \
- XBPyThread.cpp XBPython.cpp swig.cpp PyContext.cpp \
+ PythonInvoker.cpp XBPython.cpp swig.cpp PyContext.cpp \
$(GENERATED)
INCLUDES += @PYTHON_CPPFLAGS@
--- /dev/null
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
+ #include "config.h"
+#endif
+
+// python.h should always be included first before any other includes
+#include <Python.h>
+#include <osdefs.h>
+
+#include "system.h"
+#include "PythonInvoker.h"
+#include "Application.h"
+#include "ApplicationMessenger.h"
+#include "addons/AddonManager.h"
+#include "dialogs/GUIDialogKaiToast.h"
+#include "filesystem/File.h"
+#include "filesystem/SpecialProtocol.h"
+#include "guilib/GraphicContext.h"
+#include "guilib/GUIWindowManager.h"
+#include "interfaces/legacy/Addon.h"
+#include "interfaces/python/LanguageHook.h"
+#include "interfaces/python/PyContext.h"
+#include "interfaces/python/pythreadstate.h"
+#include "interfaces/python/swig.h"
+#include "interfaces/python/XBPython.h"
+#include "threads/SingleLock.h"
+#if defined(TARGET_WINDOWS)
+#include "utils/CharsetConverter.h"
+#endif // defined(TARGET_WINDOWS)
+#include "utils/log.h"
+#include "utils/URIUtils.h"
+
+#ifdef TARGET_WINDOWS
+extern "C" FILE *fopen_utf8(const char *_Filename, const char *_Mode);
+#else
+#define fopen_utf8 fopen
+#endif
+
+#define GC_SCRIPT \
+ "import gc\n" \
+ "gc.collect(2)\n"
+
+#define PY_PATH_SEP DELIM
+
+// Time before ill-behaved scripts are terminated
+#define PYTHON_SCRIPT_TIMEOUT 5000 // ms
+
+using namespace std;
+using namespace XFILE;
+
+extern "C"
+{
+ int xbp_chdir(const char *dirname);
+ char* dll_getenv(const char* szKey);
+}
+
+static const CStdString getListOfAddonClassesAsString(XBMCAddon::AddonClass::Ref<XBMCAddon::Python::LanguageHook>& languageHook)
+{
+ CStdString message;
+ XBMCAddon::AddonClass::Synchronize l(*(languageHook.get()));
+ std::set<XBMCAddon::AddonClass*>& acs = languageHook->GetRegisteredAddonClasses();
+ bool firstTime = true;
+ for (std::set<XBMCAddon::AddonClass*>::iterator iter = acs.begin(); iter != acs.end(); ++iter)
+ {
+ if (!firstTime)
+ message += ",";
+ else
+ firstTime = false;
+ message += (*iter)->GetClassname().c_str();
+ }
+
+ return message;
+}
+
+CPythonInvoker::CPythonInvoker(ILanguageInvocationHandler *invocationHandler)
+ : ILanguageInvoker(invocationHandler),
+ m_source(NULL), m_argc(0), m_argv(NULL),
+ m_threadState(NULL), m_stop(false)
+{ }
+
+CPythonInvoker::~CPythonInvoker()
+{
+ // nothing to do for the default invoker used for registration with the
+ // CScriptInvocationManager
+ if (GetId() < 0)
+ return;
+
+ if (GetState() < InvokerStateDone)
+ CLog::Log(LOGDEBUG, "CPythonInvoker(%d): waiting for python thread \"%s\" to stop",
+ GetId(), (m_source != NULL ? m_source : "unknown script"));
+ Stop(true);
+ g_pythonParser.PulseGlobalEvent();
+
+ delete [] m_source;
+ if (m_argv != NULL)
+ {
+ for (unsigned int i = 0; i < m_argc; i++)
+ delete [] m_argv[i];
+ delete [] m_argv;
+ }
+ g_pythonParser.FinalizeScript();
+}
+
+bool CPythonInvoker::Execute(const std::string &script, const std::vector<std::string> &arguments /* = std::vector<std::string>() */)
+{
+ if (script.empty())
+ return false;
+
+ if (!CFile::Exists(script))
+ {
+ CLog::Log(LOGERROR, "CPythonInvoker(%d): python script \"%s\" does not exist", GetId(), CSpecialProtocol::TranslatePath(script).c_str());
+ return false;
+ }
+
+ if (!g_pythonParser.InitializeEngine())
+ return false;
+
+ return ILanguageInvoker::Execute(script, arguments);
+}
+
+bool CPythonInvoker::execute(const std::string &script, const std::vector<std::string> &arguments)
+{
+ // copy the code/script into a local string buffer
+#ifdef TARGET_WINDOWS
+ CStdString strsrc = script;
+ g_charsetConverter.utf8ToSystem(strsrc);
+ m_source = new char[strsrc.length() + 1];
+ strcpy(m_source, strsrc);
+#else
+ m_source = new char[script.length() + 1];
+ strcpy(m_source, script.c_str());
+#endif
+
+ // copy the arguments into a local buffer
+ m_argc = arguments.size();
+ m_argv = new char*[m_argc];
+ for (unsigned int i = 0; i < m_argc; i++)
+ {
+ m_argv[i] = new char[arguments.at(i).length() + 1];
+ strcpy(m_argv[i], arguments.at(i).c_str());
+ }
+
+ CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): start processing", GetId(), m_source);
+ int m_Py_file_input = Py_file_input;
+
+ // get the global lock
+ PyEval_AcquireLock();
+ PyThreadState* state = Py_NewInterpreter();
+ if (state == NULL)
+ {
+ PyEval_ReleaseLock();
+ CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): FAILED to get thread state!", GetId(), m_source);
+ return false;
+ }
+ // swap in my thread state
+ PyThreadState_Swap(state);
+
+ XBMCAddon::AddonClass::Ref<XBMCAddon::Python::LanguageHook> languageHook(new XBMCAddon::Python::LanguageHook(state->interp));
+ languageHook->RegisterMe();
+
+ g_pythonParser.InitializeInterpreter(m_addon);
+ setState(InvokerStateInitialized);
+
+ CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): the source file to load is %s", GetId(), m_source, m_source);
+
+ // get path from script file name and add python path's
+ // this is used for python so it will search modules from script path first
+ CStdString scriptDir;
+ URIUtils::GetDirectory(CSpecialProtocol::TranslatePath(m_source), scriptDir);
+ URIUtils::RemoveSlashAtEnd(scriptDir);
+ addPath(scriptDir);
+
+ // add on any addon modules the user has installed
+ ADDON::VECADDONS addons;
+ ADDON::CAddonMgr::Get().GetAddons(ADDON::ADDON_SCRIPT_MODULE, addons);
+ for (unsigned int i = 0; i < addons.size(); ++i)
+ addPath(CSpecialProtocol::TranslatePath(addons[i]->LibPath()));
+
+ // we want to use sys.path so it includes site-packages
+ // if this fails, default to using Py_GetPath
+ PyObject *sysMod(PyImport_ImportModule((char*)"sys")); // must call Py_DECREF when finished
+ PyObject *sysModDict(PyModule_GetDict(sysMod)); // borrowed ref, no need to delete
+ PyObject *pathObj(PyDict_GetItemString(sysModDict, "path")); // borrowed ref, no need to delete
+
+ if (pathObj != NULL && PyList_Check(pathObj))
+ {
+ for (int i = 0; i < PyList_Size(pathObj); i++)
+ {
+ PyObject *e = PyList_GetItem(pathObj, i); // borrowed ref, no need to delete
+ if (e != NULL && PyString_Check(e))
+ addPath(PyString_AsString(e)); // returns internal data, don't delete or modify
+ }
+ }
+ else
+ addPath(Py_GetPath());
+
+ Py_DECREF(sysMod); // release ref to sysMod
+
+ // set current directory and python's path.
+ if (m_argv != NULL)
+ PySys_SetArgv(m_argc, m_argv);
+
+ CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): setting the Python path to %s", GetId(), m_source, m_pythonPath.c_str());
+ PySys_SetPath((char *)m_pythonPath.c_str());
+
+ CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): entering source directory %s", GetId(), m_source, scriptDir.c_str());
+ PyObject* module = PyImport_AddModule((char*)"__main__");
+ PyObject* moduleDict = PyModule_GetDict(module);
+
+ // when we are done initing we store thread state so we can be aborted
+ PyThreadState_Swap(NULL);
+ PyEval_ReleaseLock();
+
+ // we need to check if we was asked to abort before we had inited
+ bool stopping = false;
+ { CSingleLock lock(m_critical);
+ m_threadState = state;
+ stopping = m_stop;
+ }
+
+ PyEval_AcquireLock();
+ PyThreadState_Swap(state);
+
+ bool failed = false;
+ if (!stopping)
+ {
+ try
+ {
+ // run script from file
+ // We need to have python open the file because on Windows the DLL that python
+ // is linked against may not be the DLL that xbmc is linked against so
+ // passing a FILE* to python from an fopen has the potential to crash.
+ PyObject* file = PyFile_FromString((char *) CSpecialProtocol::TranslatePath(m_source).c_str(), (char*)"r");
+ FILE *fp = PyFile_AsFile(file);
+
+ if (fp != NULL)
+ {
+ PyObject *f = PyString_FromString(CSpecialProtocol::TranslatePath(m_source).c_str());
+ PyDict_SetItemString(moduleDict, "__file__", f);
+
+ if (m_addon.get() != NULL)
+ {
+ PyObject *pyaddonid = PyString_FromString(m_addon->ID().c_str());
+ PyDict_SetItemString(moduleDict, "__xbmcaddonid__", pyaddonid);
+
+ CStdString version = ADDON::GetXbmcApiVersionDependency(m_addon);
+ PyObject *pyxbmcapiversion = PyString_FromString(version.c_str());
+ PyDict_SetItemString(moduleDict, "__xbmcapiversion__", pyxbmcapiversion);
+
+ CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): instantiating addon using automatically obtained id of \"%s\" dependent on version %s of the xbmc.python api",
+ GetId(), m_source, m_addon->ID().c_str(), version.c_str());
+ }
+
+ Py_DECREF(f);
+ setState(InvokerStateRunning);
+ XBMCAddon::Python::PyContext pycontext; // this is a guard class that marks this callstack as being in a python context
+ PyRun_FileExFlags(fp, CSpecialProtocol::TranslatePath(m_source).c_str(), m_Py_file_input, moduleDict, moduleDict,1,NULL);
+ }
+ else
+ CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): %s not found!", GetId(), m_source, m_source);
+ }
+ catch (const XbmcCommons::Exception& e)
+ {
+ setState(InvokerStateFailed);
+ e.LogThrowMessage();
+ failed = true;
+ }
+ catch (...)
+ {
+ setState(InvokerStateFailed);
+ CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): failure in script", GetId(), m_source);
+ failed = true;
+ }
+ }
+
+ bool systemExitThrown = false;
+ if (!failed && !PyErr_Occurred())
+ {
+ CLog::Log(LOGINFO, "CPythonInvoker(%d, %s): script successfully run", GetId(), m_source);
+ setState(InvokerStateDone);
+ }
+ else if (PyErr_ExceptionMatches(PyExc_SystemExit))
+ {
+ systemExitThrown = true;
+ CLog::Log(LOGINFO, "CPythonInvoker(%d, %s): script aborted", GetId(), m_source);
+ setState(InvokerStateFailed);
+ }
+ else
+ {
+ setState(InvokerStateFailed);
+
+ // if it failed with an exception we already logged the details
+ if (!failed)
+ {
+ PythonBindings::PythonToCppException e;
+ e.LogThrowMessage();
+ }
+
+ {
+ CPyThreadState releaseGil;
+ CSingleLock gc(g_graphicsContext);
+
+ CGUIDialogKaiToast *pDlgToast = (CGUIDialogKaiToast*)g_windowManager.GetWindow(WINDOW_DIALOG_KAI_TOAST);
+ if (pDlgToast != NULL)
+ {
+ CStdString desc;
+ CStdString script;
+ if (m_addon.get() != NULL)
+ script = m_addon->Name();
+ else
+ {
+ CStdString path;
+ URIUtils::Split(m_source, path, script);
+ if (script.Equals("default.py"))
+ {
+ CStdString path2;
+ URIUtils::RemoveSlashAtEnd(path);
+ URIUtils::Split(path, path2, script);
+ }
+ }
+
+ desc.Format(g_localizeStrings.Get(2100), script);
+ pDlgToast->QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(257), desc);
+ }
+ }
+ }
+
+ // no need to do anything else because the script has already stopped
+ if (failed)
+ return true;
+
+ PyObject *m = PyImport_AddModule((char*)"xbmc");
+ if (m == NULL || PyObject_SetAttrString(m, (char*)"abortRequested", PyBool_FromLong(1)))
+ CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): failed to set abortRequested", GetId(), m_source);
+
+ // make sure all sub threads have finished
+ for (PyThreadState* s = state->interp->tstate_head, *old = NULL; s;)
+ {
+ if (s == state)
+ {
+ s = s->next;
+ continue;
+ }
+ if (old != s)
+ {
+ CLog::Log(LOGINFO, "CPythonInvoker(%d, %s): waiting on thread %"PRIu64, GetId(), m_source, (uint64_t)s->thread_id);
+ old = s;
+ }
+
+ CPyThreadState pyState;
+ Sleep(100);
+ pyState.Restore();
+
+ s = state->interp->tstate_head;
+ }
+
+ // pending calls must be cleared out
+ XBMCAddon::RetardedAsynchCallbackHandler::clearPendingCalls(state);
+
+ PyThreadState_Swap(NULL);
+ PyEval_ReleaseLock();
+
+ // set stopped event - this allows ::stop to run and kill remaining threads
+ // this event has to be fired without holding m_critical
+ // also the GIL (PyEval_AcquireLock) must not be held
+ // if not obeyed there is still no deadlock because ::stop waits with timeout (smart one!)
+ m_stoppedEvent.Set();
+
+ { CSingleLock lock(m_critical);
+ m_threadState = NULL;
+ }
+
+ PyEval_AcquireLock();
+ PyThreadState_Swap(state);
+
+ g_pythonParser.DeInitializeInterpreter();
+
+ // run the gc before finishing
+ //
+ // if the script exited by throwing a SystemExit excepton then going back
+ // into the interpreter causes this python bug to get hit:
+ // http://bugs.python.org/issue10582
+ // and that causes major failures. So we are not going to go back in
+ // to run the GC if that's the case.
+ if (!m_stop && languageHook->HasRegisteredAddonClasses() && !systemExitThrown &&
+ PyRun_SimpleString(GC_SCRIPT) == -1)
+ CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): failed to run the gc to clean up after running prior to shutting down the Interpreter", GetId(), m_source);
+
+ Py_EndInterpreter(state);
+
+ // If we still have objects left around, produce an error message detailing what's been left behind
+ if (languageHook->HasRegisteredAddonClasses())
+ CLog::Log(LOGWARNING, "CPythonInvoker(%d, %s): the python script \"%s\" has left several "
+ "classes in memory that we couldn't clean up. The classes include: %s",
+ GetId(), m_source, m_source, getListOfAddonClassesAsString(languageHook).c_str());
+
+ // unregister the language hook
+ languageHook->UnregisterMe();
+
+ PyEval_ReleaseLock();
+
+ return true;
+}
+
+bool CPythonInvoker::stop(bool abort)
+{
+ CSingleLock lock(m_critical);
+ m_stop = true;
+
+ if (!IsRunning())
+ return false;
+
+ setState(InvokerStateStopping);
+
+ if (m_threadState != NULL)
+ {
+ PyEval_AcquireLock();
+ PyThreadState* old = PyThreadState_Swap((PyThreadState*)m_threadState);
+
+ //tell xbmc.Monitor to call onAbortRequested()
+ if (m_addon != NULL)
+ g_pythonParser.OnAbortRequested(m_addon->ID());
+
+ PyObject *m;
+ m = PyImport_AddModule((char*)"xbmc");
+ if (m == NULL || PyObject_SetAttrString(m, (char*)"abortRequested", PyBool_FromLong(1)))
+ CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): failed to set abortRequested", GetId(), m_source);
+
+ PyThreadState_Swap(old);
+ old = NULL;
+ PyEval_ReleaseLock();
+
+ XbmcThreads::EndTime timeout(PYTHON_SCRIPT_TIMEOUT);
+ while (!m_stoppedEvent.WaitMSec(15))
+ {
+ if (timeout.IsTimePast())
+ {
+ CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): script didn't stop in %d seconds - let's kill it", GetId(), m_source, PYTHON_SCRIPT_TIMEOUT / 1000);
+ break;
+ }
+
+ // We can't empty-spin in the main thread and expect scripts to be able to
+ // dismantle themselves. Python dialogs aren't normal XBMC dialogs, they rely
+ // on TMSG_GUI_PYTHON_DIALOG messages, so pump the message loop.
+ if (g_application.IsCurrentThread())
+ {
+ CSingleExit ex(g_graphicsContext);
+ CApplicationMessenger::Get().ProcessMessages();
+ }
+ }
+
+ // Useful for add-on performance metrics
+ if (!timeout.IsTimePast())
+ CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): script termination took %dms", GetId(), m_source, PYTHON_SCRIPT_TIMEOUT - timeout.MillisLeft());
+
+ // everything which didn't exit by now gets killed
+ {
+ // grabbing the PyLock while holding the m_critical is asking for a deadlock
+ CSingleExit ex2(m_critical);
+ PyEval_AcquireLock();
+ }
+
+ // Since we released the m_critical it's possible that the state is cleaned up
+ // so we need to recheck for m_threadState == NULL
+ if (m_threadState != NULL)
+ {
+ old = PyThreadState_Swap((PyThreadState*)m_threadState);
+ for (PyThreadState* state = ((PyThreadState*)m_threadState)->interp->tstate_head; state; state = state->next)
+ {
+ // Raise a SystemExit exception in python threads
+ Py_XDECREF(state->async_exc);
+ state->async_exc = PyExc_SystemExit;
+ Py_XINCREF(state->async_exc);
+ }
+
+ // If a dialog entered its doModal(), we need to wake it to see the exception
+ g_pythonParser.PulseGlobalEvent();
+ }
+
+ if (old != NULL)
+ PyThreadState_Swap(old);
+
+ lock.Leave();
+ PyEval_ReleaseLock();
+ }
+
+ return true;
+}
+
+void CPythonInvoker::onError()
+{
+ PyThreadState_Swap(NULL);
+ PyEval_ReleaseLock();
+
+ setState(InvokerStateFailed);
+ CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): abnormally terminating python thread", GetId(), m_source);
+
+ CSingleLock lock(m_critical);
+ m_threadState = NULL;
+
+ ILanguageInvoker::onError();
+}
+
+void CPythonInvoker::addPath(const std::string path)
+{
+ if (path.empty())
+ return;
+
+ if (!m_pythonPath.empty())
+ m_pythonPath += PY_PATH_SEP;
+
+#if defined(TARGET_WINDOWS)
+ CStdString tmp(path);
+ g_charsetConverter.utf8ToSystem(tmp);
+ m_pythonPath += tmp;
+#else
+ m_pythonPath += path;
+#endif // defined(TARGET_WINDOWS)
+}
--- /dev/null
+#pragma once
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <string>
+
+#include "interfaces/generic/ILanguageInvoker.h"
+#include "threads/CriticalSection.h"
+#include "threads/Event.h"
+
+class CPythonInvoker : public ILanguageInvoker
+{
+public:
+ CPythonInvoker(ILanguageInvocationHandler *invocationHandler);
+ virtual ~CPythonInvoker();
+
+ virtual bool Execute(const std::string &script, const std::vector<std::string> &arguments = std::vector<std::string>());
+
+ virtual bool IsStopping() const { return m_stop || ILanguageInvoker::IsStopping(); }
+
+protected:
+ virtual bool execute(const std::string &script, const std::vector<std::string> &arguments);
+ virtual bool stop(bool abort);
+
+ virtual void onError();
+
+private:
+ void addPath(const std::string path);
+
+ char *m_source;
+ unsigned int m_argc;
+ char **m_argv;
+ std::string m_pythonPath;
+ void *m_threadState;
+ bool m_stop;
+ CEvent m_stoppedEvent;
+ CCriticalSection m_critical;
+};
+++ /dev/null
-/*
- * Copyright (C) 2005-2013 Team XBMC
- * http://www.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, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- */
-
-#if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
- #include "config.h"
-#endif
-
-// python.h should always be included first before any other includes
-#include <Python.h>
-#include <osdefs.h>
-
-#include "system.h"
-#include "filesystem/SpecialProtocol.h"
-#include "guilib/GUIWindowManager.h"
-#include "dialogs/GUIDialogKaiToast.h"
-#include "guilib/LocalizeStrings.h"
-#include "utils/log.h"
-#include "threads/SingleLock.h"
-#include "utils/URIUtils.h"
-#include "addons/AddonManager.h"
-#include "addons/Addon.h"
-#include "Application.h"
-#include "ApplicationMessenger.h"
-
-#include "XBPyThread.h"
-#include "XBPython.h"
-#include "LanguageHook.h"
-
-#include "interfaces/legacy/Exception.h"
-#include "interfaces/legacy/CallbackHandler.h"
-#include "interfaces/legacy/AddonUtils.h"
-#include "interfaces/legacy/ModuleXbmc.h"
-
-#include "interfaces/python/pythreadstate.h"
-#include "interfaces/python/swig.h"
-#include "utils/CharsetConverter.h"
-#include "PyContext.h"
-
-#ifdef TARGET_WINDOWS
-extern "C" FILE *fopen_utf8(const char *_Filename, const char *_Mode);
-#else
-#define fopen_utf8 fopen
-#endif
-
-#define PY_PATH_SEP DELIM
-
-// Time before ill-behaved scripts are terminated
-#define PYTHON_SCRIPT_TIMEOUT 5000 // ms
-
-extern "C"
-{
- int xbp_chdir(const char *dirname);
- char* dll_getenv(const char* szKey);
-}
-
-XBPyThread::XBPyThread(XBPython *pExecuter, int id) : CThread("XBPython")
-{
- CLog::Log(LOGDEBUG,"new python thread created. id=%d", id);
- m_pExecuter = pExecuter;
- m_threadState = NULL;
- m_id = id;
- m_stopping = false;
- m_argv = NULL;
- m_source = NULL;
- m_argc = 0;
- m_type = 0;
-}
-
-XBPyThread::~XBPyThread()
-{
- stop();
- g_pythonParser.PulseGlobalEvent();
- CLog::Log(LOGDEBUG,"waiting for python thread %d (%s) to stop", m_id, (m_source ? m_source : "unknown script"));
- StopThread();
- CLog::Log(LOGDEBUG,"python thread %d (%s) destructed", m_id, (m_source ? m_source : "unknown script"));
- delete [] m_source;
- if (m_argv)
- {
- for (unsigned int i = 0; i < m_argc; i++)
- delete [] m_argv[i];
- delete [] m_argv;
- }
- g_pythonParser.FinalizeScript();
-}
-
-void XBPyThread::setSource(const CStdString &src)
-{
- if (m_source)
- delete [] m_source;
-#ifdef TARGET_WINDOWS
- CStdString strsrc;
- if (m_type == 'F')
- strsrc = CSpecialProtocol::TranslatePath(src);
- else
- strsrc = src;
- g_charsetConverter.utf8ToSystem(strsrc);
- m_source = new char[strsrc.GetLength()+1];
- strcpy(m_source, strsrc);
-#else
- m_source = new char[src.GetLength()+1];
- strcpy(m_source, src);
-#endif
-}
-
-int XBPyThread::evalFile(const CStdString &src)
-{
- m_type = 'F';
- setSource(src);
- Create();
- return 0;
-}
-
-int XBPyThread::evalString(const CStdString &src)
-{
- m_type = 'S';
- setSource(src);
- Create();
- return 0;
-}
-
-int XBPyThread::setArgv(const std::vector<CStdString> &argv)
-{
- m_argc = argv.size();
- m_argv = new char*[m_argc];
- for(unsigned int i = 0; i < m_argc; i++)
- {
- m_argv[i] = new char[argv[i].GetLength()+1];
- strcpy(m_argv[i], argv[i].c_str());
- }
- return 0;
-}
-
-#define GC_SCRIPT \
- "import gc\n" \
- "gc.collect(2)\n"
-
-static const CStdString getListOfAddonClassesAsString(XBMCAddon::AddonClass::Ref<XBMCAddon::Python::LanguageHook>& languageHook)
-{
- CStdString message;
- XBMCAddon::AddonClass::Synchronize l(*(languageHook.get()));
- std::set<XBMCAddon::AddonClass*>& acs = languageHook->GetRegisteredAddonClasses();
- bool firstTime = true;
- for (std::set<XBMCAddon::AddonClass*>::iterator iter = acs.begin();
- iter != acs.end(); ++iter)
- {
- if (!firstTime) message += ",";
- else firstTime = false;
- message += (*iter)->GetClassname().c_str();
- }
-
- return message;
-}
-
-void XBPyThread::Process()
-{
- CLog::Log(LOGDEBUG,"Python thread: start processing");
-
- int m_Py_file_input = Py_file_input;
-
- // get the global lock
- PyEval_AcquireLock();
- PyThreadState* state = Py_NewInterpreter();
- if (!state)
- {
- PyEval_ReleaseLock();
- CLog::Log(LOGERROR,"Python thread: FAILED to get thread state!");
- return;
- }
- // swap in my thread state
- PyThreadState_Swap(state);
-
- XBMCAddon::AddonClass::Ref<XBMCAddon::Python::LanguageHook> languageHook(new XBMCAddon::Python::LanguageHook(state->interp));
- languageHook->RegisterMe();
-
- m_pExecuter->InitializeInterpreter(addon);
-
- CLog::Log(LOGDEBUG, "%s - The source file to load is %s", __FUNCTION__, m_source);
-
- // get path from script file name and add python path's
- // this is used for python so it will search modules from script path first
- CStdString scriptDir;
- URIUtils::GetDirectory(CSpecialProtocol::TranslatePath(m_source), scriptDir);
- URIUtils::RemoveSlashAtEnd(scriptDir);
- CStdString path = scriptDir;
-
- // add on any addon modules the user has installed
- ADDON::VECADDONS addons;
- ADDON::CAddonMgr::Get().GetAddons(ADDON::ADDON_SCRIPT_MODULE, addons);
- for (unsigned int i = 0; i < addons.size(); ++i)
-#ifdef TARGET_WINDOWS
- {
- CStdString strTmp(CSpecialProtocol::TranslatePath(addons[i]->LibPath()));
- g_charsetConverter.utf8ToSystem(strTmp);
- path += PY_PATH_SEP + strTmp;
- }
-#else
- path += PY_PATH_SEP + CSpecialProtocol::TranslatePath(addons[i]->LibPath());
-#endif
-
- // and add on whatever our default path is
- path += PY_PATH_SEP;
-
- // we want to use sys.path so it includes site-packages
- // if this fails, default to using Py_GetPath
- PyObject *sysMod(PyImport_ImportModule((char*)"sys")); // must call Py_DECREF when finished
- PyObject *sysModDict(PyModule_GetDict(sysMod)); // borrowed ref, no need to delete
- PyObject *pathObj(PyDict_GetItemString(sysModDict, "path")); // borrowed ref, no need to delete
-
- if( pathObj && PyList_Check(pathObj) )
- {
- for( int i = 0; i < PyList_Size(pathObj); i++ )
- {
- PyObject *e = PyList_GetItem(pathObj, i); // borrowed ref, no need to delete
- if( e && PyString_Check(e) )
- {
- path += PyString_AsString(e); // returns internal data, don't delete or modify
- path += PY_PATH_SEP;
- }
- }
- }
- else
- {
- path += Py_GetPath();
- }
- Py_DECREF(sysMod); // release ref to sysMod
-
- // set current directory and python's path.
- if (m_argv != NULL)
- PySys_SetArgv(m_argc, m_argv);
-
- CLog::Log(LOGDEBUG, "%s - Setting the Python path to %s", __FUNCTION__, path.c_str());
-
- PySys_SetPath((char *)path.c_str());
-
- CLog::Log(LOGDEBUG, "%s - Entering source directory %s", __FUNCTION__, scriptDir.c_str());
-
- PyObject* module = PyImport_AddModule((char*)"__main__");
- PyObject* moduleDict = PyModule_GetDict(module);
-
- // when we are done initing we store thread state so we can be aborted
- PyThreadState_Swap(NULL);
- PyEval_ReleaseLock();
-
- // we need to check if we was asked to abort before we had inited
- bool stopping = false;
- { CSingleLock lock(m_critSec);
- m_threadState = state;
- stopping = m_stopping;
- }
-
- PyEval_AcquireLock();
- PyThreadState_Swap(state);
-
- bool failed = false;
- if (!stopping)
- {
- try
- {
- if (m_type == 'F')
- {
- // run script from file
- // We need to have python open the file because on Windows the DLL that python
- // is linked against may not be the DLL that xbmc is linked against so
- // passing a FILE* to python from an fopen has the potential to crash.
- PyObject* file = PyFile_FromString((char *) CSpecialProtocol::TranslatePath(m_source).c_str(), (char*)"r");
- FILE *fp = PyFile_AsFile(file);
-
- if (fp)
- {
- PyObject *f = PyString_FromString(CSpecialProtocol::TranslatePath(m_source).c_str());
- PyDict_SetItemString(moduleDict, "__file__", f);
- if (addon.get() != NULL)
- {
- PyObject *pyaddonid = PyString_FromString(addon->ID().c_str());
- PyDict_SetItemString(moduleDict, "__xbmcaddonid__", pyaddonid);
-
- CStdString version = ADDON::GetXbmcApiVersionDependency(addon);
- PyObject *pyxbmcapiversion = PyString_FromString(version.c_str());
- PyDict_SetItemString(moduleDict, "__xbmcapiversion__", pyxbmcapiversion);
-
- CLog::Log(LOGDEBUG,"Instantiating addon using automatically obtained id of \"%s\" dependent on version %s of the xbmc.python api",addon->ID().c_str(),version.c_str());
- }
- Py_DECREF(f);
- XBMCAddon::Python::PyContext pycontext; // this is a guard class that marks this callstack as being in a python context
- PyRun_FileExFlags(fp, CSpecialProtocol::TranslatePath(m_source).c_str(), m_Py_file_input, moduleDict, moduleDict,1,NULL);
- }
- else
- CLog::Log(LOGERROR, "%s not found!", m_source);
- }
- else
- {
- //run script
- PyRun_String(m_source, m_Py_file_input, moduleDict, moduleDict);
- }
- }
- catch (const XbmcCommons::Exception& e)
- {
- e.LogThrowMessage();
- failed = true;
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "failure in %s", m_source);
- failed = true;
- }
- }
-
- bool systemExitThrown = false;
- if (!failed && !PyErr_Occurred())
- CLog::Log(LOGINFO, "Scriptresult: Success");
- else if (PyErr_ExceptionMatches(PyExc_SystemExit))
- {
- systemExitThrown = true;
- CLog::Log(LOGINFO, "Scriptresult: Aborted");
- }
- else
- {
- // if it failed with an exception we already logged the details
- if (!failed)
- {
- PythonBindings::PythonToCppException e;
- e.LogThrowMessage();
- }
-
- {
- CPyThreadState releaseGil;
- CSingleLock gc(g_graphicsContext);
-
- CGUIDialogKaiToast *pDlgToast = (CGUIDialogKaiToast*)g_windowManager.GetWindow(WINDOW_DIALOG_KAI_TOAST);
- if (pDlgToast)
- {
- CStdString desc;
- CStdString script;
- if (addon.get() != NULL)
- {
- script = addon->Name();
- }
- else
- {
- CStdString path;
- URIUtils::Split(m_source, path, script);
- if (script.Equals("default.py"))
- {
- CStdString path2;
- URIUtils::RemoveSlashAtEnd(path);
- URIUtils::Split(path, path2, script);
- }
- }
-
- desc.Format(g_localizeStrings.Get(2100), script);
- pDlgToast->QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(257), desc);
- }
- }
- }
-
- // no need to do anything else because the script has already stopped
- if (failed)
- return;
-
- PyObject *m = PyImport_AddModule((char*)"xbmc");
- if(!m || PyObject_SetAttrString(m, (char*)"abortRequested", PyBool_FromLong(1)))
- CLog::Log(LOGERROR, "Scriptresult: failed to set abortRequested");
-
- // make sure all sub threads have finished
- for(PyThreadState* s = state->interp->tstate_head, *old = NULL; s;)
- {
- if(s == state)
- {
- s = s->next;
- continue;
- }
- if(old != s)
- {
- CLog::Log(LOGINFO, "Scriptresult: Waiting on thread %"PRIu64, (uint64_t)s->thread_id);
- old = s;
- }
-
- CPyThreadState pyState;
- Sleep(100);
- pyState.Restore();
-
- s = state->interp->tstate_head;
- }
-
- // pending calls must be cleared out
- XBMCAddon::RetardedAsynchCallbackHandler::clearPendingCalls(state);
-
- PyThreadState_Swap(NULL);
- PyEval_ReleaseLock();
-
- //set stopped event - this allows ::stop to run and kill remaining threads
- //this event has to be fired without holding m_critSec
- //
- //Also the GIL (PyEval_AcquireLock) must not be held
- //if not obeyed there is still no deadlock because ::stop waits with timeout (smart one!)
- stoppedEvent.Set();
-
- { CSingleLock lock(m_critSec);
- m_threadState = NULL;
- }
-
- PyEval_AcquireLock();
- PyThreadState_Swap(state);
-
- m_pExecuter->DeInitializeInterpreter();
-
- // run the gc before finishing
- //
- // if the script exited by throwing a SystemExit excepton then going back
- // into the interpreter causes this python bug to get hit:
- // http://bugs.python.org/issue10582
- // and that causes major failures. So we are not going to go back in
- // to run the GC if that's the case.
- if (!m_stopping && languageHook->HasRegisteredAddonClasses() && !systemExitThrown &&
- PyRun_SimpleString(GC_SCRIPT) == -1)
- CLog::Log(LOGERROR,"Failed to run the gc to clean up after running prior to shutting down the Interpreter %s",m_source);
-
- Py_EndInterpreter(state);
-
- // If we still have objects left around, produce an error message detailing what's been left behind
- if (languageHook->HasRegisteredAddonClasses())
- CLog::Log(LOGWARNING, "The python script \"%s\" has left several "
- "classes in memory that we couldn't clean up. The classes include: %s",
- m_source, getListOfAddonClassesAsString(languageHook).c_str());
-
- // unregister the language hook
- languageHook->UnregisterMe();
-
- PyEval_ReleaseLock();
-
-}
-
-void XBPyThread::OnExit()
-{
- m_pExecuter->setDone(m_id);
-}
-
-void XBPyThread::OnException()
-{
- PyThreadState_Swap(NULL);
- PyEval_ReleaseLock();
-
- CSingleLock lock(m_critSec);
- m_threadState = NULL;
- CLog::Log(LOGERROR,"%s, abnormally terminating python thread", __FUNCTION__);
- m_pExecuter->setDone(m_id);
-}
-
-bool XBPyThread::isStopping() {
- return m_stopping;
-}
-
-void XBPyThread::stop()
-{
- CSingleLock lock(m_critSec);
- if(m_stopping)
- return;
-
- m_stopping = true;
-
- if (m_threadState)
- {
- PyEval_AcquireLock();
- PyThreadState* old = PyThreadState_Swap((PyThreadState*)m_threadState);
-
- //tell xbmc.Monitor to call onAbortRequested()
- if (addon)
- g_pythonParser.OnAbortRequested(addon->ID());
-
- PyObject *m;
- m = PyImport_AddModule((char*)"xbmc");
- if(!m || PyObject_SetAttrString(m, (char*)"abortRequested", PyBool_FromLong(1)))
- CLog::Log(LOGERROR, "XBPyThread::stop - failed to set abortRequested");
-
- PyThreadState_Swap(old);
- old = NULL;
- PyEval_ReleaseLock();
-
- XbmcThreads::EndTime timeout(PYTHON_SCRIPT_TIMEOUT);
- while (!stoppedEvent.WaitMSec(15))
- {
- if (timeout.IsTimePast())
- {
- CLog::Log(LOGERROR, "XBPyThread::stop - script %s didn't stop in %d seconds - let's kill it", m_source, PYTHON_SCRIPT_TIMEOUT / 1000);
- break;
- }
- // We can't empty-spin in the main thread and expect scripts to be able to
- // dismantle themselves. Python dialogs aren't normal XBMC dialogs, they rely
- // on TMSG_GUI_PYTHON_DIALOG messages, so pump the message loop.
- if (g_application.IsCurrentThread())
- {
- CSingleExit ex(g_graphicsContext);
- CApplicationMessenger::Get().ProcessMessages();
- }
- }
- // Useful for add-on performance metrics
- if (!timeout.IsTimePast())
- CLog::Log(LOGDEBUG, "XBPyThread::stop - script termination took %dms", PYTHON_SCRIPT_TIMEOUT - timeout.MillisLeft());
-
- //everything which didn't exit by now gets killed
- {
- // grabbing the PyLock while holding the m_critSec is asking for a deadlock
- CSingleExit ex2(m_critSec);
- PyEval_AcquireLock();
- }
-
- // Since we released the m_critSec it's possible that the state is cleaned up
- // so we need to recheck for m_threadState == NULL
- if (m_threadState)
- {
- old = PyThreadState_Swap((PyThreadState*)m_threadState);
- for(PyThreadState* state = ((PyThreadState*)m_threadState)->interp->tstate_head; state; state = state->next)
- {
- // Raise a SystemExit exception in python threads
- Py_XDECREF(state->async_exc);
- state->async_exc = PyExc_SystemExit;
- Py_XINCREF(state->async_exc);
- }
-
- // If a dialog entered its doModal(), we need to wake it to see the exception
- g_pythonParser.PulseGlobalEvent();
-
- }
-
- if (old != NULL)
- PyThreadState_Swap(old);
-
- lock.Leave();
- PyEval_ReleaseLock();
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2005-2013 Team XBMC
- * http://www.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, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- */
-
-#ifndef XBPYTHREAD_H_
-#define XBPYTHREAD_H_
-
-#include "threads/Thread.h"
-#include "threads/Event.h"
-#include "threads/CriticalSection.h"
-#include "addons/IAddon.h"
-
-class XBPython;
-
-class XBPyThread : public CThread
-{
-public:
- XBPyThread(XBPython *pExecuter, int id);
- virtual ~XBPyThread();
- int evalFile(const CStdString &src);
- int evalString(const CStdString &src);
- int setArgv(const std::vector<CStdString> &argv);
- bool isStopping();
- void stop();
-
- void setAddon(ADDON::AddonPtr _addon) { addon = _addon; }
-
-protected:
- CCriticalSection m_critSec;
- XBPython *m_pExecuter;
- CEvent stoppedEvent;
- void *m_threadState;
-
- char m_type;
- char *m_source;
- char **m_argv;
- unsigned int m_argc;
- bool m_stopping;
- int m_id;
- ADDON::AddonPtr addon;
-
- void setSource(const CStdString &src);
-
- virtual void Process();
- virtual void OnExit();
- virtual void OnException();
-};
-
-#endif // XBPYTHREAD_H_
#include "XBPython.h"
#include "filesystem/File.h"
#include "filesystem/SpecialProtocol.h"
-#include "guilib/GraphicContext.h"
#include "profiles/ProfilesManager.h"
#include "utils/log.h"
#include "pythreadstate.h"
#include "interfaces/legacy/Monitor.h"
#include "interfaces/legacy/AddonUtils.h"
+#include "interfaces/python/PythonInvoker.h"
using namespace ANNOUNCEMENT;
XBPython::XBPython()
{
m_bInitialized = false;
- m_bLogin = false;
- m_nextid = 0;
m_mainThreadState = NULL;
m_ThreadId = CThread::GetCurrentThreadId();
m_iDllScriptCounter = 0;
#define CHECK_FOR_ENTRY(l,v) \
(l.hadSomethingRemoved ? (std::find(l.begin(),l.end(),v) != l.end()) : true)
-// message all registered callbacks that xbmc stopped playing
-void XBPython::OnPlayBackEnded()
-{
- TRACE;
- LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
- for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
- if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
- ((IPlayerCallback*)(*it))->OnPlayBackEnded();
-}
-
void XBPython::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
{
if (flag & VideoLibrary)
else if (flag & GUI)
{
if (strcmp(message, "OnScreensaverDeactivated") == 0)
- OnScreensaverDeactivated();
+ OnScreensaverDeactivated();
else if (strcmp(message, "OnScreensaverActivated") == 0)
OnScreensaverActivated();
}
TRACE;
LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
((IPlayerCallback*)(*it))->OnPlayBackStarted();
+ }
}
// message all registered callbacks that we paused playing
TRACE;
LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
((IPlayerCallback*)(*it))->OnPlayBackPaused();
+ }
}
// message all registered callbacks that we resumed playing
TRACE;
LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
((IPlayerCallback*)(*it))->OnPlayBackResumed();
+ }
+}
+
+// message all registered callbacks that xbmc stopped playing
+void XBPython::OnPlayBackEnded()
+{
+ TRACE;
+ LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
+ for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
+ if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
+ ((IPlayerCallback*)(*it))->OnPlayBackEnded();
+ }
}
// message all registered callbacks that user stopped playing
TRACE;
LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
((IPlayerCallback*)(*it))->OnPlayBackStopped();
+ }
}
// message all registered callbacks that playback speed changed (FF/RW)
TRACE;
LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
((IPlayerCallback*)(*it))->OnPlayBackSpeedChanged(iSpeed);
+ }
}
// message all registered callbacks that player is seeking
TRACE;
LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
((IPlayerCallback*)(*it))->OnPlayBackSeek(iTime, seekOffset);
+ }
}
// message all registered callbacks that player chapter seeked
TRACE;
LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
((IPlayerCallback*)(*it))->OnPlayBackSeekChapter(iChapter);
+ }
}
// message all registered callbacks that next item has been queued
TRACE;
LOCK_AND_COPY(std::vector<PVOID>,tmp,m_vecPlayerCallbackList);
for (PlayerCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecPlayerCallbackList,(*it)))
((IPlayerCallback*)(*it))->OnQueueNextItem();
+ }
}
void XBPython::RegisterPythonPlayerCallBack(IPlayerCallback* pCallback)
TRACE;
LOCK_AND_COPY(std::vector<XBMCAddon::xbmc::Monitor*>,tmp,m_vecMonitorCallbackList);
for (MonitorCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecMonitorCallbackList,(*it)) && ((*it)->GetId() == ID))
(*it)->OnSettingsChanged();
-}
+ }
+}
void XBPython::OnScreensaverActivated()
{
TRACE;
LOCK_AND_COPY(std::vector<XBMCAddon::xbmc::Monitor*>,tmp,m_vecMonitorCallbackList);
for (MonitorCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecMonitorCallbackList,(*it)))
(*it)->OnScreensaverActivated();
-}
+ }
+}
void XBPython::OnScreensaverDeactivated()
{
TRACE;
LOCK_AND_COPY(std::vector<XBMCAddon::xbmc::Monitor*>,tmp,m_vecMonitorCallbackList);
for (MonitorCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecMonitorCallbackList,(*it)))
(*it)->OnScreensaverDeactivated();
-}
+ }
+}
void XBPython::OnDatabaseUpdated(const std::string &database)
{
TRACE;
LOCK_AND_COPY(std::vector<XBMCAddon::xbmc::Monitor*>,tmp,m_vecMonitorCallbackList);
for (MonitorCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecMonitorCallbackList,(*it)))
(*it)->OnDatabaseUpdated(database);
-}
+ }
+}
void XBPython::OnDatabaseScanStarted(const std::string &database)
{
TRACE;
LOCK_AND_COPY(std::vector<XBMCAddon::xbmc::Monitor*>,tmp,m_vecMonitorCallbackList);
for (MonitorCallbackList::iterator it = tmp.begin(); (it != tmp.end()); ++it)
+ {
if (CHECK_FOR_ENTRY(m_vecMonitorCallbackList,(*it)))
(*it)->OnDatabaseScanStarted(database);
+ }
}
void XBPython::OnAbortRequested(const CStdString &ID)
else if ((*it)->GetId() == ID)
(*it)->OnAbortRequested();
}
- }
-}
+ }
+}
/**
* Check for file and print an error if needed
CSingleLock lock(m_critSection);
- CLog::Log(LOGDEBUG,"%s, adding %s (%p)", __FUNCTION__, pLib->GetName(), (void*)pLib);
+ CLog::Log(LOGDEBUG, "%s, adding %s (%p)", __FUNCTION__, pLib->GetName(), (void*)pLib);
m_extensions.push_back(pLib);
}
return;
CSingleLock lock(m_critSection);
- CLog::Log(LOGDEBUG,"%s, removing %s (0x%p)", __FUNCTION__, pLib->GetName(), (void *)pLib);
+ CLog::Log(LOGDEBUG, "%s, removing %s (0x%p)", __FUNCTION__, pLib->GetName(), (void *)pLib);
PythonExtensionLibraries::iterator iter = m_extensions.begin();
while (iter != m_extensions.end())
{
void XBPython::UnloadExtensionLibs()
{
- CLog::Log(LOGDEBUG,"%s, clearing python extension libraries", __FUNCTION__);
+ CLog::Log(LOGDEBUG, "%s, clearing python extension libraries", __FUNCTION__);
CSingleLock lock(m_critSection);
PythonExtensionLibraries::iterator iter = m_extensions.begin();
while (iter != m_extensions.end())
"os.chdir_orignal = os.chdir\n" \
"os.chdir = chdir_xbmc\n" \
""
-
+
#define RUNSCRIPT_POSTSCRIPT \
"print '-->Python Interpreter Initialized<--'\n" \
""
// redirecting default output to debug console
if (PyRun_SimpleString(runscript) == -1)
- {
CLog::Log(LOGFATAL, "Python Initialize Error");
- }
}
void XBPython::DeInitializeInterpreter()
/**
* Should be called before executing a script
*/
-void XBPython::Initialize()
+bool XBPython::InitializeEngine()
{
TRACE;
- CLog::Log(LOGINFO, "initializing python engine. ");
+ CLog::Log(LOGINFO, "initializing python engine.");
CSingleLock lock(m_critSection);
m_iDllScriptCounter++;
if (!m_bInitialized)
{
CLog::Log(LOGERROR, "Python: Missing files, unable to execute script");
Finalize();
- return;
+ return false;
}
#endif
m_bInitialized = true;
}
+
+ return m_bInitialized;
}
/**
m_endtime = XbmcThreads::SystemClockMillis();
}
-
// Always called with the lock held on m_critSection
void XBPython::Finalize()
{
}
}
-void XBPython::FreeResources()
+void XBPython::Uninitialize()
{
LOCK_AND_COPY(std::vector<PyElem>,tmpvec,m_vecPyList);
m_vecPyList.clear();
void XBPython::Process()
{
- if (m_bLogin)
- {
- m_bLogin = false;
-
- // autoexec.py - profile
- CStdString strAutoExecPy = CSpecialProtocol::TranslatePath("special://profile/autoexec.py");
-
- if ( XFILE::CFile::Exists(strAutoExecPy) )
- evalFile(strAutoExecPy,ADDON::AddonPtr());
- else
- CLog::Log(LOGDEBUG, "%s - no profile autoexec.py (%s) found, skipping", __FUNCTION__, strAutoExecPy.c_str());
- }
-
- CSingleLock lock(m_vecPyList);
-
if (m_bInitialized)
{
PyList tmpvec;
+ CSingleLock lock(m_vecPyList);
for (PyList::iterator it = m_vecPyList.begin(); it != m_vecPyList.end();)
{
if (it->bDone)
}
}
-bool XBPython::StopScript(const CStdString &path)
+void XBPython::OnScriptStarted(ILanguageInvoker *invoker)
{
- TRACE;
- int id = getScriptId(path);
- if (id != -1)
- {
- /* if we are here we already know that this script is running.
- * But we will check it again to be sure :)
- */
- if (isRunning(id))
- {
- stopScript(id);
- return true;
- }
- }
- return false;
-}
-
-int XBPython::evalFile(const CStdString &src, ADDON::AddonPtr addon)
-{
- std::vector<CStdString> argv;
- return evalFile(src, argv, addon);
-}
-// execute script, returns -1 if script doesn't exist
-int XBPython::evalFile(const CStdString &src, const std::vector<CStdString> &argv, ADDON::AddonPtr addon)
-{
- CSingleExit ex(g_graphicsContext);
- // return if file doesn't exist
- if (!XFILE::CFile::Exists(src))
- {
- CLog::Log(LOGERROR, "Python script \"%s\" does not exist", CSpecialProtocol::TranslatePath(src).c_str());
- return -1;
- }
-
- // check if locked
- if (CProfilesManager::Get().GetCurrentProfile().programsLocked() && !g_passwordManager.IsMasterLockUnlocked(true))
- return -1;
-
- CSingleLock lock(m_vecPyList);
- Initialize();
+ if (invoker == NULL)
+ return;
- if (!m_bInitialized) return -1;
+ if (!m_bInitialized)
+ return;
- m_nextid++;
- boost::shared_ptr<XBPyThread> pyThread = boost::shared_ptr<XBPyThread>(new XBPyThread(this, m_nextid));
- pyThread->setArgv(argv);
- pyThread->setAddon(addon);
- pyThread->evalFile(src);
PyElem inf;
- inf.id = m_nextid;
+ inf.id = invoker->GetId();
inf.bDone = false;
- inf.strFile = src;
- inf.pyThread = pyThread;
-
+ inf.pyThread = static_cast<CPythonInvoker*>(invoker);
+ CSingleLock lock(m_vecPyList);
m_vecPyList.push_back(inf);
-
- return m_nextid;
}
-void XBPython::setDone(int id)
+void XBPython::OnScriptEnded(ILanguageInvoker *invoker)
{
CSingleLock lock(m_vecPyList);
PyList::iterator it = m_vecPyList.begin();
while (it != m_vecPyList.end())
{
- if (it->id == id)
+ if (it->id == invoker->GetId())
{
- if (it->pyThread->isStopping())
+ if (it->pyThread->IsStopping())
CLog::Log(LOGINFO, "Python script interrupted by user");
else
CLog::Log(LOGINFO, "Python script stopped");
}
}
-void XBPython::stopScript(int id)
-{
- CSingleExit ex(g_graphicsContext);
- CSingleLock lock(m_vecPyList);
- PyList::iterator it = m_vecPyList.begin();
- while (it != m_vecPyList.end())
- {
- if (it->id == id) {
- CLog::Log(LOGINFO, "Stopping script with id: %i", id);
- it->pyThread->stop();
- return;
- }
- ++it;
- }
-}
-
-void* XBPython::getMainThreadState()
+ILanguageInvoker* XBPython::CreateInvoker()
{
- CSingleLock lock(m_critSection);
- return m_mainThreadState;
-}
-
-int XBPython::ScriptsSize()
-{
- CSingleLock lock(m_vecPyList);
- return m_vecPyList.size();
-}
-
-const char* XBPython::getFileName(int scriptId)
-{
- const char* cFileName = NULL;
-
- CSingleLock lock(m_vecPyList);
- PyList::iterator it = m_vecPyList.begin();
- while (it != m_vecPyList.end())
- {
- if (it->id == scriptId)
- cFileName = it->strFile.c_str();
- ++it;
- }
-
- return cFileName;
-}
-
-int XBPython::getScriptId(const CStdString &strFile)
-{
- int iId = -1;
-
- CSingleLock lock(m_vecPyList);
-
- PyList::iterator it = m_vecPyList.begin();
- while (it != m_vecPyList.end())
- {
- if (it->strFile == strFile)
- iId = it->id;
- ++it;
- }
-
- return iId;
-}
-
-bool XBPython::isRunning(int scriptId)
-{
- CSingleLock lock(m_vecPyList);
-
- for(PyList::iterator it = m_vecPyList.begin(); it != m_vecPyList.end(); ++it)
- {
- if (it->id == scriptId)
- {
- if(it->bDone)
- return false;
- else
- return true;
- }
- }
- return false;
-}
-
-bool XBPython::isStopping(int scriptId)
-{
- bool bStopping = false;
-
- CSingleLock lock(m_vecPyList);
- PyList::iterator it = m_vecPyList.begin();
- while (it != m_vecPyList.end())
- {
- if (it->id == scriptId)
- bStopping = it->pyThread->isStopping();
- ++it;
- }
-
- return bStopping;
-}
-
-int XBPython::GetPythonScriptId(int scriptPosition)
-{
- CSingleLock lock(m_vecPyList);
- return (int)m_vecPyList[scriptPosition].id;
+ return new CPythonInvoker(this);
}
void XBPython::PulseGlobalEvent()
CEvent* ret = eventGroup.wait(milliseconds);
if (ret)
m_globalEvent.Reset();
- return ret == NULL ? false : true;
-}
-
-// execute script, returns -1 if script doesn't exist
-int XBPython::evalString(const CStdString &src, const std::vector<CStdString> &argv)
-{
- CLog::Log(LOGDEBUG, "XBPython::evalString (python)");
- CSingleLock lock(m_critSection);
-
- Initialize();
-
- if (!m_bInitialized)
- {
- CLog::Log(LOGERROR, "XBPython::evalString, python not initialized (python)");
- return -1;
- }
-
- // Previous implementation would create a new thread for every script
- m_nextid++;
- boost::shared_ptr<XBPyThread> pyThread = boost::shared_ptr<XBPyThread>(new XBPyThread(this, m_nextid));
- pyThread->setArgv(argv);
- pyThread->evalString(src);
-
- PyElem inf;
- inf.id = m_nextid;
- inf.bDone = false;
- inf.strFile = "<string>";
- inf.pyThread = pyThread;
-
- lock.Leave();
- CSingleLock l2(m_vecPyList);
-
- m_vecPyList.push_back(inf);
-
- return m_nextid;
+ return ret != NULL;
}
*
*/
-#include "XBPyThread.h"
#include "cores/IPlayerCallback.h"
#include "threads/CriticalSection.h"
+#include "threads/Event.h"
+#include "threads/Thread.h"
#include "interfaces/IAnnouncer.h"
+#include "interfaces/generic/ILanguageInvocationHandler.h"
#include "addons/IAddon.h"
#include <boost/shared_ptr.hpp>
#include <vector>
+class CPythonInvoker;
+
typedef struct {
int id;
bool bDone;
- std::string strFile;
- boost::shared_ptr<XBPyThread> pyThread;
+ CPythonInvoker* pyThread;
}PyElem;
class LibraryLoader;
}
}
-template <class T> struct LockableType : public T, public CCriticalSection
+template <class T> struct LockableType : public T, public CCriticalSection
{ bool hadSomethingRemoved; };
typedef LockableType<std::vector<void*> > PlayerCallbackList;
typedef LockableType<std::vector<PyElem> > PyList;
typedef std::vector<LibraryLoader*> PythonExtensionLibraries;
-class XBPython :
+class XBPython :
public IPlayerCallback,
- public ANNOUNCEMENT::IAnnouncer
+ public ANNOUNCEMENT::IAnnouncer,
+ public ILanguageInvocationHandler
{
- void Finalize();
public:
XBPython();
virtual ~XBPython();
void OnDatabaseUpdated(const std::string &database);
void OnDatabaseScanStarted(const std::string &database);
void OnAbortRequested(const CStdString &ID="");
- void Initialize();
+
+ virtual void Process();
+ virtual void Uninitialize();
+ virtual void OnScriptStarted(ILanguageInvoker *invoker);
+ virtual void OnScriptEnded(ILanguageInvoker *invoker);
+ virtual ILanguageInvoker* CreateInvoker();
+
+ bool InitializeEngine();
void FinalizeScript();
- void FreeResources();
- void Process();
void PulseGlobalEvent();
bool WaitForEvent(CEvent& hEvent, unsigned int milliseconds);
- int ScriptsSize();
- int GetPythonScriptId(int scriptPosition);
- int evalFile(const CStdString &src, ADDON::AddonPtr addon);
- int evalFile(const CStdString &src, const std::vector<CStdString> &argv, ADDON::AddonPtr addon);
- int evalString(const CStdString &src, const std::vector<CStdString> &argv);
-
- bool isRunning(int scriptId);
- bool isStopping(int scriptId);
- void setDone(int id);
-
- /*! \brief Stop a script if it's running
- \param path path to the script
- \return true if the script was running and is now stopped, false otherwise
- */
- bool StopScript(const CStdString &path);
-
// inject xbmc stuff into the interpreter.
// should be called for every new interpreter
void InitializeInterpreter(ADDON::AddonPtr addon);
void UnregisterExtensionLib(LibraryLoader *pLib);
void UnloadExtensionLibs();
- //only should be called from thread which is running the script
- void stopScript(int scriptId);
-
- // returns NULL if script doesn't exist or if script doesn't have a filename
- const char* getFileName(int scriptId);
-
- // returns -1 if no scripts exist with specified filename
- int getScriptId(const CStdString &strFile);
-
- void* getMainThreadState();
-
- bool m_bLogin;
private:
+ void Finalize();
+
CCriticalSection m_critSection;
bool FileExist(const char* strFile);
- int m_nextid;
void* m_mainThreadState;
ThreadIdentifier m_ThreadId;
bool m_bInitialized;
#include "URIUtils.h"
#include "log.h"
#include "addons/AddonManager.h"
-#ifdef HAS_PYTHON
-#include "interfaces/python/XBPython.h"
-#endif
+#include "interfaces/generic/ScriptInvocationManager.h"
#include "CharsetConverter.h"
#include "addons/GUIDialogAddonSettings.h"
return false;
// initialize our sys.argv variables
- std::vector<CStdString> argv;
+ std::vector<std::string> argv;
argv.push_back(addon->LibPath());
CStdString strSetting;
strSetting.Format("%i", m_location);
argv.push_back(strSetting);
-#ifdef HAS_PYTHON
// Download our weather
CLog::Log(LOGINFO, "WEATHER: Downloading weather");
// call our script, passing the areacode
- if (g_pythonParser.evalFile(argv[0], argv,addon))
+ int scriptId = -1;
+ if ((scriptId = CScriptInvocationManager::Get().Execute(argv[0], addon, argv)) >= 0)
{
while (true)
{
- if (!g_pythonParser.isRunning(g_pythonParser.getScriptId(addon->LibPath().c_str())))
+ if (!CScriptInvocationManager::Get().IsRunning(scriptId))
break;
Sleep(100);
}
g_windowManager.SendThreadMessage(msg);
}
else
-#endif
CLog::Log(LOGERROR, "WEATHER: Weather download failed!");
return true;
#include "utils/FileUtils.h"
#include "guilib/GUIEditControl.h"
#include "guilib/GUIKeyboardFactory.h"
-#ifdef HAS_PYTHON
-#include "interfaces/python/XBPython.h"
-#endif
#include "interfaces/Builtins.h"
+#include "interfaces/generic/ScriptInvocationManager.h"
#include "dialogs/GUIDialogKaiToast.h"
#include "dialogs/GUIDialogMediaFilter.h"
#include "filesystem/SmartPlaylistDirectory.h"
AddonPtr addon;
if (CAddonMgr::Get().GetAddon(url.GetHostName(), addon, ADDON_SCRIPT))
{
-#ifdef HAS_PYTHON
- if (!g_pythonParser.StopScript(addon->LibPath()))
- g_pythonParser.evalFile(addon->LibPath(),addon);
-#endif
+ if (!CScriptInvocationManager::Get().Stop(addon->LibPath()))
+ CScriptInvocationManager::Get().Execute(addon->LibPath(), addon);
return true;
}
}
#include "dialogs/GUIDialogMediaSource.h"
#include "GUIPassword.h"
#include "GUIUserMessages.h"
-#ifdef HAS_PYTHON
-#include "interfaces/python/XBPython.h"
-#endif
+#include "interfaces/generic/ScriptInvocationManager.h"
#include "pictures/GUIWindowSlideShow.h"
#include "playlists/PlayListFactory.h"
#include "network/Network.h"
#ifdef HAS_PYTHON
if (pItem->IsPythonScript())
{
- g_pythonParser.evalFile(pItem->GetPath().c_str(),ADDON::AddonPtr());
+ CScriptInvocationManager::Get().Execute(pItem->GetPath());
return ;
}
#endif
#include "profiles/windows/GUIWindowSettingsProfile.h"
#include "dialogs/GUIDialogContextMenu.h"
#include "GUIPassword.h"
-#ifdef HAS_PYTHON
-#include "interfaces/python/XBPython.h"
-#endif
#ifdef HAS_JSONRPC
#include "interfaces/json-rpc/JSONRPC.h"
#endif
ADDON::CAddonMgr::Get().ReInit();
g_weatherManager.Refresh();
-#ifdef HAS_PYTHON
- g_pythonParser.m_bLogin = true;
-#endif
+ g_application.SetLoggingIn(true);
#ifdef HAS_JSONRPC
JSONRPC::CJSONRPC::Initialize();