]> git.saurik.com Git - wxWidgets.git/blob - utils/wxPython/src/helpers.cpp
Additions for wxTreeCtrl
[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 #ifdef __WXMSW__
14 #include <windows.h>
15 #undef FindWindow
16 #undef GetCharWidth
17 #undef LoadAccelerators
18 #endif
19
20 #undef DEBUG
21 #include <Python.h>
22 #include "helpers.h"
23
24 #ifdef __WXGTK__
25 #ifdef wxUSE_GDK_IMLIB
26 #include "gdk_imlib/gdk_imlib.h"
27 #endif
28 #endif
29
30 //---------------------------------------------------------------------------
31
32 //wxHashTable* wxPyWindows = NULL;
33
34
35 wxPoint wxPyDefaultPosition; //wxDefaultPosition);
36 wxSize wxPyDefaultSize; //wxDefaultSize);
37 wxString wxPyEmptyStr("");
38
39
40
41 #ifdef __WXMSW__ // If building for win32...
42 extern HINSTANCE wxhInstance;
43
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 wxhInstance = 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 // This one isn't acutally called... See __wxStart()
67 bool wxPyApp::OnInit(void) {
68 return false;
69 }
70
71 int wxPyApp::MainLoop(void) {
72 int retval = wxApp::MainLoop();
73 AfterMainLoop();
74 return retval;
75 }
76
77 void wxPyApp::AfterMainLoop(void) {
78 // more stuff from wxEntry...
79
80 #ifdef __WXMSW__
81 if (wxPythonApp->GetTopWindow()) {
82 // Forcibly delete the window.
83 if (wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxFrame)) ||
84 wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxDialog))) {
85
86 wxPythonApp->GetTopWindow()->Close(TRUE);
87 wxPythonApp->DeletePendingObjects();
88 }
89 else {
90 delete wxPythonApp->GetTopWindow();
91 wxPythonApp->SetTopWindow(NULL);
92 }
93 }
94 #endif
95 #ifdef __WXGTK__
96 wxPythonApp->DeletePendingObjects();
97 #endif
98
99 wxPythonApp->OnExit();
100 #ifdef __WXMSW__
101 wxApp::CleanUp();
102 #endif
103 #ifdef __WXGTK__
104 wxApp::CommonCleanUp();
105 #endif
106 delete wxPythonApp;
107 }
108
109
110 //---------------------------------------------------------------------
111 // a few native methods to add to the module
112 //----------------------------------------------------------------------
113
114
115 // This is where we pick up the first part of the wxEntry functionality...
116 // The rest is in __wxStart and AfterMainLoop. This function is called when
117 // wxpc is imported. (Before there is a wxApp object.)
118 void __wxPreStart()
119 {
120 // Bail out if there is already windows created. This means that the
121 // toolkit has already been initialized, as in embedding wxPython in
122 // a C++ wxWindows app.
123 if (wxTopLevelWindows.Number() > 0)
124 return;
125
126 #ifdef __WXMSW__
127 wxApp::Initialize();
128 #endif
129 #ifdef __WXGTK__
130 wxClassInfo::InitializeClasses();
131
132 PyObject* sysargv = PySys_GetObject("argv");
133 int argc = PyList_Size(sysargv);
134 char** argv = new char*[argc+1];
135 int x;
136 for(x=0; x<argc; x++)
137 argv[x] = PyString_AsString(PyList_GetItem(sysargv, x));
138 argv[argc] = NULL;
139
140 gtk_init( &argc, &argv );
141 delete [] argv;
142
143 #ifdef wxUSE_GDK_IMLIB
144 gdk_imlib_init();
145 gtk_widget_push_visual(gdk_imlib_get_visual());
146 gtk_widget_push_colormap(gdk_imlib_get_colormap());
147 #endif
148
149 wxApp::CommonInit();
150 #endif
151
152 }
153
154
155
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
167 if (!PyArg_ParseTuple(args, "O", &onInitFunc))
168 return NULL;
169
170 if (wxTopLevelWindows.Number() > 0) {
171 PyErr_SetString(PyExc_TypeError, "Only 1 wxApp per process!");
172 return NULL;
173 }
174
175
176 // This is the next part of the wxEntry functionality...
177 wxPythonApp->argc = 0;
178 wxPythonApp->argv = __nullArgv;
179 wxPythonApp->OnInitGui();
180
181
182 // Call the Python App's OnInit function
183 arglist = PyTuple_New(0);
184 result = PyEval_CallObject(onInitFunc, arglist);
185 if (!result) {
186 PyErr_Print();
187 exit(1);
188 }
189
190 if (! PyInt_Check(result)) {
191 PyErr_SetString(PyExc_TypeError, "OnInit should return a boolean value");
192 return NULL;
193 }
194 bResult = PyInt_AS_LONG(result);
195 if (! bResult) {
196 wxPythonApp->DeletePendingObjects();
197 wxPythonApp->OnExit();
198 #ifdef __WXMSW__
199 wxApp::CleanUp();
200 #endif
201 #ifdef __WXGTK__
202 wxApp::CommonCleanUp();
203 #endif
204 PyErr_SetString(PyExc_SystemExit, "OnInit returned false, exiting...");
205 return NULL;
206 }
207
208 #ifdef __WXGTK__
209 wxTheApp->m_initialized = (wxTopLevelWindows.Number() > 0);
210 #endif
211
212 Py_INCREF(Py_None);
213 return Py_None;
214 }
215
216
217
218
219
220 PyObject* wxPython_dict;
221 PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
222 {
223
224 if (!PyArg_ParseTuple(args, "O", &wxPython_dict))
225 return NULL;
226
227 if (!PyDict_Check(wxPython_dict)) {
228 PyErr_SetString(PyExc_TypeError, "_wxSetDictionary must have dictionary object!");
229 return NULL;
230 }
231 #ifdef __WXMOTIF__
232 #define wxPlatform "__WXMOTIF__"
233 #endif
234 #ifdef __WXQT__
235 #define wxPlatform "__WXQT__"
236 #endif
237 #ifdef __WXGTK__
238 #define wxPlatform "__WXGTK__"
239 #endif
240 #if defined(__WIN32__) || defined(__WXMSW__)
241 #define wxPlatform "__WXMSW__"
242 #endif
243 #ifdef __WXMAC__
244 #define wxPlatform "__WXMAC__"
245 #endif
246
247 PyDict_SetItemString(wxPython_dict, "wxPlatform", PyString_FromString(wxPlatform));
248
249 Py_INCREF(Py_None);
250 return Py_None;
251 }
252
253
254 //---------------------------------------------------------------------------
255
256
257 static
258 PyObject* wxPyConstructObject(void* ptr, char* className)
259 {
260 char buff[64]; // should always be big enough...
261 char swigptr[64];
262
263 sprintf(buff, "_%s_p", className);
264 SWIG_MakePtr(swigptr, ptr, buff);
265
266 sprintf(buff, "%sPtr", className);
267 PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff);
268 if (! classobj) {
269 Py_INCREF(Py_None);
270 return Py_None;
271 }
272
273 PyObject* arg = Py_BuildValue("(s)", swigptr);
274 PyObject* obj = PyInstance_New(classobj, arg, NULL);
275 Py_DECREF(arg);
276
277 return obj;
278 }
279
280
281 // This function is used for all events destined for Python event handlers.
282 void wxPyCallback::EventThunker(wxEvent& event) {
283 wxPyCallback* cb = (wxPyCallback*)event.m_callbackUserData;
284 PyObject* func = cb->m_func;
285 PyObject* result;
286 PyObject* arg;
287 PyObject* tuple;
288
289 arg = wxPyConstructObject((void*)&event, event.GetClassInfo()->GetClassName());
290
291 tuple = PyTuple_New(1);
292 PyTuple_SET_ITEM(tuple, 0, arg);
293 result = PyEval_CallObject(func, tuple);
294 Py_DECREF(tuple);
295 if (result) {
296 Py_DECREF(result);
297 PyErr_Clear();
298 } else {
299 PyErr_Print();
300 }
301 }
302
303
304 //---------------------------------------------------------------------------
305
306 wxPyMenu::wxPyMenu(const wxString& title, PyObject* _func)
307 : wxMenu(title, (wxFunction)(func ? MenuCallback : NULL)), func(0) {
308
309 if (_func) {
310 func = _func;
311 Py_INCREF(func);
312 }
313 }
314
315 wxPyMenu::~wxPyMenu() {
316 if (func)
317 Py_DECREF(func);
318 }
319
320
321 void wxPyMenu::MenuCallback(wxMenu& menu, wxCommandEvent& evt) {
322 PyObject* evtobj = wxPyConstructObject((void*)&evt, "wxCommandEvent");
323 PyObject* menuobj = wxPyConstructObject((void*)&menu, "wxMenu");
324 if (PyErr_Occurred()) {
325 // bail out if a problem
326 PyErr_Print();
327 return;
328 }
329 // Now call the callback...
330 PyObject* func = ((wxPyMenu*)&menu)->func;
331 PyObject* args = PyTuple_New(2);
332 PyTuple_SET_ITEM(args, 0, menuobj);
333 PyTuple_SET_ITEM(args, 1, evtobj);
334 PyObject* res = PyEval_CallObject(func, args);
335 Py_DECREF(args);
336 Py_XDECREF(res); /* In case res is a NULL pointer */
337 }
338
339
340 //---------------------------------------------------------------------------
341
342 wxPyTimer::wxPyTimer(PyObject* callback) {
343 func = callback;
344 Py_INCREF(func);
345 }
346
347 wxPyTimer::~wxPyTimer() {
348 Py_DECREF(func);
349 }
350
351 void wxPyTimer::Notify() {
352 PyObject* result;
353 PyObject* args = Py_BuildValue("()");
354
355 result = PyEval_CallObject(func, args);
356 Py_DECREF(args);
357 if (result) {
358 Py_DECREF(result);
359 PyErr_Clear();
360 } else {
361 PyErr_Print();
362 }
363 }
364
365
366
367 //----------------------------------------------------------------------
368 //----------------------------------------------------------------------
369 // Some helper functions for typemaps in my_typemaps.i, so they won't be
370 // imcluded in every file...
371
372
373 int* int_LIST_helper(PyObject* source) {
374 if (!PyList_Check(source)) {
375 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
376 return NULL;
377 }
378 int count = PyList_Size(source);
379 int* temp = new int[count];
380 if (! temp) {
381 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
382 return NULL;
383 }
384 for (int x=0; x<count; x++) {
385 PyObject* o = PyList_GetItem(source, x);
386 if (! PyInt_Check(o)) {
387 PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
388 return NULL;
389 }
390 temp[x] = PyInt_AsLong(o);
391 }
392 return temp;
393 }
394
395
396 long* long_LIST_helper(PyObject* source) {
397 if (!PyList_Check(source)) {
398 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
399 return NULL;
400 }
401 int count = PyList_Size(source);
402 long* temp = new long[count];
403 if (! temp) {
404 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
405 return NULL;
406 }
407 for (int x=0; x<count; x++) {
408 PyObject* o = PyList_GetItem(source, x);
409 if (! PyInt_Check(o)) {
410 PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
411 return NULL;
412 }
413 temp[x] = PyInt_AsLong(o);
414 }
415 return temp;
416 }
417
418
419 char** string_LIST_helper(PyObject* source) {
420 if (!PyList_Check(source)) {
421 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
422 return NULL;
423 }
424 int count = PyList_Size(source);
425 char** temp = new char*[count];
426 if (! temp) {
427 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
428 return NULL;
429 }
430 for (int x=0; x<count; x++) {
431 PyObject* o = PyList_GetItem(source, x);
432 if (! PyString_Check(o)) {
433 PyErr_SetString(PyExc_TypeError, "Expected a list of strings.");
434 return NULL;
435 }
436 temp[x] = PyString_AsString(o);
437 }
438 return temp;
439 }
440
441
442
443 wxPoint* wxPoint_LIST_helper(PyObject* source) {
444 if (!PyList_Check(source)) {
445 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
446 return NULL;
447 }
448 int count = PyList_Size(source);
449 wxPoint* temp = new wxPoint[count];
450 if (! temp) {
451 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
452 return NULL;
453 }
454 for (int x=0; x<count; x++) {
455 PyObject* o = PyList_GetItem(source, x);
456 if (PyString_Check(o)) {
457 char* st = PyString_AsString(o);
458 wxPoint* pt;
459 if (SWIG_GetPtr(st,(void **) &pt,"_wxPoint_p")) {
460 PyErr_SetString(PyExc_TypeError,"Expected _wxPoint_p.");
461 return NULL;
462 }
463 temp[x] = *pt;
464 }
465 else if (PyTuple_Check(o)) {
466 PyObject* o1 = PyTuple_GetItem(o, 0);
467 PyObject* o2 = PyTuple_GetItem(o, 1);
468
469 temp[x].x = PyInt_AsLong(o1);
470 temp[x].y = PyInt_AsLong(o2);
471 }
472 else {
473 PyErr_SetString(PyExc_TypeError, "Expected a list of 2-tuples or wxPoints.");
474 return NULL;
475 }
476 }
477 return temp;
478 }
479
480
481 wxBitmap** wxBitmap_LIST_helper(PyObject* source) {
482 if (!PyList_Check(source)) {
483 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
484 return NULL;
485 }
486 int count = PyList_Size(source);
487 wxBitmap** temp = new wxBitmap*[count];
488 if (! temp) {
489 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
490 return NULL;
491 }
492 for (int x=0; x<count; x++) {
493 PyObject* o = PyList_GetItem(source, x);
494 if (PyString_Check(o)) {
495 char* st = PyString_AsString(o);
496 wxBitmap* pt;
497 if (SWIG_GetPtr(st,(void **) &pt,"_wxBitmap_p")) {
498 PyErr_SetString(PyExc_TypeError,"Expected _wxBitmap_p.");
499 return NULL;
500 }
501 temp[x] = pt;
502 }
503 else {
504 PyErr_SetString(PyExc_TypeError, "Expected a list of wxBitmaps.");
505 return NULL;
506 }
507 }
508 return temp;
509 }
510
511
512
513 wxString* wxString_LIST_helper(PyObject* source) {
514 if (!PyList_Check(source)) {
515 PyErr_SetString(PyExc_TypeError, "Expected a list object.");
516 return NULL;
517 }
518 int count = PyList_Size(source);
519 wxString* temp = new wxString[count];
520 if (! temp) {
521 PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
522 return NULL;
523 }
524 for (int x=0; x<count; x++) {
525 PyObject* o = PyList_GetItem(source, x);
526 if (! PyString_Check(o)) {
527 PyErr_SetString(PyExc_TypeError, "Expected a list of strings.");
528 return NULL;
529 }
530 temp[x] = PyString_AsString(o);
531 }
532 return temp;
533 }
534
535
536 #ifdef __WXMSW__
537 wxAcceleratorEntry* wxAcceleratorEntry_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 wxAcceleratorEntry* temp = new wxAcceleratorEntry[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 (PyString_Check(o)) {
551 char* st = PyString_AsString(o);
552 wxAcceleratorEntry* ae;
553 if (SWIG_GetPtr(st,(void **) &ae,"_wxAcceleratorEntry_p")) {
554 PyErr_SetString(PyExc_TypeError,"Expected _wxAcceleratorEntry_p.");
555 return NULL;
556 }
557 temp[x] = *ae;
558 }
559 else if (PyTuple_Check(o)) {
560 PyObject* o1 = PyTuple_GetItem(o, 0);
561 PyObject* o2 = PyTuple_GetItem(o, 1);
562 PyObject* o3 = PyTuple_GetItem(o, 2);
563
564 temp[x].m_flags = PyInt_AsLong(o1);
565 temp[x].m_keyCode = PyInt_AsLong(o2);
566 temp[x].m_command = PyInt_AsLong(o3);
567 }
568 else {
569 PyErr_SetString(PyExc_TypeError, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
570 return NULL;
571 }
572 }
573 return temp;
574 }
575
576 #endif
577
578 //----------------------------------------------------------------------
579 // A WinMain for when wxWindows and Python are linked together in a single
580 // application, instead of as a dynamic module
581
582
583 //#if !defined(WIN_PYD) && defined(WIN32)
584
585 //extern "C" int Py_Main(int argc, char** argv);
586
587 //int APIENTRY WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR m_lpCmdLine,
588 // int nCmdShow )
589 //{
590
591 // wxpCreateApp();
592
593 // // Initialize wxWindows, but don't start the main loop
594 // wxEntry(hInstance, hPrevInstance, m_lpCmdLine, nCmdShow, FALSE);
595
596 // Py_Initialize();
597 // PyObject *argvList = PyList_New(0);
598
599 // char* stderrfilename = "wxpstderr.log";
600 // int pyargc = 1;
601 // char* script = NULL;
602 // int argc = wxPythonApp->argc;
603 // char** argv = wxPythonApp->argv;
604
605 // for (int i = 1; i < argc; i++) {
606 // if (strncmp(argv[i], "wxpstderr=", 10) == 0)
607 // stderrfilename = argv[i]+10;
608 // else {
609 // PyList_Append(argvList, PyString_FromString(argv[i]));
610 // if (!script)
611 // script = argv[i];
612 // pyargc++;
613 // }
614 // }
615
616 // PySys_SetObject("argv", argvList);
617
618 //#if 1
619 // char buf[256];
620 //// //PyRun_SimpleString("import sys; sys.stdout=open('wxpstdout.log','w')");
621 // sprintf(buf, "import sys; sys.stdout=sys.stderr=open('%s','w')", stderrfilename);
622 // PyRun_SimpleString(buf);
623 //#endif
624
625 // initwxPythonc();
626
627 // if (script) {
628 // FILE *fp = fopen(script, "r");
629 // if (fp) {
630 // PyRun_SimpleFile(fp, script);// This returns after wxpApp constructor
631 // fclose(fp);
632 // }
633 // else {
634 // char msg[256];
635 // sprintf(msg, "Cannot open %s", script);
636 // wxMessageBox(msg);
637 // }
638 // }
639 // else
640 // PyRun_SimpleString("import wxpide");
641
642 // return 0;
643 //}
644
645
646 //#endif
647
648 //----------------------------------------------------------------------
649
650 /////////////////////////////////////////////////////////////////////////////
651 //
652 // $Log$
653 // Revision 1.12 1998/11/03 09:21:08 RD
654 // fixed a typo
655 //
656 // Revision 1.11 1998/10/20 06:43:58 RD
657 // New wxTreeCtrl wrappers (untested)
658 // some changes in helpers
659 // etc.
660 //
661 // Revision 1.10 1998/10/02 06:40:39 RD
662 //
663 // Version 0.4 of wxPython for MSW.
664 //
665 // Revision 1.9 1998/09/25 13:28:52 VZ
666 //
667 // USE_xxx constants renamed to wxUSE_xxx. This is an incompatible change, you
668 // must recompile everything after upgrading!
669 //
670 // Revision 1.8 1998/08/27 21:59:08 RD
671 // Some chicken-and-egg problems solved for wxPython on wxGTK
672 //
673 // Revision 1.7 1998/08/27 00:00:26 RD
674 // - more tweaks
675 // - have discovered some problems but not yet discovered solutions...
676 //
677 // Revision 1.6 1998/08/18 21:54:12 RD
678 //
679 // ifdef out some wxGTK specific code
680 //
681 // Revision 1.5 1998/08/18 19:48:17 RD
682 // more wxGTK compatibility things.
683 //
684 // It builds now but there are serious runtime problems...
685 //
686 // Revision 1.4 1998/08/16 04:31:06 RD
687 // More wxGTK work.
688 //
689 // Revision 1.3 1998/08/15 07:36:36 RD
690 // - Moved the header in the .i files out of the code that gets put into
691 // the .cpp files. It caused CVS conflicts because of the RCS ID being
692 // different each time.
693 //
694 // - A few minor fixes.
695 //
696 // Revision 1.2 1998/08/14 23:36:36 RD
697 // Beginings of wxGTK compatibility
698 //
699 // Revision 1.1 1998/08/09 08:25:51 RD
700 // Initial version
701 //
702 //