forked from wxWidgets/Phoenix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwxpy_api.h
330 lines (257 loc) · 11.2 KB
/
wxpy_api.h
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
//--------------------------------------------------------------------------
// Name: wxpy_api.h
// Purpose: Some utility functions and such that can be used in other
// snippets of C++ code to help reduce complexity, etc. They
// are all either macros, inline functions, or functions that
// are exported from the core extension module.
//
// Author: Robin Dunn
//
// Created: 19-Nov-2010
// Copyright: (c) 2013 by Total Control Software
// Licence: wxWindows license
//--------------------------------------------------------------------------
#ifndef _WXPY_API_H
#define _WXPY_API_H
#if defined(__APPLE__)
// When it's possible that we're building universal binaries with both
// 32-bit and 64-bit architectures then these need to be undefed because
// otherwise the values set by configure could conflict with those set
// based on runtime flags in Python's headers. We also do something
// similar in wx/platform.h so it's okay to undef them now because they
// will be defined again soon.
#undef SIZEOF_VOID_P
#undef SIZEOF_LONG
#undef SIZEOF_SIZE_T
#endif
#if defined(__GNUC__)
// Turn off the warning about converting string literals to char*
// TODO: fix these the right way...
#pragma GCC diagnostic ignored "-Wwrite-strings"
#endif
#ifdef _MSC_VER
#pragma warning(disable:4800)
#pragma warning(disable:4190)
#endif
#include <wx/wx.h>
//--------------------------------------------------------------------------
// The API items that can be inline functions or macros.
// These are made available simply by #including this header file.
//--------------------------------------------------------------------------
typedef PyGILState_STATE wxPyBlock_t;
#define wxPyBlock_t_default PyGILState_UNLOCKED
typedef unsigned char byte;
typedef unsigned char* buffer;
// Convert a wxString to a Python string (actually a PyUnicode object).
// Assumes that the GIL has already been acquired.
inline PyObject* wx2PyString(const wxString& str) {
return PyUnicode_FromWideChar(str.wc_str(), str.length());
}
// Calls from Python to wxWidgets code should be wrapped in calls to these
// functions:
inline PyThreadState* wxPyBeginAllowThreads() {
PyThreadState* saved = PyEval_SaveThread(); // Like Py_BEGIN_ALLOW_THREADS;
return saved;
}
inline void wxPyEndAllowThreads(PyThreadState* saved) {
PyEval_RestoreThread(saved); // Like Py_END_ALLOW_THREADS;
}
// A macro that will help to execute simple statments wrapped in
// StartBlock/EndBlockThreads calls
#define wxPyBLOCK_THREADS(stmt) \
{ wxPyThreadBlocker _blocker; stmt; }
// Raise any exception with a string value (blocking threads)
#define wxPyErr_SetString(err, str) \
wxPyBLOCK_THREADS(PyErr_SetString(err, str))
// Raise NotImplemented exceptions
#define wxPyRaiseNotImplemented() \
wxPyBLOCK_THREADS( PyErr_SetNone(PyExc_NotImplementedError) )
#define wxPyRaiseNotImplementedMsg(msg) \
wxPyBLOCK_THREADS( PyErr_SetString(PyExc_NotImplementedError, msg) );
// A convenience macro for properly returning Py_None
//#define RETURN_NONE() { Py_INCREF(Py_None); return Py_None; }
#define RETURN_NONE() { wxPyBLOCK_THREADS(Py_INCREF(Py_None)); return Py_None; }
// Make a memory view object from a C buffer and size.
inline PyObject* wxPyMakeBuffer(void* ptr, Py_ssize_t len, bool readOnly=false) {
// GIL should already be held
Py_buffer view;
int flags = PyBUF_FORMAT|PyBUF_ND;
if (!readOnly)
flags |= PyBUF_WRITABLE;
PyBuffer_FillInfo(&view, NULL, ptr, len, readOnly ? 1:0, flags);
return PyMemoryView_FromBuffer(&view);
}
// Macros to work around differences in the Python 3 API
#if PY_MAJOR_VERSION >= 3
#define wxPyInt_Check PyLong_Check
#define wxPyInt_AsLong PyLong_AsLong
#define wxPyInt_AS_LONG PyLong_AS_LONG
#define wxPyInt_AsSsize_t PyLong_AsSsize_t
#define wxPyInt_FromLong PyLong_FromLong
#define wxPyNumber_Int PyNumber_Long
#else
#define wxPyInt_Check PyInt_Check
#define wxPyInt_AsLong PyInt_AsLong
#define wxPyInt_AS_LONG PyInt_AS_LONG
#define wxPyInt_AsLong PyInt_AsLong
#define wxPyInt_AsSsize_t PyInt_AsSsize_t
#define wxPyInt_FromLong PyInt_FromLong
#define wxPyNumber_Int PyNumber_Int
#endif
inline
Py_ssize_t wxPyUnicode_AsWideChar(PyObject* unicode, wchar_t* w, Py_ssize_t size)
{
// GIL should already be held
#if PY_MAJOR_VERSION >= 3
return PyUnicode_AsWideChar(unicode, w, size);
#else
return PyUnicode_AsWideChar((PyUnicodeObject*)unicode, w, size);
#endif
}
//--------------------------------------------------------------------------
// These are the API items whose implementation can not or should not be
// inline functions or macros. The implementations will instead be accessed
// via a structure of function pointers that is exported from the wx._core
// extension module. See wxpy_api.sip for the implementations.
//--------------------------------------------------------------------------
struct wxPyAPI {
wxString (*p_Py2wxString)(PyObject* source);
PyObject* (*p_wxPyConstructObject)(void* ptr, const wxString& className, bool setThisOwn);
wxPyBlock_t (*p_wxPyBeginBlockThreads)();
void (*p_wxPyEndBlockThreads)(wxPyBlock_t blocked);
bool (*p_wxPyWrappedPtr_Check)(PyObject* obj);
bool (*p_wxPyConvertWrappedPtr)(PyObject* obj, void **ptr, const wxString& className);
bool (*p_wxPy2int_seq_helper)(PyObject* source, int* i1, int* i2);
bool (*p_wxPy4int_seq_helper)(PyObject* source, int* i1, int* i2, int* i3, int* i4);
bool (*p_wxPyWrappedPtr_TypeCheck)(PyObject* obj, const wxString& className);
wxVariant (*p_wxVariant_in_helper)(PyObject* obj);
PyObject* (*p_wxVariant_out_helper)(const wxVariant& value);
// Always add new items here at the end.
};
inline wxPyAPI* wxPyGetAPIPtr()
{
static wxPyAPI* wxPyAPIPtr = NULL;
if (wxPyAPIPtr == NULL) {
PyGILState_STATE state = PyGILState_Ensure();
wxPyAPIPtr = (wxPyAPI*)PyCapsule_Import("wx._wxPyAPI", 0);
// uncomment if needed for debugging
//if (PyErr_Occurred()) { PyErr_Print(); }
//wxASSERT_MSG(wxPyAPIPtr != NULL, wxT("wxPyAPIPtr is NULL!!!"));
PyGILState_Release(state);
}
return wxPyAPIPtr;
}
//--------------------------------------------------------------------------
// Inline wrappers which call the functions in the API structure
// Convert a PyObject to a wxString
// Assumes that the GIL has already been acquired.
inline wxString Py2wxString(PyObject* source)
{ return wxPyGetAPIPtr()->p_Py2wxString(source); }
// Create a PyObject of the requested type from a void* and a class name.
// Assumes that the GIL has already been acquired.
inline PyObject* wxPyConstructObject(void* ptr, const wxString& className, bool setThisOwn=false)
{ return wxPyGetAPIPtr()->p_wxPyConstructObject(ptr, className, setThisOwn); }
// Check if a PyObject is a wrapped type
inline bool wxPyWrappedPtr_Check(PyObject* obj)
{ return wxPyGetAPIPtr()->p_wxPyWrappedPtr_Check(obj); }
// Check if a PyObject is a specific wrapped type (or a subclass)
inline bool wxPyWrappedPtr_TypeCheck(PyObject* obj, const wxString& className)
{ return wxPyGetAPIPtr()->p_wxPyWrappedPtr_TypeCheck(obj, className); }
// Convert a wrapped SIP object to its C++ pointer, ensuring that it is of the expected type
inline bool wxPyConvertWrappedPtr(PyObject* obj, void **ptr, const wxString& className)
{ return wxPyGetAPIPtr()->p_wxPyConvertWrappedPtr(obj, ptr, className); }
// Calls from wxWindows back to Python code, or even any PyObject
// manipulations, PyDECREF's and etc. should be wrapped in calls to these functions:
inline wxPyBlock_t wxPyBeginBlockThreads()
{ return wxPyGetAPIPtr()->p_wxPyBeginBlockThreads(); }
inline void wxPyEndBlockThreads(wxPyBlock_t blocked)
{ wxPyGetAPIPtr()->p_wxPyEndBlockThreads(blocked); }
// A helper for converting a 2 element sequence to a pair of integers
inline bool wxPy2int_seq_helper(PyObject* source, int* i1, int* i2)
{ return wxPyGetAPIPtr()->p_wxPy2int_seq_helper(source, i1, i2); }
// A helper for converting a 4 element sequence to a set of integers
inline bool wxPy4int_seq_helper(PyObject* source, int* i1, int* i2, int* i3, int* i4)
{ return wxPyGetAPIPtr()->p_wxPy4int_seq_helper(source, i1, i2, i3, i4); }
// Convert a PyObject to a wxVariant
inline wxVariant wxVariant_in_helper(PyObject* obj)
{ return wxPyGetAPIPtr()->p_wxVariant_in_helper(obj); }
// Convert a wxVariant to a PyObject
inline PyObject* wxVariant_out_helper(const wxVariant& value)
{ return wxPyGetAPIPtr()->p_wxVariant_out_helper(value); }
//--------------------------------------------------------------------------
// Convenience helper for RAII-style thread blocking
class wxPyThreadBlocker {
public:
explicit wxPyThreadBlocker(bool block=true)
: m_oldstate(block ? wxPyBeginBlockThreads() : wxPyBlock_t_default),
m_block(block)
{ }
~wxPyThreadBlocker() {
if (m_block) {
wxPyEndBlockThreads(m_oldstate);
}
}
private:
void operator=(const wxPyThreadBlocker&);
explicit wxPyThreadBlocker(const wxPyThreadBlocker&);
wxPyBlock_t m_oldstate;
bool m_block;
};
//--------------------------------------------------------------------------
// helper template to make common code for all of the various user data owners
template<typename Base>
class wxPyUserDataHelper : public Base {
public:
explicit wxPyUserDataHelper(PyObject* obj = NULL)
: m_obj(obj ? obj : Py_None)
{
wxPyThreadBlocker blocker;
Py_INCREF(m_obj);
}
~wxPyUserDataHelper()
{ // normally the derived class does the clean up, or deliberately leaks
// by setting m_obj to 0, but if not then do it here.
if (m_obj) {
wxPyThreadBlocker blocker;
Py_DECREF(m_obj);
m_obj = 0;
}
}
// Return Value: New reference
PyObject* GetData() const {
wxPyThreadBlocker blocker;
Py_INCREF(m_obj);
return m_obj;
}
// Return Value: Borrowed reference
PyObject* BorrowData() const {
return m_obj;
}
void SetData(PyObject* obj) {
if (obj != m_obj) {
wxPyThreadBlocker blocker;
Py_DECREF(m_obj);
m_obj = obj ? obj : Py_None;
Py_INCREF(m_obj);
}
}
// Return the object in udata or None if udata is null
// Return Value: New reference
static PyObject* SafeGetData(wxPyUserDataHelper<Base>* udata) {
wxPyThreadBlocker blocker;
PyObject* obj = udata ? udata->BorrowData() : Py_None;
Py_INCREF(obj);
return obj;
}
// Set the m_obj to null, this should only be used during clean up, when
// the object should be leaked.
// Calling any other methods on this object is then undefined behaviour
void ReleaseDataDuringCleanup()
{
m_obj = 0;
}
private:
PyObject* m_obj;
};
//--------------------------------------------------------------------------
#endif