blob: 86abdac1ed0d6190dd902964ee1289fe0d1b4b6f (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
/*
* Copyright (C) 2005-2018 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
* See LICENSES/README.md for more information.
*/
#pragma once
#include "AddonClass.h"
#include "CallbackHandler.h"
#include "threads/Event.h"
/**
* This class is an interface that can be used to define programming language
* specific hooks.
*/
class IPlayerCallback;
namespace XBMCAddon
{
namespace xbmc
{
class Monitor;
}
class LanguageHook : public AddonClass
{
protected:
inline LanguageHook() = default;
public:
~LanguageHook() override;
/**
* If the scripting language needs special handling for calls
* that block or are delayed in any other means, this should
* be overloaded.
*
* In Python when control is passed to a native
* method that blocks, you need to allow other threads in
* Python to run by using Py_BEGIN_ALLOW_THREADS. This is
* the place to put that functionality
*/
virtual void DelayedCallOpen() { }
/**
* If the scripting language needs special handling for calls
* that block or are delayed in any other means, this should
* be overloaded.
*
* In Python when control is passed to a native
* method that blocks, you need to allow other threads in
* Python to run by using Py_BEGIN_ALLOW_THREADS. When that
* delayed method ends you need to restore the Python thread
* state using Py_END_ALLOW_THREADS. This is the place to put
* that functionality
*/
virtual void DelayedCallClose() { }
virtual void MakePendingCalls() {}
/**
* For scripting languages that need a global callback handler, this
* method should be overloaded to supply one.
*/
virtual CallbackHandler* GetCallbackHandler() { return NULL; }
/**
* This is a callback method that can be overridden to receive a callback
* when an AddonClass that has this language hook is on is being constructed.
* It is called from the constructor of AddonClass so the implementor
* cannot assume the subclasses have been built or that calling a
* virtual function on the AddonClass will work as expected.
*/
virtual void Constructing(AddonClass* beingConstructed) { }
/**
* This is a callback method that can be overridden to receive a callback
* when an AddonClass that has this language hook is on is being destructed.
* It is called from the destructor of AddonClass so the implementor
* should assume the subclasses have been torn down and that calling a
* virtual function on the AddonClass will not work as expected.
*/
virtual void Destructing(AddonClass* beingDestructed) { }
/**
* This method should be done a different way but since the only other way
* I can think to do it requires an InheritableThreadLocal C++ equivalent,
* I'm going to defer to this technique for now.
*
* Currently (for python) the scripting language has the Addon id injected
* into it as a global variable. Therefore the only way to retrieve it is
* to use scripting language specific calls. So until I figure out a
* better way to do this, this is how I need to retrieve it.
*/
virtual String GetAddonId() { return emptyString; }
virtual String GetAddonVersion() { return emptyString; }
virtual long GetInvokerId() { return -1; }
virtual void RegisterPlayerCallback(IPlayerCallback* player) = 0;
virtual void UnregisterPlayerCallback(IPlayerCallback* player) = 0;
virtual void RegisterMonitorCallback(XBMCAddon::xbmc::Monitor* player) = 0;
virtual void UnregisterMonitorCallback(XBMCAddon::xbmc::Monitor* player) = 0;
virtual bool WaitForEvent(CEvent& hEvent, unsigned int milliseconds) = 0;
static void SetLanguageHook(LanguageHook* languageHook);
static LanguageHook* GetLanguageHook();
static void ClearLanguageHook();
};
/**
* This class can be used to access the language hook's DelayedCallOpen
* and DelayedCallClose. It should be used whenever an API method
* is written such that it can block for an indefinite amount of time
* since certain scripting languages (like Python) need to do extra
* work for delayed calls (like free the python locks and handle
* callbacks).
*/
class DelayedCallGuard
{
LanguageHook* languageHook;
bool clearOnExit = false;
public:
inline explicit DelayedCallGuard(LanguageHook* languageHook_) : languageHook(languageHook_)
{ if (languageHook) languageHook->DelayedCallOpen(); }
inline DelayedCallGuard() : languageHook(LanguageHook::GetLanguageHook())
{ if (languageHook) languageHook->DelayedCallOpen(); }
inline ~DelayedCallGuard()
{
if (clearOnExit) LanguageHook::ClearLanguageHook();
if (languageHook) languageHook->DelayedCallClose();
}
inline LanguageHook* getLanguageHook() { return languageHook; }
};
class SetLanguageHookGuard
{
public:
inline explicit SetLanguageHookGuard(LanguageHook* languageHook) { LanguageHook::SetLanguageHook(languageHook); }
inline ~SetLanguageHookGuard() { LanguageHook::ClearLanguageHook(); }
};
}
|