]> git.saurik.com Git - wxWidgets.git/blob - utils/wxPython/src/helpers.cpp
Prep for wxPython 2.1b3 release
[wxWidgets.git] / utils / wxPython / src / helpers.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: helpers.cpp
3 // Purpose: Helper functions/classes for the wxPython extension module
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
13
14 #ifdef __WXGTK__
15 #include <gtk/gtk.h>
16 #endif
17
18 #undef DEBUG
19 #include <Python.h>
20 #include "helpers.h"
21 #ifdef __WXMSW__
22 #include <wx/msw/private.h>
23 #undef FindWindow
24 #undef GetCharWidth
25 #undef LoadAccelerators
26 #undef GetClassInfo
27 #undef GetClassName
28 #endif
29 #include <wx/module.h>
30
31
32 //---------------------------------------------------------------------------
33
34 //wxHashTable* wxPyWindows = NULL;
35
36
37 wxPoint wxPyDefaultPosition; //wxDefaultPosition);
38 wxSize wxPyDefaultSize; //wxDefaultSize);
39 wxString wxPyEmptyStr("");
40
41
42
43 #ifdef __WXMSW__ // If building for win32...
44 //----------------------------------------------------------------------
45 // This gets run when the DLL is loaded. We just need to save a handle.
46 //----------------------------------------------------------------------
47
48 BOOL WINAPI DllMain(
49 HINSTANCE hinstDLL, // handle to DLL module
50 DWORD fdwReason, // reason for calling function
51 LPVOID lpvReserved // reserved
52 )
53 {
54 wxSetInstance(hinstDLL);
55 return 1;
56 }
57 #endif
58
59 //----------------------------------------------------------------------
60 // Class for implementing the wxp main application shell.
61 //----------------------------------------------------------------------
62
63 wxPyApp *wxPythonApp = NULL; // Global instance of application object
64
65
66 wxPyApp::wxPyApp() {
67 // printf("**** ctor\n");
68 }
69
70 wxPyApp::~wxPyApp() {
71 // printf("**** dtor\n");
72 }
73
74
75 // This one isn't acutally called... See __wxStart()
76 bool wxPyApp::OnInit(void) {
77 return false;
78 }
79
80 int wxPyApp::MainLoop(void) {
81 int retval = wxApp::MainLoop();
82 //# AfterMainLoop();
83 wxPythonApp->OnExit(); //#
84 return retval;
85 }
86
87
88 //# void wxPyApp::AfterMainLoop(void) {
89 // // more stuff from wxEntry...
90
91 // if (wxPythonApp->GetTopWindow()) {
92 // // Forcibly delete the window.
93 // if (wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxFrame)) ||
94 // wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxDialog))) {
95
96 // wxPythonApp->GetTopWindow()->Close(TRUE);
97 // wxPythonApp->DeletePendingObjects();
98 // }
99 // else {
100 // delete wxPythonApp->GetTopWindow();
101 // wxPythonApp->SetTopWindow(NULL);
102 // }
103 // }
104 // #ifdef __WXGTK__
105 // wxPythonApp->DeletePendingObjects();
106 // #endif
107
108 // wxPythonApp->OnExit();
109 // wxApp::CleanUp();
110 // // delete wxPythonApp;
111 // }
112
113
114 //---------------------------------------------------------------------
115 // a few native methods to add to the module
116 //----------------------------------------------------------------------
117
118
119 // This is where we pick up the first part of the wxEntry functionality...
120 // The rest is in __wxStart and AfterMainLoop. This function is called when
121 // wxcmodule is imported. (Before there is a wxApp object.)
122 void __wxPreStart()
123 {
124 // Bail out if there is already windows created. This means that the
125 // toolkit has already been initialized, as in embedding wxPython in
126 // a C++ wxWindows app.
127 if (wxTopLevelWindows.Number() > 0)
128 return;
129
130 #ifdef __WXMSW__
131 wxApp::Initialize();
132 #endif
133
134 #ifdef __WXGTK__
135 PyObject* sysargv = PySys_GetObject("argv");
136 int argc = PyList_Size(sysargv);
137 char** argv = new char*[argc+1];
138 int x;
139 for(x=0; x<argc; x++)
140 argv[x] = PyString_AsString(PyList_GetItem(sysargv, x));
141 argv[argc] = NULL;
142
143 gtk_set_locale();
144 if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
145 gtk_init( &argc, &argv );
146 wxSetDetectableAutoRepeat( TRUE );
147 delete [] argv;
148
149 wxApp::Initialize(); // may return FALSE. Should we check?
150 #endif
151
152 }
153
154
155 #ifdef WXP_WITH_THREAD
156 PyThreadState* wxPyEventThreadState = NULL;
157 bool wxPyInEvent = false;
158 #endif
159 static char* __nullArgv[1] = { 0 };
160
161
162
163 // Start the user application, user App's OnInit method is a parameter here
164 PyObject* __wxStart(PyObject* /* self */, PyObject* args)
165 {
166 PyObject* onInitFunc = NULL;
167 PyObject* arglist;
168 PyObject* result;
169 long bResult;
170
171 #ifdef WXP_WITH_THREAD
172 wxPyEventThreadState = PyThreadState_Get();
173 #endif
174
175 if (!PyArg_ParseTuple(args, "O", &onInitFunc))
176 return NULL;
177
178 if (wxTopLevelWindows.Number() > 0) {
179 PyErr_SetString(PyExc_TypeError, "Only 1 wxApp per process!");
180 return NULL;
181 }
182
183
184 // This is the next part of the wxEntry functionality...
185 wxPythonApp->argc = 0;
186 wxPythonApp->argv = NULL;
187 wxPythonApp->OnInitGui();
188
189
190 // Call the Python App's OnInit function
191 arglist = PyTuple_New(0);
192 result = PyEval_CallObject(onInitFunc, arglist);
193 if (!result) { // an exception was raised.
194 return NULL;
195 }
196
197 if (! PyInt_Check(result)) {
198 PyErr_SetString(PyExc_TypeError, "OnInit should return a boolean value");
199 return NULL;
200 }
201 bResult = PyInt_AS_LONG(result);
202 if (! bResult) {
203 PyErr_SetString(PyExc_SystemExit, "OnInit returned false, exiting...");
204 return NULL;
205 }
206
207 #ifdef __WXGTK__
208 wxTheApp->m_initialized = (wxTopLevelWindows.Number() > 0);
209 #endif
210
211 Py_INCREF(Py_None);
212 return Py_None;
213 }
214
215
216
217
218
219 PyObject* wxPython_dict;
220 PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
221 {
222
223 if (!PyArg_ParseTuple(args, "O", &wxPython_dict))
224 return NULL;
225
226 if (!PyDict_Check(wxPython_dict)) {
227 PyErr_SetString(PyExc_TypeError, "_wxSetDictionary must have dictionary object!");
228 return NULL;
229 }
230 #ifdef __WXMOTIF__
231 #define wxPlatform "__WXMOTIF__"
232 #endif
233 #ifdef __WXQT__
234 #define wxPlatform "__WXQT__"
235 #endif
236 #ifdef __WXGTK__
237 #define wxPlatform "__WXGTK__"
238 #endif
239 #if defined(__WIN32__) || defined(__WXMSW__)
240 #define wxPlatform "__WXMSW__"
241 #endif
242 #ifdef __WXMAC__
243 #define wxPlatform "__WXMAC__"
244 #endif
245
246 PyDict_SetItemString(wxPython_dict, "wxPlatform", PyString_FromString(wxPlatform));
247
248 Py_INCREF(Py_None);
249 return Py_None;
250 }
251
252
253 //---------------------------------------------------------------------------
254
255 PyObject* wxPyConstructObject(void* ptr, char* className)
256 {
257 char buff[64]; // should always be big enough...
258 char swigptr[64];
259
260 sprintf(buff, "_%s_p", className);
261 SWIG_MakePtr(swigptr, ptr, buff);
262
263 sprintf(buff, "%sPtr", className);
264 PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff);
265 if (! classobj) {
266 Py_INCREF(Py_None);
267 return Py_None;
268 }
269
270 PyObject* arg = Py_BuildValue("(s)", swigptr);
271 PyObject* obj = PyInstance_New(classobj, arg, NULL);
272 Py_DECREF(arg);
273
274 return obj;
275 }
276
277
278
279 wxPyCallback::wxPyCallback(PyObject* func) {
280 m_func = func;
281 Py_INCREF(m_func);
282 }
283
284 wxPyCallback::~wxPyCallback() {
285 #ifdef WXP_WITH_THREAD
286 //if (! wxPyInEvent)
287 PyEval_RestoreThread(wxPyEventThreadState);
288 #endif
289
290 Py_DECREF(m_func);
291
292 #ifdef WXP_WITH_THREAD
293 //if (! wxPyInEvent)
294 PyEval_SaveThread();
295 #endif
296 }
297
298
299
300
301 // This function is used for all events destined for Python event handlers.
302 void wxPyCallback::EventThunker(wxEvent& event) {
303 wxPyCallback* cb = (wxPyCallback*)event.m_callbackUserData;
304 PyObject* func = cb->m_func;
305 PyObject* result;
306 PyObject* arg;
307 PyObject* tuple;
308
309
310 #ifdef WXP_WITH_THREAD
311 PyEval_RestoreThread(wxPyEventThreadState);
312 wxPyInEvent = true;
313 #endif
314 arg = wxPyConstructObject((void*)&event, event.GetClassInfo()->GetClassName());
315
316 tuple = PyTuple_New(1);
317 PyTuple_SET_ITEM(tuple, 0, arg);
318 result = PyEval_CallObject(func, tuple);
319 Py_DECREF(tuple);
320 if (result) {
321 Py_DECREF(result);
322 PyErr_Clear();
323 } else {
324 PyErr_Print();
325 }
326 #ifdef WXP_WITH_THREAD
327 PyEval_SaveThread();
328 wxPyInEvent = false;
329 #endif
330 }
331
332
333 //---------------------------------------------------------------------------
334
335 // wxPyMenu::wxPyMenu(const wxString& title, PyObject* _func)
336 // : wxMenu(title, (wxFunction)(func ? MenuCallback : NULL)), func(0) {
337
338 // if (_func) {
339 // func = _func;
340 // Py_INCREF(func);
341 // }
342 // }
343
344 // wxPyMenu::~wxPyMenu() {
345 // #ifdef WXP_WITH_THREAD
346 // //if (! wxPyInEvent)
347 // PyEval_RestoreThread(wxPyEventThreadState);
348 // #endif
349
350 // if (func)
351 // Py_DECREF(func);
352
353 // #ifdef WXP_WITH_THREAD
354 // //if (! wxPyInEvent)
355 // PyEval_SaveThread();
356 // #endif
357 // }
358
359
360 // void wxPyMenu::MenuCallback(wxMenu& menu, wxCommandEvent& evt) {
361 // PyObject* evtobj;
362 // PyObject* menuobj;
363 // PyObject* func;
364 // PyObject* args;
365 // PyObject* res;
366
367 // #ifdef WXP_WITH_THREAD
368 // PyEval_RestoreThread(wxPyEventThreadState);
369 // wxPyInEvent = true;
370 // #endif
371 // evtobj = wxPyConstructObject((void*)&evt, "wxCommandEvent");
372 // menuobj = wxPyConstructObject((void*)&menu, "wxMenu");
373 // if (PyErr_Occurred()) {
374 // // bail out if a problem
375 // PyErr_Print();
376 // goto done;
377 // }
378 // // Now call the callback...
379 // func = ((wxPyMenu*)&menu)->func;
380 // args = PyTuple_New(2);
381 // PyTuple_SET_ITEM(args, 0, menuobj);
382 // PyTuple_SET_ITEM(args, 1, evtobj);
383 // res = PyEval_CallObject(func, args);
384 // Py_DECREF(args);
385 // Py_XDECREF(res); /* In case res is a NULL pointer */
386 // done:
387 // #ifdef WXP_WITH_THREAD
388 // PyEval_SaveThread();
389 // wxPyInEvent = false;
390 // #endif
391 // return;
392 // }
393
394
395 //---------------------------------------------------------------------------
396
397 wxPyTimer::wxPyTimer(PyObject* callback) {
398 func = callback;
399 Py_INCREF(func);
400 }
401
402 wxPyTimer::~wxPyTimer() {
403 #ifdef WXP_WITH_THREAD
404 //if (! wxPyInEvent)
405 PyEval_RestoreThread(wxPyEventThreadState);
406 #endif
407
408 Py_DECREF(func);
409
410 #ifdef WXP_WITH_THREAD
411 //if (! wxPyInEvent)
412 PyEval_SaveThread();
413 #endif
414 }
415
416 void wxPyTimer::Notify() {
417 #ifdef WXP_WITH_THREAD
418 PyEval_RestoreThread(wxPyEventThreadState);
419 wxPyInEvent = true;
420 #endif
421 PyObject* result;
422 PyObject* args = Py_BuildValue("()");
423
424 result = PyEval_CallObject(func, args);
425 Py_DECREF(args);
426 if (result) {
427 Py_DECREF(result);
428 PyErr_Clear();
429 } else {
430 PyErr_Print();
431 }
432 #ifdef WXP_WITH_THREAD
433 PyEval_SaveThread();
434 wxPyInEvent = false;
435 #endif
436 }
437
438
439 //----------------------------------------------------------------------
440
441 IMPLEMENT_DYNAMIC_CLASS(wxPyEvent, wxCommandEvent)
442
443 wxPyEvent::wxPyEvent(wxEventType commandType, PyObject* userData)
444 : wxCommandEvent(commandType), m_userData(Py_None)
445 {
446 m_userData = userData;
447 if (m_userData != Py_None) {
448 Py_INCREF(m_userData);
449 }
450 }
451
452
453 wxPyEvent::~wxPyEvent() {
454 #ifdef WXP_WITH_THREAD
455 //if (! wxPyInEvent)
456 PyEval_RestoreThread(wxPyEventThreadState);
457 #endif
458 if (m_userData != Py_None) {
459 Py_DECREF(m_userData);
460 m_userData = Py_None;
461 }
462 #ifdef WXP_WITH_THREAD
463 //if (! wxPyInEvent)
464 PyEval_SaveThread();
465 #endif
466 }
467
468
469 void wxPyEvent::SetUserData(PyObject* userData) {
470 if (m_userData != Py_None) {
471 Py_DECREF(m_userData);
472 m_userData = Py_None;
473 }
474 m_userData = userData;
475 if (m_userData != Py_None) {
476 Py_INCREF(m_userData);
477 }
478 }
479
480
481 PyObject* wxPyEvent::GetUserData() {
482 return m_userData;
483 }
484
485 //----------------------------------------------------------------------
486 //----------------------------------------------------------------------
487 // Some helper functions for typemaps in my_typemaps.i, so they won't be
488 // imcluded in every file...
489
490
491 byte* byte_LIST_helper(PyObject* source) {
492 if (!PyList_Check(source)) {
493 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
494 return NULL;
495 }
496 int count = PyList_Size(source);
497 byte* temp = new byte[count];
498 if (! temp) {
499 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
500 return NULL;
501 }
502 for (int x=0; x<count; x++) {
503 PyObject* o = PyList_GetItem(source, x);
504 if (! PyInt_Check(o)) {
505 PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
506 return NULL;
507 }
508 temp[x] = (byte)PyInt_AsLong(o);
509 }
510 return temp;
511 }
512
513
514 int* int_LIST_helper(PyObject* source) {
515 if (!PyList_Check(source)) {
516 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
517 return NULL;
518 }
519 int count = PyList_Size(source);
520 int* temp = new int[count];
521 if (! temp) {
522 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
523 return NULL;
524 }
525 for (int x=0; x<count; x++) {
526 PyObject* o = PyList_GetItem(source, x);
527 if (! PyInt_Check(o)) {
528 PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
529 return NULL;
530 }
531 temp[x] = PyInt_AsLong(o);
532 }
533 return temp;
534 }
535
536
537 long* long_LIST_helper(PyObject* source) {
538 if (!PyList_Check(source)) {
539 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
540 return NULL;
541 }
542 int count = PyList_Size(source);
543 long* temp = new long[count];
544 if (! temp) {
545 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
546 return NULL;
547 }
548 for (int x=0; x<count; x++) {
549 PyObject* o = PyList_GetItem(source, x);
550 if (! PyInt_Check(o)) {
551 PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
552 return NULL;
553 }
554 temp[x] = PyInt_AsLong(o);
555 }
556 return temp;
557 }
558
559
560 char** string_LIST_helper(PyObject* source) {
561 if (!PyList_Check(source)) {
562 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
563 return NULL;
564 }
565 int count = PyList_Size(source);
566 char** temp = new char*[count];
567 if (! temp) {
568 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
569 return NULL;
570 }
571 for (int x=0; x<count; x++) {
572 PyObject* o = PyList_GetItem(source, x);
573 if (! PyString_Check(o)) {
574 PyErr_SetString(PyExc_TypeError, "Expected a list of strings.");
575 return NULL;
576 }
577 temp[x] = PyString_AsString(o);
578 }
579 return temp;
580 }
581
582
583
584 wxPoint* wxPoint_LIST_helper(PyObject* source) {
585 if (!PyList_Check(source)) {
586 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
587 return NULL;
588 }
589 int count = PyList_Size(source);
590 wxPoint* temp = new wxPoint[count];
591 if (! temp) {
592 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
593 return NULL;
594 }
595 for (int x=0; x<count; x++) {
596 PyObject* o = PyList_GetItem(source, x);
597 if (PyString_Check(o)) {
598 char* st = PyString_AsString(o);
599 wxPoint* pt;
600 if (SWIG_GetPtr(st,(void **) &pt,"_wxPoint_p")) {
601 PyErr_SetString(PyExc_TypeError,"Expected _wxPoint_p.");
602 return NULL;
603 }
604 temp[x] = *pt;
605 }
606 else if (PyTuple_Check(o)) {
607 PyObject* o1 = PyTuple_GetItem(o, 0);
608 PyObject* o2 = PyTuple_GetItem(o, 1);
609
610 temp[x].x = PyInt_AsLong(o1);
611 temp[x].y = PyInt_AsLong(o2);
612 }
613 else {
614 PyErr_SetString(PyExc_TypeError, "Expected a list of 2-tuples or wxPoints.");
615 return NULL;
616 }
617 }
618 return temp;
619 }
620
621
622 wxBitmap** wxBitmap_LIST_helper(PyObject* source) {
623 if (!PyList_Check(source)) {
624 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
625 return NULL;
626 }
627 int count = PyList_Size(source);
628 wxBitmap** temp = new wxBitmap*[count];
629 if (! temp) {
630 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
631 return NULL;
632 }
633 for (int x=0; x<count; x++) {
634 PyObject* o = PyList_GetItem(source, x);
635 if (PyString_Check(o)) {
636 char* st = PyString_AsString(o);
637 wxBitmap* pt;
638 if (SWIG_GetPtr(st,(void **) &pt,"_wxBitmap_p")) {
639 PyErr_SetString(PyExc_TypeError,"Expected _wxBitmap_p.");
640 return NULL;
641 }
642 temp[x] = pt;
643 }
644 else {
645 PyErr_SetString(PyExc_TypeError, "Expected a list of wxBitmaps.");
646 return NULL;
647 }
648 }
649 return temp;
650 }
651
652
653
654 wxString* wxString_LIST_helper(PyObject* source) {
655 if (!PyList_Check(source)) {
656 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
657 return NULL;
658 }
659 int count = PyList_Size(source);
660 wxString* temp = new wxString[count];
661 if (! temp) {
662 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
663 return NULL;
664 }
665 for (int x=0; x<count; x++) {
666 PyObject* o = PyList_GetItem(source, x);
667 if (! PyString_Check(o)) {
668 PyErr_SetString(PyExc_TypeError, "Expected a list of strings.");
669 return NULL;
670 }
671 temp[x] = PyString_AsString(o);
672 }
673 return temp;
674 }
675
676
677 wxAcceleratorEntry* wxAcceleratorEntry_LIST_helper(PyObject* source) {
678 if (!PyList_Check(source)) {
679 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
680 return NULL;
681 }
682 int count = PyList_Size(source);
683 wxAcceleratorEntry* temp = new wxAcceleratorEntry[count];
684 if (! temp) {
685 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
686 return NULL;
687 }
688 for (int x=0; x<count; x++) {
689 PyObject* o = PyList_GetItem(source, x);
690 if (PyString_Check(o)) {
691 char* st = PyString_AsString(o);
692 wxAcceleratorEntry* ae;
693 if (SWIG_GetPtr(st,(void **) &ae,"_wxAcceleratorEntry_p")) {
694 PyErr_SetString(PyExc_TypeError,"Expected _wxAcceleratorEntry_p.");
695 return NULL;
696 }
697 temp[x] = *ae;
698 }
699 else if (PyTuple_Check(o)) {
700 PyObject* o1 = PyTuple_GetItem(o, 0);
701 PyObject* o2 = PyTuple_GetItem(o, 1);
702 PyObject* o3 = PyTuple_GetItem(o, 2);
703
704 temp[x].m_flags = PyInt_AsLong(o1);
705 temp[x].m_keyCode = PyInt_AsLong(o2);
706 temp[x].m_command = PyInt_AsLong(o3);
707 }
708 else {
709 PyErr_SetString(PyExc_TypeError, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
710 return NULL;
711 }
712 }
713 return temp;
714 }
715
716
717
718 //----------------------------------------------------------------------
719 //----------------------------------------------------------------------
720
721 wxPyCallbackHelper::wxPyCallbackHelper() {
722 m_self = NULL;
723 m_lastFound = NULL;
724 }
725
726
727 wxPyCallbackHelper::~wxPyCallbackHelper() {
728 #ifdef WXP_WITH_THREAD
729 PyEval_RestoreThread(wxPyEventThreadState);
730 #endif
731
732 Py_XDECREF(m_self);
733
734 #ifdef WXP_WITH_THREAD
735 PyEval_SaveThread();
736 #endif
737 }
738
739 void wxPyCallbackHelper::setSelf(PyObject* self) {
740 m_self = self;
741 Py_INCREF(m_self);
742 }
743
744
745
746 bool wxPyCallbackHelper::findCallback(const wxString& name) {
747 m_lastFound = NULL;
748 if (m_self && PyObject_HasAttrString(m_self, (char*)name.c_str()))
749 m_lastFound = PyObject_GetAttrString(m_self, (char*)name.c_str());
750
751 return m_lastFound != NULL;
752 }
753
754
755 int wxPyCallbackHelper::callCallback(PyObject* argTuple) {
756 PyObject* result;
757 int retval = FALSE;
758
759 result = callCallbackObj(argTuple);
760 if (result) { // Assumes an integer return type...
761 retval = PyInt_AsLong(result);
762 Py_DECREF(result);
763 PyErr_Clear(); // forget about it if it's not...
764 }
765 #ifdef WXP_WITH_THREAD
766 PyEval_SaveThread();
767 #endif
768 return retval;
769 }
770
771 // Invoke the Python callable object, returning the raw PyObject return
772 // value. Caller should DECREF the return value and also call PyEval_SaveThread.
773 PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) {
774 #ifdef WXP_WITH_THREAD
775 PyEval_RestoreThread(wxPyEventThreadState);
776 #endif
777 PyObject* result;
778
779 result = PyEval_CallObject(m_lastFound, argTuple);
780 Py_DECREF(argTuple);
781 if (!result) {
782 PyErr_Print();
783 }
784 return result;
785 }
786
787
788
789
790 //----------------------------------------------------------------------
791 //----------------------------------------------------------------------
792 //----------------------------------------------------------------------
793
794
795