]> git.saurik.com Git - wxWidgets.git/blob - utils/wxPython/src/helpers.cpp
wxPython 2.1b1 for wxMSW (wxGTK coming soon)
[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 }
398
399
400 //---------------------------------------------------------------------------
401
402 wxPyTimer::wxPyTimer(PyObject* callback) {
403 func = callback;
404 Py_INCREF(func);
405 }
406
407 wxPyTimer::~wxPyTimer() {
408 #ifdef WXP_WITH_THREAD
409 //if (! wxPyInEvent)
410 PyEval_RestoreThread(wxPyEventThreadState);
411 #endif
412
413 Py_DECREF(func);
414
415 #ifdef WXP_WITH_THREAD
416 //if (! wxPyInEvent)
417 PyEval_SaveThread();
418 #endif
419 }
420
421 void wxPyTimer::Notify() {
422 #ifdef WXP_WITH_THREAD
423 PyEval_RestoreThread(wxPyEventThreadState);
424 wxPyInEvent = true;
425 #endif
426 PyObject* result;
427 PyObject* args = Py_BuildValue("()");
428
429 result = PyEval_CallObject(func, args);
430 Py_DECREF(args);
431 if (result) {
432 Py_DECREF(result);
433 PyErr_Clear();
434 } else {
435 PyErr_Print();
436 }
437 #ifdef WXP_WITH_THREAD
438 PyEval_SaveThread();
439 wxPyInEvent = false;
440 #endif
441 }
442
443
444 //----------------------------------------------------------------------
445
446 IMPLEMENT_DYNAMIC_CLASS(wxPyEvent, wxCommandEvent)
447
448 wxPyEvent::wxPyEvent(wxEventType commandType, PyObject* userData)
449 : wxCommandEvent(commandType), m_userData(Py_None)
450 {
451 m_userData = userData;
452 if (m_userData != Py_None) {
453 Py_INCREF(m_userData);
454 }
455 }
456
457
458 wxPyEvent::~wxPyEvent() {
459 #ifdef WXP_WITH_THREAD
460 //if (! wxPyInEvent)
461 PyEval_RestoreThread(wxPyEventThreadState);
462 #endif
463 if (m_userData != Py_None) {
464 Py_DECREF(m_userData);
465 m_userData = Py_None;
466 }
467 #ifdef WXP_WITH_THREAD
468 //if (! wxPyInEvent)
469 PyEval_SaveThread();
470 #endif
471 }
472
473
474 void wxPyEvent::SetUserData(PyObject* userData) {
475 if (m_userData != Py_None) {
476 Py_DECREF(m_userData);
477 m_userData = Py_None;
478 }
479 m_userData = userData;
480 if (m_userData != Py_None) {
481 Py_INCREF(m_userData);
482 }
483 }
484
485
486 PyObject* wxPyEvent::GetUserData() {
487 return m_userData;
488 }
489
490 //----------------------------------------------------------------------
491 //----------------------------------------------------------------------
492 // Some helper functions for typemaps in my_typemaps.i, so they won't be
493 // imcluded in every file...
494
495
496 byte* byte_LIST_helper(PyObject* source) {
497 if (!PyList_Check(source)) {
498 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
499 return NULL;
500 }
501 int count = PyList_Size(source);
502 byte* temp = new byte[count];
503 if (! temp) {
504 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
505 return NULL;
506 }
507 for (int x=0; x<count; x++) {
508 PyObject* o = PyList_GetItem(source, x);
509 if (! PyInt_Check(o)) {
510 PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
511 return NULL;
512 }
513 temp[x] = (byte)PyInt_AsLong(o);
514 }
515 return temp;
516 }
517
518
519 int* int_LIST_helper(PyObject* source) {
520 if (!PyList_Check(source)) {
521 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
522 return NULL;
523 }
524 int count = PyList_Size(source);
525 int* temp = new int[count];
526 if (! temp) {
527 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
528 return NULL;
529 }
530 for (int x=0; x<count; x++) {
531 PyObject* o = PyList_GetItem(source, x);
532 if (! PyInt_Check(o)) {
533 PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
534 return NULL;
535 }
536 temp[x] = PyInt_AsLong(o);
537 }
538 return temp;
539 }
540
541
542 long* long_LIST_helper(PyObject* source) {
543 if (!PyList_Check(source)) {
544 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
545 return NULL;
546 }
547 int count = PyList_Size(source);
548 long* temp = new long[count];
549 if (! temp) {
550 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
551 return NULL;
552 }
553 for (int x=0; x<count; x++) {
554 PyObject* o = PyList_GetItem(source, x);
555 if (! PyInt_Check(o)) {
556 PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
557 return NULL;
558 }
559 temp[x] = PyInt_AsLong(o);
560 }
561 return temp;
562 }
563
564
565 char** string_LIST_helper(PyObject* source) {
566 if (!PyList_Check(source)) {
567 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
568 return NULL;
569 }
570 int count = PyList_Size(source);
571 char** temp = new char*[count];
572 if (! temp) {
573 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
574 return NULL;
575 }
576 for (int x=0; x<count; x++) {
577 PyObject* o = PyList_GetItem(source, x);
578 if (! PyString_Check(o)) {
579 PyErr_SetString(PyExc_TypeError, "Expected a list of strings.");
580 return NULL;
581 }
582 temp[x] = PyString_AsString(o);
583 }
584 return temp;
585 }
586
587
588
589 wxPoint* wxPoint_LIST_helper(PyObject* source) {
590 if (!PyList_Check(source)) {
591 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
592 return NULL;
593 }
594 int count = PyList_Size(source);
595 wxPoint* temp = new wxPoint[count];
596 if (! temp) {
597 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
598 return NULL;
599 }
600 for (int x=0; x<count; x++) {
601 PyObject* o = PyList_GetItem(source, x);
602 if (PyString_Check(o)) {
603 char* st = PyString_AsString(o);
604 wxPoint* pt;
605 if (SWIG_GetPtr(st,(void **) &pt,"_wxPoint_p")) {
606 PyErr_SetString(PyExc_TypeError,"Expected _wxPoint_p.");
607 return NULL;
608 }
609 temp[x] = *pt;
610 }
611 else if (PyTuple_Check(o)) {
612 PyObject* o1 = PyTuple_GetItem(o, 0);
613 PyObject* o2 = PyTuple_GetItem(o, 1);
614
615 temp[x].x = PyInt_AsLong(o1);
616 temp[x].y = PyInt_AsLong(o2);
617 }
618 else {
619 PyErr_SetString(PyExc_TypeError, "Expected a list of 2-tuples or wxPoints.");
620 return NULL;
621 }
622 }
623 return temp;
624 }
625
626
627 wxBitmap** wxBitmap_LIST_helper(PyObject* source) {
628 if (!PyList_Check(source)) {
629 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
630 return NULL;
631 }
632 int count = PyList_Size(source);
633 wxBitmap** temp = new wxBitmap*[count];
634 if (! temp) {
635 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
636 return NULL;
637 }
638 for (int x=0; x<count; x++) {
639 PyObject* o = PyList_GetItem(source, x);
640 if (PyString_Check(o)) {
641 char* st = PyString_AsString(o);
642 wxBitmap* pt;
643 if (SWIG_GetPtr(st,(void **) &pt,"_wxBitmap_p")) {
644 PyErr_SetString(PyExc_TypeError,"Expected _wxBitmap_p.");
645 return NULL;
646 }
647 temp[x] = pt;
648 }
649 else {
650 PyErr_SetString(PyExc_TypeError, "Expected a list of wxBitmaps.");
651 return NULL;
652 }
653 }
654 return temp;
655 }
656
657
658
659 wxString* wxString_LIST_helper(PyObject* source) {
660 if (!PyList_Check(source)) {
661 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
662 return NULL;
663 }
664 int count = PyList_Size(source);
665 wxString* temp = new wxString[count];
666 if (! temp) {
667 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
668 return NULL;
669 }
670 for (int x=0; x<count; x++) {
671 PyObject* o = PyList_GetItem(source, x);
672 if (! PyString_Check(o)) {
673 PyErr_SetString(PyExc_TypeError, "Expected a list of strings.");
674 return NULL;
675 }
676 temp[x] = PyString_AsString(o);
677 }
678 return temp;
679 }
680
681
682 wxAcceleratorEntry* wxAcceleratorEntry_LIST_helper(PyObject* source) {
683 if (!PyList_Check(source)) {
684 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
685 return NULL;
686 }
687 int count = PyList_Size(source);
688 wxAcceleratorEntry* temp = new wxAcceleratorEntry[count];
689 if (! temp) {
690 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
691 return NULL;
692 }
693 for (int x=0; x<count; x++) {
694 PyObject* o = PyList_GetItem(source, x);
695 if (PyString_Check(o)) {
696 char* st = PyString_AsString(o);
697 wxAcceleratorEntry* ae;
698 if (SWIG_GetPtr(st,(void **) &ae,"_wxAcceleratorEntry_p")) {
699 PyErr_SetString(PyExc_TypeError,"Expected _wxAcceleratorEntry_p.");
700 return NULL;
701 }
702 temp[x] = *ae;
703 }
704 else if (PyTuple_Check(o)) {
705 PyObject* o1 = PyTuple_GetItem(o, 0);
706 PyObject* o2 = PyTuple_GetItem(o, 1);
707 PyObject* o3 = PyTuple_GetItem(o, 2);
708
709 temp[x].m_flags = PyInt_AsLong(o1);
710 temp[x].m_keyCode = PyInt_AsLong(o2);
711 temp[x].m_command = PyInt_AsLong(o3);
712 }
713 else {
714 PyErr_SetString(PyExc_TypeError, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
715 return NULL;
716 }
717 }
718 return temp;
719 }
720
721
722
723 //----------------------------------------------------------------------
724 //----------------------------------------------------------------------
725
726 wxPyCallbackHelper::wxPyCallbackHelper() {
727 m_self = NULL;
728 m_lastFound = NULL;
729 }
730
731
732 wxPyCallbackHelper::~wxPyCallbackHelper() {
733 #ifdef WXP_WITH_THREAD
734 PyEval_RestoreThread(wxPyEventThreadState);
735 #endif
736
737 Py_XDECREF(m_self);
738
739 #ifdef WXP_WITH_THREAD
740 PyEval_SaveThread();
741 #endif
742 }
743
744 void wxPyCallbackHelper::setSelf(PyObject* self) {
745 m_self = self;
746 Py_INCREF(m_self);
747 }
748
749
750
751 bool wxPyCallbackHelper::findCallback(const wxString& name) {
752 m_lastFound = NULL;
753 if (m_self && PyObject_HasAttrString(m_self, (char*)name.c_str()))
754 m_lastFound = PyObject_GetAttrString(m_self, (char*)name.c_str());
755
756 return m_lastFound != NULL;
757 }
758
759
760 int wxPyCallbackHelper::callCallback(PyObject* argTuple) {
761 PyObject* result;
762 int retval = FALSE;
763
764 result = callCallbackObj(argTuple);
765 if (result) { // Assumes an integer return type...
766 retval = PyInt_AsLong(result);
767 Py_DECREF(result);
768 PyErr_Clear(); // forget about it if it's not...
769 }
770 #ifdef WXP_WITH_THREAD
771 PyEval_SaveThread();
772 #endif
773 return retval;
774 }
775
776 // Invoke the Python callable object, returning the raw PyObject return
777 // value. Caller should DECREF the return value and also call PyEval_SaveThread.
778 PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) {
779 #ifdef WXP_WITH_THREAD
780 PyEval_RestoreThread(wxPyEventThreadState);
781 #endif
782 PyObject* result;
783
784 result = PyEval_CallObject(m_lastFound, argTuple);
785 Py_DECREF(argTuple);
786 if (!result) {
787 PyErr_Print();
788 }
789 return result;
790 }
791
792
793
794
795 //----------------------------------------------------------------------
796 //----------------------------------------------------------------------
797 //----------------------------------------------------------------------
798
799
800