]>
Commit | Line | Data |
---|---|---|
7bf85405 RD |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: helpers.cpp | |
03e9bead | 3 | // Purpose: Helper functions/classes for the wxPython extension module |
7bf85405 RD |
4 | // |
5 | // Author: Robin Dunn | |
6 | // | |
7 | // Created: 7/1/97 | |
8 | // RCS-ID: $Id$ | |
9 | // Copyright: (c) 1998 by Total Control Software | |
10 | // Licence: wxWindows license | |
11 | ///////////////////////////////////////////////////////////////////////////// | |
12 | ||
694759cf | 13 | #include <stdio.h> // get the correct definition of NULL |
08127323 | 14 | |
7bf85405 RD |
15 | #undef DEBUG |
16 | #include <Python.h> | |
17 | #include "helpers.h" | |
694759cf | 18 | |
af309447 RD |
19 | #ifdef __WXMSW__ |
20 | #include <wx/msw/private.h> | |
21 | #undef FindWindow | |
22 | #undef GetCharWidth | |
23 | #undef LoadAccelerators | |
24 | #undef GetClassInfo | |
25 | #undef GetClassName | |
26 | #endif | |
694759cf RD |
27 | |
28 | #ifdef __WXGTK__ | |
29 | #include <gtk/gtk.h> | |
54b96882 RD |
30 | #include <gdk/gdkprivate.h> |
31 | #include <wx/gtk/win_gtk.h> | |
32 | //#include <gdk/gdk.h> | |
33 | //#include <gdk/gdkx.h> | |
34 | //#include <gtk/gtkwindow.h> | |
7ff49f0c | 35 | |
f6bcfd97 | 36 | //extern GtkWidget *wxRootWindow; |
7ff49f0c | 37 | |
694759cf | 38 | #endif |
7bf85405 | 39 | |
cf694132 | 40 | |
7bf85405 RD |
41 | //--------------------------------------------------------------------------- |
42 | ||
43 | //wxHashTable* wxPyWindows = NULL; | |
44 | ||
45 | ||
46 | wxPoint wxPyDefaultPosition; //wxDefaultPosition); | |
47 | wxSize wxPyDefaultSize; //wxDefaultSize); | |
48 | wxString wxPyEmptyStr(""); | |
49 | ||
50 | ||
51 | ||
21f4bf45 | 52 | #ifdef __WXMSW__ // If building for win32... |
21f4bf45 RD |
53 | //---------------------------------------------------------------------- |
54 | // This gets run when the DLL is loaded. We just need to save a handle. | |
55 | //---------------------------------------------------------------------- | |
9c039d08 | 56 | |
21f4bf45 RD |
57 | BOOL WINAPI DllMain( |
58 | HINSTANCE hinstDLL, // handle to DLL module | |
59 | DWORD fdwReason, // reason for calling function | |
60 | LPVOID lpvReserved // reserved | |
61 | ) | |
62 | { | |
af309447 | 63 | wxSetInstance(hinstDLL); |
21f4bf45 RD |
64 | return 1; |
65 | } | |
66 | #endif | |
67 | ||
7bf85405 RD |
68 | //---------------------------------------------------------------------- |
69 | // Class for implementing the wxp main application shell. | |
70 | //---------------------------------------------------------------------- | |
71 | ||
72 | wxPyApp *wxPythonApp = NULL; // Global instance of application object | |
73 | ||
74 | ||
cf694132 RD |
75 | wxPyApp::wxPyApp() { |
76 | // printf("**** ctor\n"); | |
77 | } | |
78 | ||
79 | wxPyApp::~wxPyApp() { | |
80 | // printf("**** dtor\n"); | |
81 | } | |
82 | ||
83 | ||
7bf85405 RD |
84 | // This one isn't acutally called... See __wxStart() |
85 | bool wxPyApp::OnInit(void) { | |
6999b0d8 | 86 | return FALSE; |
7bf85405 RD |
87 | } |
88 | ||
89 | int wxPyApp::MainLoop(void) { | |
7ff49f0c | 90 | int retval = 0; |
af309447 | 91 | |
7ff49f0c RD |
92 | DeletePendingObjects(); |
93 | #ifdef __WXGTK__ | |
94 | m_initialized = wxTopLevelWindows.GetCount() != 0; | |
95 | #endif | |
7bf85405 | 96 | |
7ff49f0c RD |
97 | if (Initialized()) { |
98 | retval = wxApp::MainLoop(); | |
99 | wxPythonApp->OnExit(); | |
100 | } | |
101 | return retval; | |
102 | } | |
7bf85405 RD |
103 | |
104 | ||
fb5e0af0 | 105 | //--------------------------------------------------------------------- |
7bf85405 RD |
106 | //---------------------------------------------------------------------- |
107 | ||
7ece89c6 RD |
108 | int WXDLLEXPORT wxEntryStart( int argc, char** argv ); |
109 | int WXDLLEXPORT wxEntryInitGui(); | |
110 | void WXDLLEXPORT wxEntryCleanup(); | |
7ff49f0c | 111 | |
7bf85405 | 112 | |
f6bcfd97 BP |
113 | #ifdef WXP_WITH_THREAD |
114 | PyThreadState* wxPyEventThreadState = NULL; | |
115 | #endif | |
116 | static char* __nullArgv[1] = { 0 }; | |
117 | ||
118 | ||
0d6f9504 | 119 | // This is where we pick up the first part of the wxEntry functionality... |
f6bcfd97 | 120 | // The rest is in __wxStart and __wxCleanup. This function is called when |
8bf5d46e | 121 | // wxcmodule is imported. (Before there is a wxApp object.) |
0d6f9504 | 122 | void __wxPreStart() |
7bf85405 | 123 | { |
9d8bd15f RD |
124 | #ifdef WXP_WITH_THREAD |
125 | PyEval_InitThreads(); | |
f6bcfd97 | 126 | wxPyEventThreadState = PyThreadState_Get(); |
9d8bd15f RD |
127 | #endif |
128 | ||
0d6f9504 RD |
129 | // Bail out if there is already windows created. This means that the |
130 | // toolkit has already been initialized, as in embedding wxPython in | |
131 | // a C++ wxWindows app. | |
132 | if (wxTopLevelWindows.Number() > 0) | |
133 | return; | |
7bf85405 | 134 | |
7ff49f0c RD |
135 | |
136 | PyObject* sysargv = PySys_GetObject("argv"); | |
137 | int argc = PyList_Size(sysargv); | |
138 | char** argv = new char*[argc+1]; | |
139 | int x; | |
140 | for(x=0; x<argc; x++) | |
141 | argv[x] = PyString_AsString(PyList_GetItem(sysargv, x)); | |
142 | argv[argc] = NULL; | |
7bf85405 | 143 | |
7ff49f0c | 144 | wxEntryStart(argc, argv); |
f6bcfd97 | 145 | delete [] argv; |
0d6f9504 RD |
146 | } |
147 | ||
148 | ||
7ff49f0c | 149 | |
0d6f9504 RD |
150 | // Start the user application, user App's OnInit method is a parameter here |
151 | PyObject* __wxStart(PyObject* /* self */, PyObject* args) | |
152 | { | |
153 | PyObject* onInitFunc = NULL; | |
154 | PyObject* arglist; | |
155 | PyObject* result; | |
156 | long bResult; | |
157 | ||
0d6f9504 RD |
158 | if (!PyArg_ParseTuple(args, "O", &onInitFunc)) |
159 | return NULL; | |
160 | ||
161 | if (wxTopLevelWindows.Number() > 0) { | |
162 | PyErr_SetString(PyExc_TypeError, "Only 1 wxApp per process!"); | |
163 | return NULL; | |
164 | } | |
165 | ||
166 | ||
167 | // This is the next part of the wxEntry functionality... | |
f6bcfd97 BP |
168 | PyObject* sysargv = PySys_GetObject("argv"); |
169 | int argc = PyList_Size(sysargv); | |
170 | char** argv = new char*[argc+1]; | |
171 | int x; | |
172 | for(x=0; x<argc; x++) | |
c368d904 | 173 | argv[x] = copystring(PyString_AsString(PyList_GetItem(sysargv, x))); |
f6bcfd97 BP |
174 | argv[argc] = NULL; |
175 | ||
176 | wxPythonApp->argc = argc; | |
177 | wxPythonApp->argv = argv; | |
0d6f9504 | 178 | |
7ff49f0c | 179 | wxEntryInitGui(); |
7bf85405 RD |
180 | |
181 | // Call the Python App's OnInit function | |
182 | arglist = PyTuple_New(0); | |
183 | result = PyEval_CallObject(onInitFunc, arglist); | |
8bf5d46e RD |
184 | if (!result) { // an exception was raised. |
185 | return NULL; | |
7bf85405 RD |
186 | } |
187 | ||
188 | if (! PyInt_Check(result)) { | |
189 | PyErr_SetString(PyExc_TypeError, "OnInit should return a boolean value"); | |
190 | return NULL; | |
191 | } | |
192 | bResult = PyInt_AS_LONG(result); | |
193 | if (! bResult) { | |
194fa2ac | 194 | PyErr_SetString(PyExc_SystemExit, "OnInit returned FALSE, exiting..."); |
7bf85405 RD |
195 | return NULL; |
196 | } | |
197 | ||
13dfc243 | 198 | #ifdef __WXGTK__ |
7ff49f0c | 199 | wxTheApp->m_initialized = (wxTopLevelWindows.GetCount() > 0); |
13dfc243 | 200 | #endif |
fb5e0af0 | 201 | |
7bf85405 RD |
202 | Py_INCREF(Py_None); |
203 | return Py_None; | |
204 | } | |
205 | ||
7ff49f0c RD |
206 | void __wxCleanup() { |
207 | wxEntryCleanup(); | |
208 | } | |
7bf85405 RD |
209 | |
210 | ||
211 | ||
212 | PyObject* wxPython_dict; | |
213 | PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args) | |
214 | { | |
215 | ||
216 | if (!PyArg_ParseTuple(args, "O", &wxPython_dict)) | |
217 | return NULL; | |
218 | ||
219 | if (!PyDict_Check(wxPython_dict)) { | |
220 | PyErr_SetString(PyExc_TypeError, "_wxSetDictionary must have dictionary object!"); | |
221 | return NULL; | |
222 | } | |
223 | #ifdef __WXMOTIF__ | |
21f4bf45 RD |
224 | #define wxPlatform "__WXMOTIF__" |
225 | #endif | |
226 | #ifdef __WXQT__ | |
227 | #define wxPlatform "__WXQT__" | |
7bf85405 RD |
228 | #endif |
229 | #ifdef __WXGTK__ | |
21f4bf45 | 230 | #define wxPlatform "__WXGTK__" |
7bf85405 RD |
231 | #endif |
232 | #if defined(__WIN32__) || defined(__WXMSW__) | |
fb5e0af0 | 233 | #define wxPlatform "__WXMSW__" |
7bf85405 RD |
234 | #endif |
235 | #ifdef __WXMAC__ | |
21f4bf45 | 236 | #define wxPlatform "__WXMAC__" |
7bf85405 RD |
237 | #endif |
238 | ||
239 | PyDict_SetItemString(wxPython_dict, "wxPlatform", PyString_FromString(wxPlatform)); | |
240 | ||
241 | Py_INCREF(Py_None); | |
242 | return Py_None; | |
243 | } | |
244 | ||
245 | ||
246 | //--------------------------------------------------------------------------- | |
247 | ||
c368d904 | 248 | PyObject* wxPyConstructObject(void* ptr, |
33510773 RD |
249 | const char* className, |
250 | int setThisOwn) { | |
251 | PyObject* obj; | |
252 | PyObject* arg; | |
253 | ||
254 | if (!ptr) { | |
255 | Py_INCREF(Py_None); | |
256 | return Py_None; | |
257 | } | |
258 | ||
9c039d08 | 259 | char buff[64]; // should always be big enough... |
7bf85405 RD |
260 | char swigptr[64]; |
261 | ||
262 | sprintf(buff, "_%s_p", className); | |
263 | SWIG_MakePtr(swigptr, ptr, buff); | |
264 | ||
265 | sprintf(buff, "%sPtr", className); | |
266 | PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff); | |
267 | if (! classobj) { | |
33510773 RD |
268 | //Py_INCREF(Py_None); |
269 | //return Py_None; | |
270 | char temp[128]; | |
271 | sprintf(temp, | |
272 | "*** Unknown class name %s, tell Robin about it please ***", | |
273 | buff); | |
274 | obj = PyString_FromString(temp); | |
275 | return obj; | |
7bf85405 RD |
276 | } |
277 | ||
33510773 RD |
278 | arg = Py_BuildValue("(s)", swigptr); |
279 | obj = PyInstance_New(classobj, arg, NULL); | |
7bf85405 RD |
280 | Py_DECREF(arg); |
281 | ||
c368d904 RD |
282 | if (setThisOwn) { |
283 | PyObject_SetAttrString(obj, "thisown", PyInt_FromLong(1)); | |
284 | } | |
285 | ||
7bf85405 RD |
286 | return obj; |
287 | } | |
288 | ||
d559219f | 289 | //--------------------------------------------------------------------------- |
7bf85405 | 290 | |
99a49d3e | 291 | static unsigned int _wxPyNestCount = 0; |
cf694132 | 292 | |
99a49d3e RD |
293 | static PyThreadState* myPyThreadState_Get() { |
294 | PyThreadState* current; | |
295 | current = PyThreadState_Swap(NULL); | |
296 | PyThreadState_Swap(current); | |
297 | return current; | |
298 | } | |
d559219f | 299 | |
99a49d3e RD |
300 | |
301 | HELPEREXPORT bool wxPyRestoreThread() { | |
d559219f RD |
302 | // NOTE: The Python API docs state that if a thread already has the |
303 | // interpreter lock and calls PyEval_RestoreThread again a deadlock | |
99a49d3e RD |
304 | // occurs, so I put in this code as a guard condition since there are |
305 | // many possibilites for nested events and callbacks in wxPython. If | |
306 | // The current thread is our thread, then we can assume that we | |
2abc0a0f | 307 | // already have the lock. (I hope!) |
d559219f | 308 | // |
cf694132 | 309 | #ifdef WXP_WITH_THREAD |
99a49d3e RD |
310 | _wxPyNestCount += 1; |
311 | if (wxPyEventThreadState != myPyThreadState_Get()) { | |
312 | PyEval_RestoreThread(wxPyEventThreadState); | |
313 | return TRUE; | |
314 | } | |
315 | else | |
cf694132 | 316 | #endif |
d559219f RD |
317 | return FALSE; |
318 | } | |
cf694132 | 319 | |
cf694132 | 320 | |
d559219f | 321 | HELPEREXPORT void wxPySaveThread(bool doSave) { |
cf694132 | 322 | #ifdef WXP_WITH_THREAD |
99a49d3e | 323 | if (doSave) { |
9d8bd15f | 324 | wxPyEventThreadState = PyEval_SaveThread(); |
99a49d3e RD |
325 | } |
326 | _wxPyNestCount -= 1; | |
cf694132 RD |
327 | #endif |
328 | } | |
329 | ||
d559219f RD |
330 | //--------------------------------------------------------------------------- |
331 | ||
332 | ||
2f90df85 RD |
333 | IMPLEMENT_ABSTRACT_CLASS(wxPyCallback, wxObject); |
334 | ||
d559219f RD |
335 | wxPyCallback::wxPyCallback(PyObject* func) { |
336 | m_func = func; | |
337 | Py_INCREF(m_func); | |
338 | } | |
339 | ||
2f90df85 RD |
340 | wxPyCallback::wxPyCallback(const wxPyCallback& other) { |
341 | m_func = other.m_func; | |
342 | Py_INCREF(m_func); | |
343 | } | |
344 | ||
d559219f RD |
345 | wxPyCallback::~wxPyCallback() { |
346 | bool doSave = wxPyRestoreThread(); | |
347 | Py_DECREF(m_func); | |
348 | wxPySaveThread(doSave); | |
349 | } | |
350 | ||
cf694132 RD |
351 | |
352 | ||
7bf85405 RD |
353 | // This function is used for all events destined for Python event handlers. |
354 | void wxPyCallback::EventThunker(wxEvent& event) { | |
355 | wxPyCallback* cb = (wxPyCallback*)event.m_callbackUserData; | |
356 | PyObject* func = cb->m_func; | |
357 | PyObject* result; | |
358 | PyObject* arg; | |
359 | PyObject* tuple; | |
360 | ||
cf694132 | 361 | |
d559219f | 362 | bool doSave = wxPyRestoreThread(); |
65dd82cb RD |
363 | wxString className = event.GetClassInfo()->GetClassName(); |
364 | ||
365 | if (className == "wxPyEvent") | |
366 | arg = ((wxPyEvent*)&event)->GetSelf(); | |
367 | else if (className == "wxPyCommandEvent") | |
368 | arg = ((wxPyCommandEvent*)&event)->GetSelf(); | |
369 | else | |
370 | arg = wxPyConstructObject((void*)&event, className); | |
7bf85405 RD |
371 | |
372 | tuple = PyTuple_New(1); | |
373 | PyTuple_SET_ITEM(tuple, 0, arg); | |
374 | result = PyEval_CallObject(func, tuple); | |
7bf85405 RD |
375 | Py_DECREF(tuple); |
376 | if (result) { | |
377 | Py_DECREF(result); | |
378 | PyErr_Clear(); | |
379 | } else { | |
380 | PyErr_Print(); | |
381 | } | |
d559219f | 382 | wxPySaveThread(doSave); |
7bf85405 RD |
383 | } |
384 | ||
385 | ||
d559219f | 386 | //---------------------------------------------------------------------- |
7bf85405 | 387 | |
d559219f | 388 | wxPyCallbackHelper::wxPyCallbackHelper() { |
f6bcfd97 | 389 | m_class = NULL; |
d559219f RD |
390 | m_self = NULL; |
391 | m_lastFound = NULL; | |
b7312675 | 392 | m_incRef = FALSE; |
d559219f | 393 | } |
8bf5d46e | 394 | |
8bf5d46e | 395 | |
d559219f RD |
396 | wxPyCallbackHelper::~wxPyCallbackHelper() { |
397 | bool doSave = wxPyRestoreThread(); | |
f6bcfd97 | 398 | if (m_incRef) { |
b7312675 | 399 | Py_XDECREF(m_self); |
f6bcfd97 BP |
400 | Py_XDECREF(m_class); |
401 | } | |
d559219f RD |
402 | wxPySaveThread(doSave); |
403 | } | |
8bf5d46e | 404 | |
2f90df85 RD |
405 | wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper& other) { |
406 | m_lastFound = NULL; | |
407 | m_self = other.m_self; | |
f6bcfd97 BP |
408 | m_class = other.m_class; |
409 | if (m_self) { | |
2f90df85 | 410 | Py_INCREF(m_self); |
f6bcfd97 BP |
411 | Py_INCREF(m_class); |
412 | } | |
2f90df85 RD |
413 | } |
414 | ||
415 | ||
33510773 | 416 | void wxPyCallbackHelper::setSelf(PyObject* self, PyObject* klass, int incref) { |
d559219f | 417 | m_self = self; |
33510773 | 418 | m_class = klass; |
b7312675 | 419 | m_incRef = incref; |
f6bcfd97 | 420 | if (incref) { |
2f90df85 | 421 | Py_INCREF(m_self); |
f6bcfd97 BP |
422 | Py_INCREF(m_class); |
423 | } | |
d559219f | 424 | } |
8bf5d46e | 425 | |
8bf5d46e | 426 | |
f6bcfd97 BP |
427 | // If the object (m_self) has an attibute of the given name, and if that |
428 | // attribute is a method, and if that method's class is not from a base class, | |
429 | // then we'll save a pointer to the method so callCallback can call it. | |
430 | bool wxPyCallbackHelper::findCallback(const wxString& name) const { | |
431 | wxPyCallbackHelper* self = (wxPyCallbackHelper*)this; // cast away const | |
432 | self->m_lastFound = NULL; | |
433 | if (m_self && PyObject_HasAttrString(m_self, (char*)name.c_str())) { | |
434 | PyObject* method; | |
435 | method = PyObject_GetAttrString(m_self, (char*)name.c_str()); | |
436 | ||
437 | if (PyMethod_Check(method) && | |
438 | ((PyMethod_GET_CLASS(method) == m_class) || | |
439 | PyClass_IsSubclass(PyMethod_GET_CLASS(method), m_class))) { | |
8bf5d46e | 440 | |
f6bcfd97 BP |
441 | self->m_lastFound = method; |
442 | } | |
443 | } | |
d559219f RD |
444 | return m_lastFound != NULL; |
445 | } | |
8bf5d46e | 446 | |
d559219f | 447 | |
f6bcfd97 | 448 | int wxPyCallbackHelper::callCallback(PyObject* argTuple) const { |
d559219f RD |
449 | PyObject* result; |
450 | int retval = FALSE; | |
451 | ||
452 | result = callCallbackObj(argTuple); | |
453 | if (result) { // Assumes an integer return type... | |
454 | retval = PyInt_AsLong(result); | |
455 | Py_DECREF(result); | |
456 | PyErr_Clear(); // forget about it if it's not... | |
457 | } | |
458 | return retval; | |
459 | } | |
460 | ||
461 | // Invoke the Python callable object, returning the raw PyObject return | |
462 | // value. Caller should DECREF the return value and also call PyEval_SaveThread. | |
f6bcfd97 | 463 | PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) const { |
d559219f RD |
464 | PyObject* result; |
465 | ||
466 | result = PyEval_CallObject(m_lastFound, argTuple); | |
467 | Py_DECREF(argTuple); | |
468 | if (!result) { | |
469 | PyErr_Print(); | |
470 | } | |
471 | return result; | |
472 | } | |
714e6a9e | 473 | |
7bf85405 | 474 | |
d559219f | 475 | |
65dd82cb RD |
476 | //--------------------------------------------------------------------------- |
477 | //--------------------------------------------------------------------------- | |
478 | // These classes can be derived from in Python and passed through the event | |
c368d904 | 479 | // system without losing anything. They do this by keeping a reference to |
65dd82cb RD |
480 | // themselves and some special case handling in wxPyCallback::EventThunker. |
481 | ||
482 | ||
e19b7164 | 483 | wxPyEvtSelfRef::wxPyEvtSelfRef() { |
65dd82cb RD |
484 | //m_self = Py_None; // **** We don't do normal ref counting to prevent |
485 | //Py_INCREF(m_self); // circular loops... | |
194fa2ac | 486 | m_cloned = FALSE; |
65dd82cb RD |
487 | } |
488 | ||
e19b7164 | 489 | wxPyEvtSelfRef::~wxPyEvtSelfRef() { |
65dd82cb RD |
490 | bool doSave = wxPyRestoreThread(); |
491 | if (m_cloned) | |
492 | Py_DECREF(m_self); | |
493 | wxPySaveThread(doSave); | |
494 | } | |
495 | ||
e19b7164 | 496 | void wxPyEvtSelfRef::SetSelf(PyObject* self, bool clone) { |
65dd82cb RD |
497 | bool doSave = wxPyRestoreThread(); |
498 | if (m_cloned) | |
499 | Py_DECREF(m_self); | |
500 | m_self = self; | |
501 | if (clone) { | |
502 | Py_INCREF(m_self); | |
503 | m_cloned = TRUE; | |
504 | } | |
505 | wxPySaveThread(doSave); | |
506 | } | |
507 | ||
e19b7164 | 508 | PyObject* wxPyEvtSelfRef::GetSelf() const { |
65dd82cb RD |
509 | Py_INCREF(m_self); |
510 | return m_self; | |
511 | } | |
512 | ||
513 | ||
514 | wxPyEvent::wxPyEvent(int id) | |
515 | : wxEvent(id) { | |
516 | } | |
517 | ||
518 | wxPyEvent::~wxPyEvent() { | |
519 | } | |
520 | ||
521 | // This one is so the event object can be Cloned... | |
522 | void wxPyEvent::CopyObject(wxObject& dest) const { | |
523 | wxEvent::CopyObject(dest); | |
524 | ((wxPyEvent*)&dest)->SetSelf(m_self, TRUE); | |
525 | } | |
526 | ||
527 | ||
528 | IMPLEMENT_DYNAMIC_CLASS(wxPyEvent, wxEvent); | |
529 | ||
530 | ||
531 | wxPyCommandEvent::wxPyCommandEvent(wxEventType commandType, int id) | |
532 | : wxCommandEvent(commandType, id) { | |
533 | } | |
534 | ||
535 | wxPyCommandEvent::~wxPyCommandEvent() { | |
536 | } | |
537 | ||
538 | void wxPyCommandEvent::CopyObject(wxObject& dest) const { | |
539 | wxCommandEvent::CopyObject(dest); | |
540 | ((wxPyCommandEvent*)&dest)->SetSelf(m_self, TRUE); | |
541 | } | |
542 | ||
543 | ||
544 | IMPLEMENT_DYNAMIC_CLASS(wxPyCommandEvent, wxCommandEvent); | |
545 | ||
546 | ||
547 | ||
d559219f | 548 | //--------------------------------------------------------------------------- |
7bf85405 RD |
549 | //--------------------------------------------------------------------------- |
550 | ||
d559219f | 551 | |
7bf85405 RD |
552 | wxPyTimer::wxPyTimer(PyObject* callback) { |
553 | func = callback; | |
554 | Py_INCREF(func); | |
555 | } | |
556 | ||
557 | wxPyTimer::~wxPyTimer() { | |
d559219f | 558 | bool doSave = wxPyRestoreThread(); |
7bf85405 | 559 | Py_DECREF(func); |
d559219f | 560 | wxPySaveThread(doSave); |
7bf85405 RD |
561 | } |
562 | ||
563 | void wxPyTimer::Notify() { | |
185d7c3e RD |
564 | if (!func || func == Py_None) { |
565 | wxTimer::Notify(); | |
566 | } | |
567 | else { | |
568 | bool doSave = wxPyRestoreThread(); | |
569 | ||
570 | PyObject* result; | |
571 | PyObject* args = Py_BuildValue("()"); | |
572 | ||
573 | result = PyEval_CallObject(func, args); | |
574 | Py_DECREF(args); | |
575 | if (result) { | |
576 | Py_DECREF(result); | |
577 | PyErr_Clear(); | |
578 | } else { | |
579 | PyErr_Print(); | |
580 | } | |
7bf85405 | 581 | |
185d7c3e | 582 | wxPySaveThread(doSave); |
7bf85405 RD |
583 | } |
584 | } | |
585 | ||
586 | ||
cf694132 | 587 | |
2f90df85 | 588 | //--------------------------------------------------------------------------- |
389c5527 RD |
589 | //--------------------------------------------------------------------------- |
590 | // Convert a wxList to a Python List | |
591 | ||
65dd82cb | 592 | PyObject* wxPy_ConvertList(wxListBase* list, const char* className) { |
389c5527 RD |
593 | PyObject* pyList; |
594 | PyObject* pyObj; | |
595 | wxObject* wxObj; | |
596 | wxNode* node = list->First(); | |
597 | ||
598 | bool doSave = wxPyRestoreThread(); | |
599 | pyList = PyList_New(0); | |
600 | while (node) { | |
601 | wxObj = node->Data(); | |
602 | pyObj = wxPyConstructObject(wxObj, className); | |
603 | PyList_Append(pyList, pyObj); | |
604 | node = node->Next(); | |
605 | } | |
606 | wxPySaveThread(doSave); | |
607 | return pyList; | |
608 | } | |
609 | ||
54b96882 RD |
610 | //---------------------------------------------------------------------- |
611 | ||
612 | long wxPyGetWinHandle(wxWindow* win) { | |
613 | #ifdef __WXMSW__ | |
614 | return (long)win->GetHandle(); | |
615 | #endif | |
616 | ||
617 | // Find and return the actual X-Window. | |
618 | #ifdef __WXGTK__ | |
619 | if (win->m_wxwindow) { | |
620 | GdkWindowPrivate* bwin = (GdkWindowPrivate*)GTK_PIZZA(win->m_wxwindow)->bin_window; | |
621 | if (bwin) { | |
622 | return (long)bwin->xwindow; | |
623 | } | |
624 | } | |
625 | #endif | |
626 | return 0; | |
627 | } | |
628 | ||
7bf85405 RD |
629 | //---------------------------------------------------------------------- |
630 | // Some helper functions for typemaps in my_typemaps.i, so they won't be | |
389c5527 | 631 | // included in every file... |
7bf85405 RD |
632 | |
633 | ||
2f90df85 | 634 | byte* byte_LIST_helper(PyObject* source) { |
b639c3c5 RD |
635 | if (!PyList_Check(source)) { |
636 | PyErr_SetString(PyExc_TypeError, "Expected a list object."); | |
637 | return NULL; | |
638 | } | |
639 | int count = PyList_Size(source); | |
640 | byte* temp = new byte[count]; | |
641 | if (! temp) { | |
642 | PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array"); | |
643 | return NULL; | |
644 | } | |
645 | for (int x=0; x<count; x++) { | |
646 | PyObject* o = PyList_GetItem(source, x); | |
647 | if (! PyInt_Check(o)) { | |
648 | PyErr_SetString(PyExc_TypeError, "Expected a list of integers."); | |
649 | return NULL; | |
650 | } | |
651 | temp[x] = (byte)PyInt_AsLong(o); | |
652 | } | |
653 | return temp; | |
654 | } | |
655 | ||
656 | ||
2f90df85 | 657 | int* int_LIST_helper(PyObject* source) { |
7bf85405 RD |
658 | if (!PyList_Check(source)) { |
659 | PyErr_SetString(PyExc_TypeError, "Expected a list object."); | |
660 | return NULL; | |
661 | } | |
662 | int count = PyList_Size(source); | |
663 | int* temp = new int[count]; | |
664 | if (! temp) { | |
665 | PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array"); | |
666 | return NULL; | |
667 | } | |
668 | for (int x=0; x<count; x++) { | |
669 | PyObject* o = PyList_GetItem(source, x); | |
670 | if (! PyInt_Check(o)) { | |
671 | PyErr_SetString(PyExc_TypeError, "Expected a list of integers."); | |
672 | return NULL; | |
673 | } | |
674 | temp[x] = PyInt_AsLong(o); | |
675 | } | |
676 | return temp; | |
677 | } | |
678 | ||
679 | ||
2f90df85 | 680 | long* long_LIST_helper(PyObject* source) { |
7bf85405 RD |
681 | if (!PyList_Check(source)) { |
682 | PyErr_SetString(PyExc_TypeError, "Expected a list object."); | |
683 | return NULL; | |
684 | } | |
685 | int count = PyList_Size(source); | |
686 | long* temp = new long[count]; | |
687 | if (! temp) { | |
688 | PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array"); | |
689 | return NULL; | |
690 | } | |
691 | for (int x=0; x<count; x++) { | |
692 | PyObject* o = PyList_GetItem(source, x); | |
693 | if (! PyInt_Check(o)) { | |
694 | PyErr_SetString(PyExc_TypeError, "Expected a list of integers."); | |
695 | return NULL; | |
696 | } | |
697 | temp[x] = PyInt_AsLong(o); | |
698 | } | |
699 | return temp; | |
700 | } | |
701 | ||
702 | ||
2f90df85 | 703 | char** string_LIST_helper(PyObject* source) { |
7bf85405 RD |
704 | if (!PyList_Check(source)) { |
705 | PyErr_SetString(PyExc_TypeError, "Expected a list object."); | |
706 | return NULL; | |
707 | } | |
708 | int count = PyList_Size(source); | |
709 | char** temp = new char*[count]; | |
710 | if (! temp) { | |
711 | PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array"); | |
712 | return NULL; | |
713 | } | |
714 | for (int x=0; x<count; x++) { | |
715 | PyObject* o = PyList_GetItem(source, x); | |
716 | if (! PyString_Check(o)) { | |
717 | PyErr_SetString(PyExc_TypeError, "Expected a list of strings."); | |
718 | return NULL; | |
719 | } | |
720 | temp[x] = PyString_AsString(o); | |
721 | } | |
722 | return temp; | |
723 | } | |
724 | ||
725 | ||
726 | ||
2f90df85 | 727 | wxPoint* wxPoint_LIST_helper(PyObject* source) { |
7bf85405 RD |
728 | if (!PyList_Check(source)) { |
729 | PyErr_SetString(PyExc_TypeError, "Expected a list object."); | |
730 | return NULL; | |
731 | } | |
732 | int count = PyList_Size(source); | |
733 | wxPoint* temp = new wxPoint[count]; | |
734 | if (! temp) { | |
735 | PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array"); | |
736 | return NULL; | |
737 | } | |
738 | for (int x=0; x<count; x++) { | |
739 | PyObject* o = PyList_GetItem(source, x); | |
d559219f | 740 | if (PyTuple_Check(o)) { |
7bf85405 RD |
741 | PyObject* o1 = PyTuple_GetItem(o, 0); |
742 | PyObject* o2 = PyTuple_GetItem(o, 1); | |
743 | ||
744 | temp[x].x = PyInt_AsLong(o1); | |
745 | temp[x].y = PyInt_AsLong(o2); | |
746 | } | |
d559219f RD |
747 | else if (PyInstance_Check(o)) { |
748 | wxPoint* pt; | |
749 | if (SWIG_GetPtrObj(o,(void **) &pt,"_wxPoint_p")) { | |
750 | PyErr_SetString(PyExc_TypeError,"Expected _wxPoint_p."); | |
751 | return NULL; | |
752 | } | |
753 | temp[x] = *pt; | |
754 | } | |
7bf85405 RD |
755 | else { |
756 | PyErr_SetString(PyExc_TypeError, "Expected a list of 2-tuples or wxPoints."); | |
757 | return NULL; | |
758 | } | |
759 | } | |
760 | return temp; | |
761 | } | |
762 | ||
763 | ||
2f90df85 | 764 | wxBitmap** wxBitmap_LIST_helper(PyObject* source) { |
7bf85405 RD |
765 | if (!PyList_Check(source)) { |
766 | PyErr_SetString(PyExc_TypeError, "Expected a list object."); | |
767 | return NULL; | |
768 | } | |
769 | int count = PyList_Size(source); | |
770 | wxBitmap** temp = new wxBitmap*[count]; | |
771 | if (! temp) { | |
772 | PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array"); | |
773 | return NULL; | |
774 | } | |
775 | for (int x=0; x<count; x++) { | |
776 | PyObject* o = PyList_GetItem(source, x); | |
e166644c | 777 | if (PyInstance_Check(o)) { |
7bf85405 | 778 | wxBitmap* pt; |
e166644c | 779 | if (SWIG_GetPtrObj(o, (void **) &pt,"_wxBitmap_p")) { |
7bf85405 RD |
780 | PyErr_SetString(PyExc_TypeError,"Expected _wxBitmap_p."); |
781 | return NULL; | |
782 | } | |
783 | temp[x] = pt; | |
784 | } | |
785 | else { | |
786 | PyErr_SetString(PyExc_TypeError, "Expected a list of wxBitmaps."); | |
787 | return NULL; | |
788 | } | |
789 | } | |
790 | return temp; | |
791 | } | |
792 | ||
793 | ||
794 | ||
2f90df85 | 795 | wxString* wxString_LIST_helper(PyObject* source) { |
7bf85405 RD |
796 | if (!PyList_Check(source)) { |
797 | PyErr_SetString(PyExc_TypeError, "Expected a list object."); | |
798 | return NULL; | |
799 | } | |
800 | int count = PyList_Size(source); | |
801 | wxString* temp = new wxString[count]; | |
802 | if (! temp) { | |
803 | PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array"); | |
804 | return NULL; | |
805 | } | |
806 | for (int x=0; x<count; x++) { | |
807 | PyObject* o = PyList_GetItem(source, x); | |
808 | if (! PyString_Check(o)) { | |
809 | PyErr_SetString(PyExc_TypeError, "Expected a list of strings."); | |
810 | return NULL; | |
811 | } | |
812 | temp[x] = PyString_AsString(o); | |
813 | } | |
814 | return temp; | |
815 | } | |
816 | ||
817 | ||
2f90df85 | 818 | wxAcceleratorEntry* wxAcceleratorEntry_LIST_helper(PyObject* source) { |
7bf85405 RD |
819 | if (!PyList_Check(source)) { |
820 | PyErr_SetString(PyExc_TypeError, "Expected a list object."); | |
821 | return NULL; | |
822 | } | |
823 | int count = PyList_Size(source); | |
824 | wxAcceleratorEntry* temp = new wxAcceleratorEntry[count]; | |
825 | if (! temp) { | |
826 | PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array"); | |
827 | return NULL; | |
828 | } | |
829 | for (int x=0; x<count; x++) { | |
830 | PyObject* o = PyList_GetItem(source, x); | |
e166644c | 831 | if (PyInstance_Check(o)) { |
7bf85405 | 832 | wxAcceleratorEntry* ae; |
e166644c | 833 | if (SWIG_GetPtrObj(o, (void **) &ae,"_wxAcceleratorEntry_p")) { |
7bf85405 RD |
834 | PyErr_SetString(PyExc_TypeError,"Expected _wxAcceleratorEntry_p."); |
835 | return NULL; | |
836 | } | |
837 | temp[x] = *ae; | |
838 | } | |
839 | else if (PyTuple_Check(o)) { | |
840 | PyObject* o1 = PyTuple_GetItem(o, 0); | |
841 | PyObject* o2 = PyTuple_GetItem(o, 1); | |
842 | PyObject* o3 = PyTuple_GetItem(o, 2); | |
843 | ||
844 | temp[x].m_flags = PyInt_AsLong(o1); | |
845 | temp[x].m_keyCode = PyInt_AsLong(o2); | |
846 | temp[x].m_command = PyInt_AsLong(o3); | |
847 | } | |
848 | else { | |
849 | PyErr_SetString(PyExc_TypeError, "Expected a list of 3-tuples or wxAcceleratorEntry objects."); | |
850 | return NULL; | |
851 | } | |
852 | } | |
853 | return temp; | |
854 | } | |
855 | ||
bb0054cd RD |
856 | |
857 | ||
858 | //---------------------------------------------------------------------- | |
bb0054cd | 859 | |
2f90df85 RD |
860 | bool wxSize_helper(PyObject* source, wxSize** obj) { |
861 | ||
862 | // If source is an object instance then it may already be the right type | |
863 | if (PyInstance_Check(source)) { | |
864 | wxSize* ptr; | |
865 | if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxSize_p")) | |
866 | goto error; | |
867 | *obj = ptr; | |
868 | return TRUE; | |
869 | } | |
870 | // otherwise a 2-tuple of integers is expected | |
871 | else if (PySequence_Check(source) && PyObject_Length(source) == 2) { | |
872 | PyObject* o1 = PySequence_GetItem(source, 0); | |
873 | PyObject* o2 = PySequence_GetItem(source, 1); | |
874 | **obj = wxSize(PyInt_AsLong(o1), PyInt_AsLong(o2)); | |
875 | return TRUE; | |
876 | } | |
877 | ||
878 | error: | |
879 | PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of integers or a wxSize object."); | |
880 | return FALSE; | |
881 | } | |
882 | ||
883 | bool wxPoint_helper(PyObject* source, wxPoint** obj) { | |
884 | ||
885 | // If source is an object instance then it may already be the right type | |
886 | if (PyInstance_Check(source)) { | |
887 | wxPoint* ptr; | |
888 | if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxPoint_p")) | |
889 | goto error; | |
890 | *obj = ptr; | |
891 | return TRUE; | |
892 | } | |
893 | // otherwise a 2-tuple of integers is expected | |
894 | else if (PySequence_Check(source) && PyObject_Length(source) == 2) { | |
895 | PyObject* o1 = PySequence_GetItem(source, 0); | |
896 | PyObject* o2 = PySequence_GetItem(source, 1); | |
897 | **obj = wxPoint(PyInt_AsLong(o1), PyInt_AsLong(o2)); | |
898 | return TRUE; | |
899 | } | |
900 | ||
901 | error: | |
902 | PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of integers or a wxPoint object."); | |
903 | return FALSE; | |
904 | } | |
905 | ||
906 | ||
907 | ||
908 | bool wxRealPoint_helper(PyObject* source, wxRealPoint** obj) { | |
909 | ||
910 | // If source is an object instance then it may already be the right type | |
911 | if (PyInstance_Check(source)) { | |
912 | wxRealPoint* ptr; | |
913 | if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxRealPoint_p")) | |
914 | goto error; | |
915 | *obj = ptr; | |
916 | return TRUE; | |
917 | } | |
918 | // otherwise a 2-tuple of floats is expected | |
919 | else if (PySequence_Check(source) && PyObject_Length(source) == 2) { | |
920 | PyObject* o1 = PySequence_GetItem(source, 0); | |
921 | PyObject* o2 = PySequence_GetItem(source, 1); | |
922 | **obj = wxRealPoint(PyFloat_AsDouble(o1), PyFloat_AsDouble(o2)); | |
923 | return TRUE; | |
924 | } | |
925 | ||
926 | error: | |
927 | PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of floats or a wxRealPoint object."); | |
928 | return FALSE; | |
929 | } | |
930 | ||
931 | ||
932 | ||
933 | ||
934 | bool wxRect_helper(PyObject* source, wxRect** obj) { | |
935 | ||
936 | // If source is an object instance then it may already be the right type | |
937 | if (PyInstance_Check(source)) { | |
938 | wxRect* ptr; | |
939 | if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxRect_p")) | |
940 | goto error; | |
941 | *obj = ptr; | |
942 | return TRUE; | |
943 | } | |
944 | // otherwise a 4-tuple of integers is expected | |
945 | else if (PySequence_Check(source) && PyObject_Length(source) == 4) { | |
946 | PyObject* o1 = PySequence_GetItem(source, 0); | |
947 | PyObject* o2 = PySequence_GetItem(source, 1); | |
948 | PyObject* o3 = PySequence_GetItem(source, 2); | |
949 | PyObject* o4 = PySequence_GetItem(source, 3); | |
950 | **obj = wxRect(PyInt_AsLong(o1), PyInt_AsLong(o2), | |
951 | PyInt_AsLong(o3), PyInt_AsLong(o4)); | |
952 | return TRUE; | |
953 | } | |
954 | ||
955 | error: | |
956 | PyErr_SetString(PyExc_TypeError, "Expected a 4-tuple of integers or a wxRect object."); | |
957 | return FALSE; | |
958 | } | |
959 | ||
960 | ||
961 | ||
f6bcfd97 BP |
962 | bool wxColour_helper(PyObject* source, wxColour** obj) { |
963 | ||
964 | // If source is an object instance then it may already be the right type | |
965 | if (PyInstance_Check(source)) { | |
966 | wxColour* ptr; | |
967 | if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxColour_p")) | |
968 | goto error; | |
969 | *obj = ptr; | |
970 | return TRUE; | |
971 | } | |
972 | // otherwise a string is expected | |
973 | else if (PyString_Check(source)) { | |
974 | wxString spec = PyString_AS_STRING(source); | |
975 | if (spec[0] == '#' && spec.Length() == 7) { // It's #RRGGBB | |
976 | char* junk; | |
977 | int red = strtol(spec.Mid(1,2), &junk, 16); | |
978 | int green = strtol(spec.Mid(3,2), &junk, 16); | |
979 | int blue = strtol(spec.Mid(5,2), &junk, 16); | |
980 | **obj = wxColour(red, green, blue); | |
981 | return TRUE; | |
982 | } | |
983 | else { // it's a colour name | |
984 | **obj = wxColour(spec); | |
985 | return TRUE; | |
986 | } | |
987 | } | |
988 | ||
989 | error: | |
990 | PyErr_SetString(PyExc_TypeError, "Expected a wxColour object or a string containing a colour name or #RRGGBB."); | |
991 | return FALSE; | |
992 | } | |
993 | ||
994 | ||
bb0054cd RD |
995 | //---------------------------------------------------------------------- |
996 | //---------------------------------------------------------------------- | |
7bf85405 | 997 | //---------------------------------------------------------------------- |
7bf85405 | 998 | |
7bf85405 | 999 | |
7bf85405 | 1000 |