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