]> git.saurik.com Git - wxWidgets.git/blame_incremental - wxPython/src/helpers.cpp
added SetStatusText method (avoiding dc.Clear)
[wxWidgets.git] / wxPython / src / helpers.cpp
... / ...
CommitLineData
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#include <stdio.h> // get the correct definition of NULL
14
15#undef DEBUG
16#include <Python.h>
17#include "helpers.h"
18
19#ifdef __WXMSW__
20#include <wx/msw/private.h>
21#include <wx/msw/winundef.h>
22#include <wx/msw/msvcrt.h>
23#endif
24
25#ifdef __WXGTK__
26#include <gtk/gtk.h>
27#include <gdk/gdkprivate.h>
28#include <wx/gtk/win_gtk.h>
29#endif
30
31
32//----------------------------------------------------------------------
33
34
35int WXDLLEXPORT wxEntryStart( int argc, char** argv );
36int WXDLLEXPORT wxEntryInitGui();
37void WXDLLEXPORT wxEntryCleanup();
38
39wxPyApp* wxPythonApp = NULL; // Global instance of application object
40
41
42#ifdef WXP_WITH_THREAD
43struct wxPyThreadState {
44 unsigned long tid;
45 PyThreadState* tstate;
46
47 wxPyThreadState(unsigned long _tid=0, PyThreadState* _tstate=NULL)
48 : tid(_tid), tstate(_tstate) {}
49};
50
51#include <wx/dynarray.h>
52WX_DECLARE_OBJARRAY(wxPyThreadState, wxPyThreadStateArray);
53#include <wx/arrimpl.cpp>
54WX_DEFINE_OBJARRAY(wxPyThreadStateArray);
55
56wxPyThreadStateArray* wxPyTStates = NULL;
57wxMutex* wxPyTMutex = NULL;
58#endif
59
60
61#ifdef __WXMSW__ // If building for win32...
62//----------------------------------------------------------------------
63// This gets run when the DLL is loaded. We just need to save a handle.
64//----------------------------------------------------------------------
65
66BOOL WINAPI DllMain(
67 HINSTANCE hinstDLL, // handle to DLL module
68 DWORD fdwReason, // reason for calling function
69 LPVOID lpvReserved // reserved
70 )
71{
72 wxSetInstance(hinstDLL);
73 return 1;
74}
75#endif
76
77//----------------------------------------------------------------------
78// Classes for implementing the wxp main application shell.
79//----------------------------------------------------------------------
80
81
82wxPyApp::wxPyApp() {
83// printf("**** ctor\n");
84}
85
86wxPyApp::~wxPyApp() {
87// printf("**** dtor\n");
88}
89
90
91// This one isn't acutally called... See __wxStart()
92bool wxPyApp::OnInit() {
93 return FALSE;
94}
95
96
97int wxPyApp::MainLoop() {
98 int retval = 0;
99
100 DeletePendingObjects();
101 bool initialized = wxTopLevelWindows.GetCount() != 0;
102#ifdef __WXGTK__
103 m_initialized = initialized;
104#endif
105
106 if (initialized) {
107 retval = wxApp::MainLoop();
108 OnExit();
109 }
110 return retval;
111}
112
113
114
115//---------------------------------------------------------------------
116//----------------------------------------------------------------------
117
118
119// This is where we pick up the first part of the wxEntry functionality...
120// The rest is in __wxStart and __wxCleanup. This function is called when
121// wxcmodule is imported. (Before there is a wxApp object.)
122void __wxPreStart()
123{
124
125#ifdef __WXMSW__
126 wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
127#endif
128
129#ifdef WXP_WITH_THREAD
130 PyEval_InitThreads();
131 wxPyTStates = new wxPyThreadStateArray;
132 wxPyTMutex = new wxMutex;
133#endif
134
135 // Bail out if there is already windows created. This means that the
136 // toolkit has already been initialized, as in embedding wxPython in
137 // a C++ wxWindows app.
138 if (wxTopLevelWindows.Number() > 0)
139 return;
140
141
142 int argc = 0;
143 char** argv = NULL;
144 PyObject* sysargv = PySys_GetObject("argv");
145 if (sysargv != NULL) {
146 argc = PyList_Size(sysargv);
147 argv = new char*[argc+1];
148 int x;
149 for(x=0; x<argc; x++)
150 argv[x] = copystring(PyString_AsString(PyList_GetItem(sysargv, x)));
151 argv[argc] = NULL;
152 }
153
154 wxEntryStart(argc, argv);
155 delete [] argv;
156}
157
158
159
160// Start the user application, user App's OnInit method is a parameter here
161PyObject* __wxStart(PyObject* /* self */, PyObject* args)
162{
163 PyObject* onInitFunc = NULL;
164 PyObject* arglist;
165 PyObject* result;
166 long bResult;
167
168 if (!PyArg_ParseTuple(args, "O", &onInitFunc))
169 return NULL;
170
171#if 0 // Try it out without this check, see how it does...
172 if (wxTopLevelWindows.Number() > 0) {
173 PyErr_SetString(PyExc_TypeError, "Only 1 wxApp per process!");
174 return NULL;
175 }
176#endif
177
178 // This is the next part of the wxEntry functionality...
179 int argc = 0;
180 char** argv = NULL;
181 PyObject* sysargv = PySys_GetObject("argv");
182 if (sysargv != NULL) {
183 argc = PyList_Size(sysargv);
184 argv = new char*[argc+1];
185 int x;
186 for(x=0; x<argc; x++)
187 argv[x] = copystring(PyString_AsString(PyList_GetItem(sysargv, x)));
188 argv[argc] = NULL;
189 }
190 wxPythonApp->argc = argc;
191 wxPythonApp->argv = argv;
192
193 wxEntryInitGui();
194
195 // Call the Python App's OnInit function
196 arglist = PyTuple_New(0);
197 result = PyEval_CallObject(onInitFunc, arglist);
198 if (!result) { // an exception was raised.
199 return NULL;
200 }
201
202 if (! PyInt_Check(result)) {
203 PyErr_SetString(PyExc_TypeError, "OnInit should return a boolean value");
204 return NULL;
205 }
206 bResult = PyInt_AS_LONG(result);
207 if (! bResult) {
208 PyErr_SetString(PyExc_SystemExit, "OnInit returned FALSE, exiting...");
209 return NULL;
210 }
211
212#ifdef __WXGTK__
213 wxTheApp->m_initialized = (wxTopLevelWindows.GetCount() > 0);
214#endif
215
216 Py_INCREF(Py_None);
217 return Py_None;
218}
219
220
221void __wxCleanup() {
222 wxEntryCleanup();
223 delete wxPyTMutex;
224 wxPyTMutex = NULL;
225 wxPyTStates->Empty();
226 delete wxPyTStates;
227 wxPyTStates = NULL;
228}
229
230
231
232static PyObject* wxPython_dict = NULL;
233static PyObject* wxPyPtrTypeMap = NULL;
234
235PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
236{
237
238 if (!PyArg_ParseTuple(args, "O", &wxPython_dict))
239 return NULL;
240
241 if (!PyDict_Check(wxPython_dict)) {
242 PyErr_SetString(PyExc_TypeError, "_wxSetDictionary must have dictionary object!");
243 return NULL;
244 }
245
246 if (! wxPyPtrTypeMap)
247 wxPyPtrTypeMap = PyDict_New();
248 PyDict_SetItemString(wxPython_dict, "__wxPyPtrTypeMap", wxPyPtrTypeMap);
249
250
251#ifdef __WXMOTIF__
252#define wxPlatform "__WXMOTIF__"
253#endif
254#ifdef __WXQT__
255#define wxPlatform "__WXQT__"
256#endif
257#ifdef __WXGTK__
258#define wxPlatform "__WXGTK__"
259#endif
260#if defined(__WIN32__) || defined(__WXMSW__)
261#define wxPlatform "__WXMSW__"
262#endif
263#ifdef __WXMAC__
264#define wxPlatform "__WXMAC__"
265#endif
266
267 PyDict_SetItemString(wxPython_dict, "wxPlatform", PyString_FromString(wxPlatform));
268
269 Py_INCREF(Py_None);
270 return Py_None;
271}
272
273
274//---------------------------------------------------------------------------
275// Stuff used by OOR to find the right wxPython class type to return and to
276// build it.
277
278
279// The pointer type map is used when the "pointer" type name generated by SWIG
280// is not the same as the shadow class name, for example wxPyTreeCtrl
281// vs. wxTreeCtrl. It needs to be referenced in Python as well as from C++,
282// so we'll just make it a Python dictionary in the wx module's namespace.
283void wxPyPtrTypeMap_Add(const char* commonName, const char* ptrName) {
284 if (! wxPyPtrTypeMap)
285 wxPyPtrTypeMap = PyDict_New();
286 PyDict_SetItemString(wxPyPtrTypeMap,
287 (char*)commonName,
288 PyString_FromString((char*)ptrName));
289}
290
291
292
293PyObject* wxPyClassExists(const char* className) {
294
295 if (!className)
296 return NULL;
297
298 char buff[64]; // should always be big enough...
299
300 sprintf(buff, "%sPtr", className);
301 PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff);
302
303 return classobj; // returns NULL if not found
304}
305
306
307PyObject* wxPyMake_wxObject(wxObject* source, bool checkEvtHandler) {
308 PyObject* target = NULL;
309 bool isEvtHandler = FALSE;
310
311 if (source) {
312 // If it's derived from wxEvtHandler then there may
313 // already be a pointer to a Python object that we can use
314 // in the OOR data.
315 if (checkEvtHandler && wxIsKindOf(source, wxEvtHandler)) {
316 isEvtHandler = TRUE;
317 wxEvtHandler* eh = (wxEvtHandler*)source;
318 wxPyClientData* data = (wxPyClientData*)eh->GetClientObject();
319 if (data) {
320 target = data->m_obj;
321 Py_INCREF(target);
322 }
323 }
324
325 if (! target) {
326 // Otherwise make it the old fashioned way by making a
327 // new shadow object and putting this pointer in it.
328 wxClassInfo* info = source->GetClassInfo();
329 wxChar* name = (wxChar*)info->GetClassName();
330 PyObject* klass = wxPyClassExists(name);
331 while (info && !klass) {
332 name = (wxChar*)info->GetBaseClassName1();
333 info = wxClassInfo::FindClass(name);
334 klass = wxPyClassExists(name);
335 }
336 if (info) {
337 target = wxPyConstructObject(source, name, klass, FALSE);
338 if (target && isEvtHandler)
339 ((wxEvtHandler*)source)->SetClientObject(new wxPyClientData(target));
340 } else {
341 wxString msg("wxPython class not found for ");
342 msg += source->GetClassInfo()->GetClassName();
343 PyErr_SetString(PyExc_NameError, msg.c_str());
344 target = NULL;
345 }
346 }
347 } else { // source was NULL so return None.
348 Py_INCREF(Py_None); target = Py_None;
349 }
350 return target;
351}
352
353
354PyObject* wxPyMake_wxSizer(wxSizer* source) {
355 PyObject* target = NULL;
356
357 if (source && wxIsKindOf(source, wxSizer)) {
358 // If it's derived from wxSizer then there may
359 // already be a pointer to a Python object that we can use
360 // in the OOR data.
361 wxSizer* sz = (wxSizer*)source;
362 wxPyClientData* data = (wxPyClientData*)sz->GetClientObject();
363 if (data) {
364 target = data->m_obj;
365 Py_INCREF(target);
366 }
367 }
368 if (! target) {
369 target = wxPyMake_wxObject(source, FALSE);
370 if (target != Py_None)
371 ((wxSizer*)source)->SetClientObject(new wxPyClientData(target));
372 }
373 return target;
374}
375
376
377
378//---------------------------------------------------------------------------
379
380PyObject* wxPyConstructObject(void* ptr,
381 const char* className,
382 PyObject* klass,
383 int setThisOwn) {
384
385 PyObject* obj;
386 PyObject* arg;
387 PyObject* item;
388 char swigptr[64]; // should always be big enough...
389 char buff[64];
390
391 if ((item = PyDict_GetItemString(wxPyPtrTypeMap, (char*)className)) != NULL) {
392 className = PyString_AsString(item);
393 }
394 sprintf(buff, "_%s_p", className);
395 SWIG_MakePtr(swigptr, ptr, buff);
396
397 arg = Py_BuildValue("(s)", swigptr);
398 obj = PyInstance_New(klass, arg, NULL);
399 Py_DECREF(arg);
400
401 if (setThisOwn) {
402 PyObject* one = PyInt_FromLong(1);
403 PyObject_SetAttrString(obj, "thisown", one);
404 Py_DECREF(one);
405 }
406
407 return obj;
408}
409
410
411PyObject* wxPyConstructObject(void* ptr,
412 const char* className,
413 int setThisOwn) {
414 PyObject* obj;
415
416 if (!ptr) {
417 Py_INCREF(Py_None);
418 return Py_None;
419 }
420
421 char buff[64]; // should always be big enough...
422 sprintf(buff, "%sPtr", className);
423
424 wxASSERT_MSG(wxPython_dict, "wxPython_dict is not set yet!!");
425
426 PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff);
427 if (! classobj) {
428 char temp[128];
429 sprintf(temp,
430 "*** Unknown class name %s, tell Robin about it please ***",
431 buff);
432 obj = PyString_FromString(temp);
433 return obj;
434 }
435
436 return wxPyConstructObject(ptr, className, classobj, setThisOwn);
437}
438
439//---------------------------------------------------------------------------
440
441// TODO: This should really be wxThread::GetCurrentId(), and I will do so
442// after I make a quick 2.3.2.1 release.
443#ifdef WXP_WITH_THREAD
444#ifdef __WXGTK__ // does wxGTK always use pthreads?
445#include <unistd.h>
446#include <pthread.h>
447#endif
448inline
449unsigned long wxPyGetCurrentThreadId() {
450#ifdef __WXMSW__
451 return (unsigned long)::GetCurrentThreadId();
452#endif
453#ifdef __WXGTK__ // does wxGTK always use pthreads?
454 return (unsigned long)pthread_self();
455#endif
456#ifdef __WXMAC__
457#error Fix this!
458#endif
459}
460
461
462
463static
464PyThreadState* wxPyGetThreadState() {
465 unsigned long ctid = wxPyGetCurrentThreadId();
466 PyThreadState* tstate = NULL;
467
468 wxPyTMutex->Lock();
469 for(size_t i=0; i < wxPyTStates->GetCount(); i++) {
470 wxPyThreadState& info = wxPyTStates->Item(i);
471 if (info.tid == ctid) {
472 tstate = info.tstate;
473 break;
474 }
475 }
476 wxPyTMutex->Unlock();
477 wxASSERT_MSG(tstate, "PyThreadState should not be NULL!");
478 return tstate;
479}
480
481static
482void wxPySaveThreadState(PyThreadState* tstate) {
483 unsigned long ctid = wxPyGetCurrentThreadId();
484 wxPyTMutex->Lock();
485 for(size_t i=0; i < wxPyTStates->GetCount(); i++) {
486 wxPyThreadState& info = wxPyTStates->Item(i);
487 if (info.tid == ctid) {
488 info.tstate = tstate;
489 wxPyTMutex->Unlock();
490 return;
491 }
492 }
493 // not found, so add it...
494 wxPyTStates->Add(new wxPyThreadState(ctid, tstate));
495 wxPyTMutex->Unlock();
496}
497
498#endif
499
500
501// Calls from Python to wxWindows code are wrapped in calls to these
502// functions:
503
504PyThreadState* wxPyBeginAllowThreads() {
505#ifdef WXP_WITH_THREAD
506 PyThreadState* saved = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS;
507 wxPySaveThreadState(saved);
508 return saved;
509#else
510 return NULL;
511#endif
512}
513
514void wxPyEndAllowThreads(PyThreadState* saved) {
515#ifdef WXP_WITH_THREAD
516 PyEval_RestoreThread(saved); // Py_END_ALLOW_THREADS;
517#endif
518}
519
520
521
522// Calls from wxWindows back to Python code, or even any PyObject
523// manipulations, PyDECREF's and etc. are wrapped in calls to these functions:
524
525void wxPyBeginBlockThreads() {
526#ifdef WXP_WITH_THREAD
527 PyThreadState* tstate = wxPyGetThreadState();
528 PyEval_RestoreThread(tstate);
529#endif
530}
531
532
533void wxPyEndBlockThreads() {
534#ifdef WXP_WITH_THREAD
535 PyThreadState* tstate = PyEval_SaveThread();
536 // Is there any need to save it again?
537#endif
538}
539
540
541//---------------------------------------------------------------------------
542
543IMPLEMENT_ABSTRACT_CLASS(wxPyCallback, wxObject);
544
545wxPyCallback::wxPyCallback(PyObject* func) {
546 m_func = func;
547 Py_INCREF(m_func);
548}
549
550wxPyCallback::wxPyCallback(const wxPyCallback& other) {
551 m_func = other.m_func;
552 Py_INCREF(m_func);
553}
554
555wxPyCallback::~wxPyCallback() {
556 wxPyBeginBlockThreads();
557 Py_DECREF(m_func);
558 wxPyEndBlockThreads();
559}
560
561
562
563// This function is used for all events destined for Python event handlers.
564void wxPyCallback::EventThunker(wxEvent& event) {
565 wxPyCallback* cb = (wxPyCallback*)event.m_callbackUserData;
566 PyObject* func = cb->m_func;
567 PyObject* result;
568 PyObject* arg;
569 PyObject* tuple;
570
571
572 wxPyBeginBlockThreads();
573 wxString className = event.GetClassInfo()->GetClassName();
574
575 if (className == "wxPyEvent")
576 arg = ((wxPyEvent*)&event)->GetSelf();
577 else if (className == "wxPyCommandEvent")
578 arg = ((wxPyCommandEvent*)&event)->GetSelf();
579 else
580 arg = wxPyConstructObject((void*)&event, className);
581
582 tuple = PyTuple_New(1);
583 PyTuple_SET_ITEM(tuple, 0, arg);
584 result = PyEval_CallObject(func, tuple);
585 Py_DECREF(tuple);
586 if (result) {
587 Py_DECREF(result);
588 PyErr_Clear(); // Just in case...
589 } else {
590 PyErr_Print();
591 }
592 wxPyEndBlockThreads();
593}
594
595
596//----------------------------------------------------------------------
597
598wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper& other) {
599 m_lastFound = NULL;
600 m_self = other.m_self;
601 m_class = other.m_class;
602 if (m_self) {
603 Py_INCREF(m_self);
604 Py_INCREF(m_class);
605 }
606}
607
608
609void wxPyCallbackHelper::setSelf(PyObject* self, PyObject* klass, int incref) {
610 m_self = self;
611 m_class = klass;
612 m_incRef = incref;
613 if (incref) {
614 Py_INCREF(m_self);
615 Py_INCREF(m_class);
616 }
617}
618
619
620#if PYTHON_API_VERSION >= 1011
621
622// Prior to Python 2.2 PyMethod_GetClass returned the class object
623// in which the method was defined. Starting with 2.2 it returns
624// "class that asked for the method" which seems totally bogus to me
625// but apprently if fixes some obscure problem waiting to happen in
626// Python. Since the API was not documented Guido and the gang felt
627// safe in changing it. Needless to say that totally screwed up the
628// logic below in wxPyCallbackHelper::findCallback, hence this icky
629// code to find the class where the method is actuallt defined...
630
631static
632PyObject* PyFindClassWithAttr(PyObject *klass, PyObject *name)
633{
634 int i, n;
635
636 if (PyType_Check(klass)) { // new style classes
637 // This code is borrowed/adapted from _PyType_Lookup in typeobject.c
638 // (TODO: This part is not tested yet, so I'm not sure it is correct...)
639 PyTypeObject* type = (PyTypeObject*)klass;
640 PyObject *mro, *res, *base, *dict;
641 /* Look in tp_dict of types in MRO */
642 mro = type->tp_mro;
643 assert(PyTuple_Check(mro));
644 n = PyTuple_GET_SIZE(mro);
645 for (i = 0; i < n; i++) {
646 base = PyTuple_GET_ITEM(mro, i);
647 if (PyClass_Check(base))
648 dict = ((PyClassObject *)base)->cl_dict;
649 else {
650 assert(PyType_Check(base));
651 dict = ((PyTypeObject *)base)->tp_dict;
652 }
653 assert(dict && PyDict_Check(dict));
654 res = PyDict_GetItem(dict, name);
655 if (res != NULL)
656 return base;
657 }
658 return NULL;
659 }
660
661 else if (PyClass_Check(klass)) { // old style classes
662 // This code is borrowed/adapted from class_lookup in classobject.c
663 PyClassObject* cp = (PyClassObject*)klass;
664 PyObject *value = PyDict_GetItem(cp->cl_dict, name);
665 if (value != NULL) {
666 return (PyObject*)cp;
667 }
668 n = PyTuple_Size(cp->cl_bases);
669 for (i = 0; i < n; i++) {
670 PyObject* base = PyTuple_GetItem(cp->cl_bases, i);
671 PyObject *v = PyFindClassWithAttr(base, name);
672 if (v != NULL)
673 return v;
674 }
675 return NULL;
676 }
677}
678#endif
679
680
681static
682PyObject* PyMethod_GetDefiningClass(PyObject* method, const char* name)
683{
684 PyObject* mgc = PyMethod_GET_CLASS(method);
685
686#if PYTHON_API_VERSION <= 1010 // prior to Python 2.2, the easy way
687 return mgc;
688#else // 2.2 and after, the hard way...
689
690 PyObject* nameo = PyString_FromString(name);
691 PyObject* klass = PyFindClassWithAttr(mgc, nameo);
692 Py_DECREF(nameo);
693 return klass;
694#endif
695}
696
697
698
699bool wxPyCallbackHelper::findCallback(const char* name) const {
700 wxPyCallbackHelper* self = (wxPyCallbackHelper*)this; // cast away const
701 self->m_lastFound = NULL;
702
703 // If the object (m_self) has an attibute of the given name...
704 if (m_self && PyObject_HasAttrString(m_self, (char*)name)) {
705 PyObject *method, *klass;
706 method = PyObject_GetAttrString(m_self, (char*)name);
707
708 // ...and if that attribute is a method, and if that method's class is
709 // not from a base class...
710 if (PyMethod_Check(method) &&
711 (klass = PyMethod_GetDefiningClass(method, (char*)name)) != NULL &&
712 ((klass == m_class) || PyClass_IsSubclass(klass, m_class))) {
713
714 // ...then we'll save a pointer to the method so callCallback can call it.
715 self->m_lastFound = method;
716 }
717 else {
718 Py_DECREF(method);
719 }
720 }
721 return m_lastFound != NULL;
722}
723
724
725int wxPyCallbackHelper::callCallback(PyObject* argTuple) const {
726 PyObject* result;
727 int retval = FALSE;
728
729 result = callCallbackObj(argTuple);
730 if (result) { // Assumes an integer return type...
731 retval = PyInt_AsLong(result);
732 Py_DECREF(result);
733 PyErr_Clear(); // forget about it if it's not...
734 }
735 return retval;
736}
737
738// Invoke the Python callable object, returning the raw PyObject return
739// value. Caller should DECREF the return value and also call PyEval_SaveThread.
740PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) const {
741 PyObject* result;
742
743 // Save a copy of the pointer in case the callback generates another
744 // callback. In that case m_lastFound will have a different value when
745 // it gets back here...
746 PyObject* method = m_lastFound;
747
748 result = PyEval_CallObject(method, argTuple);
749 Py_DECREF(argTuple);
750 Py_DECREF(method);
751 if (!result) {
752 PyErr_Print();
753 }
754 return result;
755}
756
757
758void wxPyCBH_setCallbackInfo(wxPyCallbackHelper& cbh, PyObject* self, PyObject* klass, int incref) {
759 cbh.setSelf(self, klass, incref);
760}
761
762bool wxPyCBH_findCallback(const wxPyCallbackHelper& cbh, const char* name) {
763 return cbh.findCallback(name);
764}
765
766int wxPyCBH_callCallback(const wxPyCallbackHelper& cbh, PyObject* argTuple) {
767 return cbh.callCallback(argTuple);
768}
769
770PyObject* wxPyCBH_callCallbackObj(const wxPyCallbackHelper& cbh, PyObject* argTuple) {
771 return cbh.callCallbackObj(argTuple);
772}
773
774
775void wxPyCBH_delete(wxPyCallbackHelper* cbh) {
776 if (cbh->m_incRef) {
777 wxPyBeginBlockThreads();
778 Py_XDECREF(cbh->m_self);
779 Py_XDECREF(cbh->m_class);
780 wxPyEndBlockThreads();
781 }
782}
783
784//---------------------------------------------------------------------------
785//---------------------------------------------------------------------------
786// These event classes can be derived from in Python and passed through the event
787// system without losing anything. They do this by keeping a reference to
788// themselves and some special case handling in wxPyCallback::EventThunker.
789
790
791wxPyEvtSelfRef::wxPyEvtSelfRef() {
792 //m_self = Py_None; // **** We don't do normal ref counting to prevent
793 //Py_INCREF(m_self); // circular loops...
794 m_cloned = FALSE;
795}
796
797wxPyEvtSelfRef::~wxPyEvtSelfRef() {
798 wxPyBeginBlockThreads();
799 if (m_cloned)
800 Py_DECREF(m_self);
801 wxPyEndBlockThreads();
802}
803
804void wxPyEvtSelfRef::SetSelf(PyObject* self, bool clone) {
805 wxPyBeginBlockThreads();
806 if (m_cloned)
807 Py_DECREF(m_self);
808 m_self = self;
809 if (clone) {
810 Py_INCREF(m_self);
811 m_cloned = TRUE;
812 }
813 wxPyEndBlockThreads();
814}
815
816PyObject* wxPyEvtSelfRef::GetSelf() const {
817 Py_INCREF(m_self);
818 return m_self;
819}
820
821
822IMPLEMENT_ABSTRACT_CLASS(wxPyEvent, wxEvent);
823IMPLEMENT_ABSTRACT_CLASS(wxPyCommandEvent, wxCommandEvent);
824
825
826wxPyEvent::wxPyEvent(int id)
827 : wxEvent(id) {
828}
829
830
831wxPyEvent::wxPyEvent(const wxPyEvent& evt)
832 : wxEvent(evt)
833{
834 SetSelf(evt.m_self, TRUE);
835}
836
837
838wxPyEvent::~wxPyEvent() {
839}
840
841
842wxPyCommandEvent::wxPyCommandEvent(wxEventType commandType, int id)
843 : wxCommandEvent(commandType, id) {
844}
845
846
847wxPyCommandEvent::wxPyCommandEvent(const wxPyCommandEvent& evt)
848 : wxCommandEvent(evt)
849{
850 SetSelf(evt.m_self, TRUE);
851}
852
853
854wxPyCommandEvent::~wxPyCommandEvent() {
855}
856
857
858
859
860//---------------------------------------------------------------------------
861//---------------------------------------------------------------------------
862
863
864wxPyTimer::wxPyTimer(PyObject* callback) {
865 func = callback;
866 Py_INCREF(func);
867}
868
869wxPyTimer::~wxPyTimer() {
870 wxPyBeginBlockThreads();
871 Py_DECREF(func);
872 wxPyEndBlockThreads();
873}
874
875void wxPyTimer::Notify() {
876 if (!func || func == Py_None) {
877 wxTimer::Notify();
878 }
879 else {
880 wxPyBeginBlockThreads();
881
882 PyObject* result;
883 PyObject* args = Py_BuildValue("()");
884
885 result = PyEval_CallObject(func, args);
886 Py_DECREF(args);
887 if (result) {
888 Py_DECREF(result);
889 PyErr_Clear();
890 } else {
891 PyErr_Print();
892 }
893
894 wxPyEndBlockThreads();
895 }
896}
897
898
899
900//---------------------------------------------------------------------------
901//---------------------------------------------------------------------------
902// Convert a wxList to a Python List
903
904PyObject* wxPy_ConvertList(wxListBase* list, const char* className) {
905 PyObject* pyList;
906 PyObject* pyObj;
907 wxObject* wxObj;
908 wxNode* node = list->First();
909
910 wxPyBeginBlockThreads();
911 pyList = PyList_New(0);
912 while (node) {
913 wxObj = node->Data();
914 pyObj = wxPyMake_wxObject(wxObj); //wxPyConstructObject(wxObj, className);
915 PyList_Append(pyList, pyObj);
916 node = node->Next();
917 }
918 wxPyEndBlockThreads();
919 return pyList;
920}
921
922//----------------------------------------------------------------------
923
924long wxPyGetWinHandle(wxWindow* win) {
925#ifdef __WXMSW__
926 return (long)win->GetHandle();
927#endif
928
929 // Find and return the actual X-Window.
930#ifdef __WXGTK__
931 if (win->m_wxwindow) {
932 GdkWindowPrivate* bwin = (GdkWindowPrivate*)GTK_PIZZA(win->m_wxwindow)->bin_window;
933 if (bwin) {
934 return (long)bwin->xwindow;
935 }
936 }
937#endif
938 return 0;
939}
940
941//----------------------------------------------------------------------
942// Some helper functions for typemaps in my_typemaps.i, so they won't be
943// included in every file...
944
945
946byte* byte_LIST_helper(PyObject* source) {
947 if (!PyList_Check(source)) {
948 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
949 return NULL;
950 }
951 int count = PyList_Size(source);
952 byte* temp = new byte[count];
953 if (! temp) {
954 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
955 return NULL;
956 }
957 for (int x=0; x<count; x++) {
958 PyObject* o = PyList_GetItem(source, x);
959 if (! PyInt_Check(o)) {
960 PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
961 return NULL;
962 }
963 temp[x] = (byte)PyInt_AsLong(o);
964 }
965 return temp;
966}
967
968
969int* int_LIST_helper(PyObject* source) {
970 if (!PyList_Check(source)) {
971 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
972 return NULL;
973 }
974 int count = PyList_Size(source);
975 int* temp = new int[count];
976 if (! temp) {
977 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
978 return NULL;
979 }
980 for (int x=0; x<count; x++) {
981 PyObject* o = PyList_GetItem(source, x);
982 if (! PyInt_Check(o)) {
983 PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
984 return NULL;
985 }
986 temp[x] = PyInt_AsLong(o);
987 }
988 return temp;
989}
990
991
992long* long_LIST_helper(PyObject* source) {
993 if (!PyList_Check(source)) {
994 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
995 return NULL;
996 }
997 int count = PyList_Size(source);
998 long* temp = new long[count];
999 if (! temp) {
1000 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
1001 return NULL;
1002 }
1003 for (int x=0; x<count; x++) {
1004 PyObject* o = PyList_GetItem(source, x);
1005 if (! PyInt_Check(o)) {
1006 PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
1007 return NULL;
1008 }
1009 temp[x] = PyInt_AsLong(o);
1010 }
1011 return temp;
1012}
1013
1014
1015char** string_LIST_helper(PyObject* source) {
1016 if (!PyList_Check(source)) {
1017 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
1018 return NULL;
1019 }
1020 int count = PyList_Size(source);
1021 char** temp = new char*[count];
1022 if (! temp) {
1023 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
1024 return NULL;
1025 }
1026 for (int x=0; x<count; x++) {
1027 PyObject* o = PyList_GetItem(source, x);
1028 if (! PyString_Check(o)) {
1029 PyErr_SetString(PyExc_TypeError, "Expected a list of strings.");
1030 return NULL;
1031 }
1032 temp[x] = PyString_AsString(o);
1033 }
1034 return temp;
1035}
1036
1037//--------------------------------
1038// Part of patch from Tim Hochberg
1039static inline bool wxPointFromObjects(PyObject* o1, PyObject* o2, wxPoint* point) {
1040 if (PyInt_Check(o1) && PyInt_Check(o2)) {
1041 point->x = PyInt_AS_LONG(o1);
1042 point->y = PyInt_AS_LONG(o2);
1043 return true;
1044 }
1045 if (PyFloat_Check(o1) && PyFloat_Check(o2)) {
1046 point->x = (int)PyFloat_AS_DOUBLE(o1);
1047 point->y = (int)PyFloat_AS_DOUBLE(o2);
1048 return true;
1049 }
1050 if (PyInstance_Check(o1) || PyInstance_Check(o2)) {
1051 // Disallow instances because they can cause havok
1052 return false;
1053 }
1054 if (PyNumber_Check(o1) && PyNumber_Check(o2)) {
1055 // I believe this excludes instances, so this should be safe without INCREFFing o1 and o2
1056 point->x = PyInt_AsLong(o1);
1057 point->y = PyInt_AsLong(o2);
1058 return true;
1059 }
1060 return false;
1061}
1062
1063
1064wxPoint* wxPoint_LIST_helper(PyObject* source, int *count) {
1065 // Putting all of the declarations here allows
1066 // us to put the error handling all in one place.
1067 int x;
1068 wxPoint* temp;
1069 PyObject *o, *o1, *o2;
1070 bool isFast = PyList_Check(source) || PyTuple_Check(source);
1071
1072 if (!PySequence_Check(source)) {
1073 goto error0;
1074 }
1075
1076 // The length of the sequence is returned in count.
1077 *count = PySequence_Length(source);
1078 if (*count < 0) {
1079 goto error0;
1080 }
1081
1082 temp = new wxPoint[*count];
1083 if (!temp) {
1084 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
1085 return NULL;
1086 }
1087 for (x=0; x<*count; x++) {
1088 // Get an item: try fast way first.
1089 if (isFast) {
1090 o = PySequence_Fast_GET_ITEM(source, x);
1091 }
1092 else {
1093 o = PySequence_GetItem(source, x);
1094 if (o == NULL) {
1095 goto error1;
1096 }
1097 }
1098
1099 // Convert o to wxPoint.
1100 if ((PyTuple_Check(o) && PyTuple_GET_SIZE(o) == 2) ||
1101 (PyList_Check(o) && PyList_GET_SIZE(o) == 2)) {
1102 o1 = PySequence_Fast_GET_ITEM(o, 0);
1103 o2 = PySequence_Fast_GET_ITEM(o, 1);
1104 if (!wxPointFromObjects(o1, o2, &temp[x])) {
1105 goto error2;
1106 }
1107 }
1108 else if (PyInstance_Check(o)) {
1109 wxPoint* pt;
1110 if (SWIG_GetPtrObj(o, (void **)&pt, "_wxPoint_p")) {
1111 goto error2;
1112 }
1113 temp[x] = *pt;
1114 }
1115 else if (PySequence_Check(o) && PySequence_Length(o) == 2) {
1116 o1 = PySequence_GetItem(o, 0);
1117 o2 = PySequence_GetItem(o, 1);
1118 if (!wxPointFromObjects(o1, o2, &temp[x])) {
1119 goto error3;
1120 }
1121 Py_DECREF(o1);
1122 Py_DECREF(o2);
1123 }
1124 else {
1125 goto error2;
1126 }
1127 // Clean up.
1128 if (!isFast)
1129 Py_DECREF(o);
1130 }
1131 return temp;
1132
1133error3:
1134 Py_DECREF(o1);
1135 Py_DECREF(o2);
1136error2:
1137 if (!isFast)
1138 Py_DECREF(o);
1139error1:
1140 delete temp;
1141error0:
1142 PyErr_SetString(PyExc_TypeError, "Expected a sequence of length-2 sequences or wxPoints.");
1143 return NULL;
1144}
1145// end of patch
1146//------------------------------
1147
1148
1149wxBitmap** wxBitmap_LIST_helper(PyObject* source) {
1150 if (!PyList_Check(source)) {
1151 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
1152 return NULL;
1153 }
1154 int count = PyList_Size(source);
1155 wxBitmap** temp = new wxBitmap*[count];
1156 if (! temp) {
1157 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
1158 return NULL;
1159 }
1160 for (int x=0; x<count; x++) {
1161 PyObject* o = PyList_GetItem(source, x);
1162 if (PyInstance_Check(o)) {
1163 wxBitmap* pt;
1164 if (SWIG_GetPtrObj(o, (void **) &pt,"_wxBitmap_p")) {
1165 PyErr_SetString(PyExc_TypeError,"Expected _wxBitmap_p.");
1166 return NULL;
1167 }
1168 temp[x] = pt;
1169 }
1170 else {
1171 PyErr_SetString(PyExc_TypeError, "Expected a list of wxBitmaps.");
1172 return NULL;
1173 }
1174 }
1175 return temp;
1176}
1177
1178
1179
1180wxString* wxString_LIST_helper(PyObject* source) {
1181 if (!PyList_Check(source)) {
1182 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
1183 return NULL;
1184 }
1185 int count = PyList_Size(source);
1186 wxString* temp = new wxString[count];
1187 if (! temp) {
1188 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
1189 return NULL;
1190 }
1191 for (int x=0; x<count; x++) {
1192 PyObject* o = PyList_GetItem(source, x);
1193#if PYTHON_API_VERSION >= 1009
1194 if (! PyString_Check(o) && ! PyUnicode_Check(o)) {
1195 PyErr_SetString(PyExc_TypeError, "Expected a list of string or unicode objects.");
1196 return NULL;
1197 }
1198
1199 char* buff;
1200 int length;
1201 if (PyString_AsStringAndSize(o, &buff, &length) == -1)
1202 return NULL;
1203 temp[x] = wxString(buff, length);
1204#else
1205 if (! PyString_Check(o)) {
1206 PyErr_SetString(PyExc_TypeError, "Expected a list of strings.");
1207 return NULL;
1208 }
1209 temp[x] = PyString_AsString(o);
1210#endif
1211 }
1212 return temp;
1213}
1214
1215
1216wxAcceleratorEntry* wxAcceleratorEntry_LIST_helper(PyObject* source) {
1217 if (!PyList_Check(source)) {
1218 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
1219 return NULL;
1220 }
1221 int count = PyList_Size(source);
1222 wxAcceleratorEntry* temp = new wxAcceleratorEntry[count];
1223 if (! temp) {
1224 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
1225 return NULL;
1226 }
1227 for (int x=0; x<count; x++) {
1228 PyObject* o = PyList_GetItem(source, x);
1229 if (PyInstance_Check(o)) {
1230 wxAcceleratorEntry* ae;
1231 if (SWIG_GetPtrObj(o, (void **) &ae,"_wxAcceleratorEntry_p")) {
1232 PyErr_SetString(PyExc_TypeError,"Expected _wxAcceleratorEntry_p.");
1233 return NULL;
1234 }
1235 temp[x] = *ae;
1236 }
1237 else if (PyTuple_Check(o)) {
1238 PyObject* o1 = PyTuple_GetItem(o, 0);
1239 PyObject* o2 = PyTuple_GetItem(o, 1);
1240 PyObject* o3 = PyTuple_GetItem(o, 2);
1241 temp[x].Set(PyInt_AsLong(o1), PyInt_AsLong(o2), PyInt_AsLong(o3));
1242 }
1243 else {
1244 PyErr_SetString(PyExc_TypeError, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
1245 return NULL;
1246 }
1247 }
1248 return temp;
1249}
1250
1251
1252wxPen** wxPen_LIST_helper(PyObject* source) {
1253 if (!PyList_Check(source)) {
1254 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
1255 return NULL;
1256 }
1257 int count = PyList_Size(source);
1258 wxPen** temp = new wxPen*[count];
1259 if (!temp) {
1260 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
1261 return NULL;
1262 }
1263 for (int x=0; x<count; x++) {
1264 PyObject* o = PyList_GetItem(source, x);
1265 if (PyInstance_Check(o)) {
1266 wxPen* pt;
1267 if (SWIG_GetPtrObj(o, (void **) &pt,"_wxPen_p")) {
1268 delete temp;
1269 PyErr_SetString(PyExc_TypeError,"Expected _wxPen_p.");
1270 return NULL;
1271 }
1272 temp[x] = pt;
1273 }
1274 else {
1275 delete temp;
1276 PyErr_SetString(PyExc_TypeError, "Expected a list of wxPens.");
1277 return NULL;
1278 }
1279 }
1280 return temp;
1281}
1282
1283
1284bool _2int_seq_helper(PyObject* source, int* i1, int* i2) {
1285 bool isFast = PyList_Check(source) || PyTuple_Check(source);
1286 PyObject *o1, *o2;
1287
1288 if (!PySequence_Check(source) || PySequence_Length(source) != 2)
1289 return FALSE;
1290
1291 if (isFast) {
1292 o1 = PySequence_Fast_GET_ITEM(source, 0);
1293 o2 = PySequence_Fast_GET_ITEM(source, 1);
1294 }
1295 else {
1296 o1 = PySequence_GetItem(source, 0);
1297 o2 = PySequence_GetItem(source, 1);
1298 }
1299
1300 *i1 = PyInt_AsLong(o1);
1301 *i2 = PyInt_AsLong(o2);
1302
1303 if (! isFast) {
1304 Py_DECREF(o1);
1305 Py_DECREF(o2);
1306 }
1307 return TRUE;
1308}
1309
1310
1311bool _4int_seq_helper(PyObject* source, int* i1, int* i2, int* i3, int* i4) {
1312 bool isFast = PyList_Check(source) || PyTuple_Check(source);
1313 PyObject *o1, *o2, *o3, *o4;
1314
1315 if (!PySequence_Check(source) || PySequence_Length(source) != 4)
1316 return FALSE;
1317
1318 if (isFast) {
1319 o1 = PySequence_Fast_GET_ITEM(source, 0);
1320 o2 = PySequence_Fast_GET_ITEM(source, 1);
1321 o3 = PySequence_Fast_GET_ITEM(source, 2);
1322 o4 = PySequence_Fast_GET_ITEM(source, 3);
1323 }
1324 else {
1325 o1 = PySequence_GetItem(source, 0);
1326 o2 = PySequence_GetItem(source, 1);
1327 o3 = PySequence_GetItem(source, 2);
1328 o4 = PySequence_GetItem(source, 3);
1329 }
1330
1331 *i1 = PyInt_AsLong(o1);
1332 *i2 = PyInt_AsLong(o2);
1333 *i3 = PyInt_AsLong(o3);
1334 *i4 = PyInt_AsLong(o4);
1335
1336 if (! isFast) {
1337 Py_DECREF(o1);
1338 Py_DECREF(o2);
1339 Py_DECREF(o3);
1340 Py_DECREF(o4);
1341 }
1342 return TRUE;
1343}
1344
1345
1346//----------------------------------------------------------------------
1347
1348bool wxSize_helper(PyObject* source, wxSize** obj) {
1349
1350 // If source is an object instance then it may already be the right type
1351 if (PyInstance_Check(source)) {
1352 wxSize* ptr;
1353 if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxSize_p"))
1354 goto error;
1355 *obj = ptr;
1356 return TRUE;
1357 }
1358 // otherwise a 2-tuple of integers is expected
1359 else if (PySequence_Check(source) && PyObject_Length(source) == 2) {
1360 PyObject* o1 = PySequence_GetItem(source, 0);
1361 PyObject* o2 = PySequence_GetItem(source, 1);
1362 **obj = wxSize(PyInt_AsLong(o1), PyInt_AsLong(o2));
1363 return TRUE;
1364 }
1365
1366 error:
1367 PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of integers or a wxSize object.");
1368 return FALSE;
1369}
1370
1371bool wxPoint_helper(PyObject* source, wxPoint** obj) {
1372
1373 // If source is an object instance then it may already be the right type
1374 if (PyInstance_Check(source)) {
1375 wxPoint* ptr;
1376 if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxPoint_p"))
1377 goto error;
1378 *obj = ptr;
1379 return TRUE;
1380 }
1381 // otherwise a length-2 sequence of integers is expected
1382 if (PySequence_Check(source) && PySequence_Length(source) == 2) {
1383 PyObject* o1 = PySequence_GetItem(source, 0);
1384 PyObject* o2 = PySequence_GetItem(source, 1);
1385 // This should really check for integers, not numbers -- but that would break code.
1386 if (!PyNumber_Check(o1) || !PyNumber_Check(o2)) {
1387 Py_DECREF(o1);
1388 Py_DECREF(o2);
1389 goto error;
1390 }
1391 **obj = wxPoint(PyInt_AsLong(o1), PyInt_AsLong(o2));
1392 Py_DECREF(o1);
1393 Py_DECREF(o2);
1394 return TRUE;
1395 }
1396 error:
1397 PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of integers or a wxPoint object.");
1398 return FALSE;
1399}
1400
1401
1402
1403bool wxRealPoint_helper(PyObject* source, wxRealPoint** obj) {
1404
1405 // If source is an object instance then it may already be the right type
1406 if (PyInstance_Check(source)) {
1407 wxRealPoint* ptr;
1408 if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxRealPoint_p"))
1409 goto error;
1410 *obj = ptr;
1411 return TRUE;
1412 }
1413 // otherwise a 2-tuple of floats is expected
1414 else if (PySequence_Check(source) && PyObject_Length(source) == 2) {
1415 PyObject* o1 = PySequence_GetItem(source, 0);
1416 PyObject* o2 = PySequence_GetItem(source, 1);
1417 **obj = wxRealPoint(PyFloat_AsDouble(o1), PyFloat_AsDouble(o2));
1418 return TRUE;
1419 }
1420
1421 error:
1422 PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of floats or a wxRealPoint object.");
1423 return FALSE;
1424}
1425
1426
1427
1428
1429bool wxRect_helper(PyObject* source, wxRect** obj) {
1430
1431 // If source is an object instance then it may already be the right type
1432 if (PyInstance_Check(source)) {
1433 wxRect* ptr;
1434 if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxRect_p"))
1435 goto error;
1436 *obj = ptr;
1437 return TRUE;
1438 }
1439 // otherwise a 4-tuple of integers is expected
1440 else if (PySequence_Check(source) && PyObject_Length(source) == 4) {
1441 PyObject* o1 = PySequence_GetItem(source, 0);
1442 PyObject* o2 = PySequence_GetItem(source, 1);
1443 PyObject* o3 = PySequence_GetItem(source, 2);
1444 PyObject* o4 = PySequence_GetItem(source, 3);
1445 **obj = wxRect(PyInt_AsLong(o1), PyInt_AsLong(o2),
1446 PyInt_AsLong(o3), PyInt_AsLong(o4));
1447 return TRUE;
1448 }
1449
1450 error:
1451 PyErr_SetString(PyExc_TypeError, "Expected a 4-tuple of integers or a wxRect object.");
1452 return FALSE;
1453}
1454
1455
1456
1457bool wxColour_helper(PyObject* source, wxColour** obj) {
1458
1459 // If source is an object instance then it may already be the right type
1460 if (PyInstance_Check(source)) {
1461 wxColour* ptr;
1462 if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxColour_p"))
1463 goto error;
1464 *obj = ptr;
1465 return TRUE;
1466 }
1467 // otherwise a string is expected
1468 else if (PyString_Check(source)) {
1469 wxString spec = PyString_AS_STRING(source);
1470 if (spec[0U] == '#' && spec.Length() == 7) { // It's #RRGGBB
1471 char* junk;
1472 int red = strtol(spec.Mid(1,2), &junk, 16);
1473 int green = strtol(spec.Mid(3,2), &junk, 16);
1474 int blue = strtol(spec.Mid(5,2), &junk, 16);
1475 **obj = wxColour(red, green, blue);
1476 return TRUE;
1477 }
1478 else { // it's a colour name
1479 **obj = wxColour(spec);
1480 return TRUE;
1481 }
1482 }
1483
1484 error:
1485 PyErr_SetString(PyExc_TypeError, "Expected a wxColour object or a string containing a colour name or '#RRGGBB'.");
1486 return FALSE;
1487}
1488
1489
1490//----------------------------------------------------------------------
1491
1492PyObject* wxArrayString2PyList_helper(const wxArrayString& arr) {
1493
1494 PyObject* list = PyList_New(0);
1495 for (size_t i=0; i < arr.GetCount(); i++) {
1496 PyObject* str = PyString_FromString(arr[i].c_str());
1497 PyList_Append(list, str);
1498 Py_DECREF(str);
1499 }
1500 return list;
1501}
1502
1503
1504//----------------------------------------------------------------------
1505//----------------------------------------------------------------------
1506
1507
1508
1509