1 /***********************************************************
2 Copyright (C) 1994 Steen Lumholt.
3
4 All Rights Reserved
5
6 ******************************************************************/
7
8 /* _tkinter.c -- Interface to libtk.a and libtcl.a. */
9
10 /* TCL/TK VERSION INFO:
11
12 Only Tcl/Tk 8.0 and later are supported. Older versions are not
13 supported. (Use Python 1.5.2 if you cannot upgrade your Tcl/Tk
14 libraries.)
15 */
16
17 /* XXX Further speed-up ideas, involving Tcl 8.0 features:
18
19 - In Tcl_Call(), create Tcl objects from the arguments, possibly using
20 intelligent mappings between Python objects and Tcl objects (e.g. ints,
21 floats and Tcl window pointers could be handled specially).
22
23 - Register a new Tcl type, "Python callable", which can be called more
24 efficiently and passed to Tcl_EvalObj() directly (if this is possible).
25
26 */
27
28
29 #include "Python.h"
30 #include <ctype.h>
31
32 #ifdef WITH_THREAD
33 #include "pythread.h"
34 #endif
35
36 #ifdef MS_WINDOWS
37 #include <windows.h>
38 #endif
39
40 #ifdef macintosh
41 #define MAC_TCL
42 #endif
43
44 #include <tcl.h>
45 #include <tk.h>
46 #ifdef WITH_TIX
47 #include <tix.h>
48 #endif
49
50 #define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION)
51
52 #if TKMAJORMINOR < 8000
53 #error "Tk older than 8.0 not supported"
54 #endif
55
56 #if defined(macintosh)
57 /* Sigh, we have to include this to get at the tcl qd pointer */
58 #include <tkMac.h>
59 /* And this one we need to clear the menu bar */
60 #include <Menus.h>
61 #endif
62
63 #if !(defined(MS_WINDOWS) || defined(__CYGWIN__))
64 #define HAVE_CREATEFILEHANDLER
65 #endif
66
67 #ifdef HAVE_CREATEFILEHANDLER
68
69 /* Tcl_CreateFileHandler() changed several times; these macros deal with the
70 messiness. In Tcl 8.0 and later, it is not available on Windows (and on
71 Unix, only because Jack added it back); when available on Windows, it only
72 applies to sockets. */
73
74 #ifdef MS_WINDOWS
75 #define FHANDLETYPE TCL_WIN_SOCKET
76 #else
77 #define FHANDLETYPE TCL_UNIX_FD
78 #endif
79
80 /* If Tcl can wait for a Unix file descriptor, define the EventHook() routine
81 which uses this to handle Tcl events while the user is typing commands. */
82
83 #if FHANDLETYPE == TCL_UNIX_FD
84 #define WAIT_FOR_STDIN
85 #endif
86
87 #endif /* HAVE_CREATEFILEHANDLER */
88
89 #ifdef MS_WINDOWS
90 #include <conio.h>
91 #define WAIT_FOR_STDIN
92 #endif
93
94 #ifdef WITH_THREAD
95
96 /* The threading situation is complicated. Tcl is not thread-safe, except for
97 Tcl 8.1, which will probably remain in alpha status for another 6 months
98 (and the README says that Tk will probably remain thread-unsafe forever).
99 So we need to use a lock around all uses of Tcl. Previously, the Python
100 interpreter lock was used for this. However, this causes problems when
101 other Python threads need to run while Tcl is blocked waiting for events.
102
103 To solve this problem, a separate lock for Tcl is introduced. Holding it
104 is incompatible with holding Python's interpreter lock. The following four
105 macros manipulate both locks together.
106
107 ENTER_TCL and LEAVE_TCL are brackets, just like Py_BEGIN_ALLOW_THREADS and
108 Py_END_ALLOW_THREADS. They should be used whenever a call into Tcl is made
109 that could call an event handler, or otherwise affect the state of a Tcl
110 interpreter. These assume that the surrounding code has the Python
111 interpreter lock; inside the brackets, the Python interpreter lock has been
112 released and the lock for Tcl has been acquired.
113
114 Sometimes, it is necessary to have both the Python lock and the Tcl lock.
115 (For example, when transferring data from the Tcl interpreter result to a
116 Python string object.) This can be done by using different macros to close
117 the ENTER_TCL block: ENTER_OVERLAP reacquires the Python lock (and restores
118 the thread state) but doesn't release the Tcl lock; LEAVE_OVERLAP_TCL
119 releases the Tcl lock.
120
121 By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event
122 handlers when the handler needs to use Python. Such event handlers are
123 entered while the lock for Tcl is held; the event handler presumably needs
124 to use Python. ENTER_PYTHON releases the lock for Tcl and acquires
125 the Python interpreter lock, restoring the appropriate thread state, and
126 LEAVE_PYTHON releases the Python interpreter lock and re-acquires the lock
127 for Tcl. It is okay for ENTER_TCL/LEAVE_TCL pairs to be contained inside
128 the code between ENTER_PYTHON and LEAVE_PYTHON.
129
130 These locks expand to several statements and brackets; they should not be
131 used in branches of if statements and the like.
132
133 */
134
135 static PyThread_type_lock tcl_lock = 0;
136 static PyThreadState *tcl_tstate = NULL;
137
138 #define ENTER_TCL \
139 { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \
140 PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
141
142 #define LEAVE_TCL \
143 tcl_tstate = NULL; PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
144
145 #define ENTER_OVERLAP \
146 Py_END_ALLOW_THREADS
147
148 #define LEAVE_OVERLAP_TCL \
149 tcl_tstate = NULL; PyThread_release_lock(tcl_lock); }
150
151 #define ENTER_PYTHON \
152 { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
153 PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
154
155 #define LEAVE_PYTHON \
156 { PyThreadState *tstate = PyEval_SaveThread(); \
157 PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }
158
159 #else
160
161 #define ENTER_TCL
162 #define LEAVE_TCL
163 #define ENTER_OVERLAP
164 #define LEAVE_OVERLAP_TCL
165 #define ENTER_PYTHON
166 #define LEAVE_PYTHON
167
168 #endif
169
170 #ifdef macintosh
171
172 /*
173 ** Additional cruft needed by Tcl/Tk on the Mac.
174 ** This is for Tcl 7.5 and Tk 4.1 (patch release 1).
175 */
176
177 /* ckfree() expects a char* */
178 #define FREECAST (char *)
179
180 #include <Events.h> /* For EventRecord */
181
182 typedef int (*TclMacConvertEventPtr) (EventRecord *eventPtr);
183 void Tcl_MacSetEventProc(TclMacConvertEventPtr procPtr);
184 int TkMacConvertEvent(EventRecord *eventPtr);
185
186 staticforward int PyMacConvertEvent(EventRecord *eventPtr);
187
188 #if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
189 #pragma import on
190 #endif
191
192 #include <SIOUX.h>
193 extern int SIOUXIsAppWindow(WindowPtr);
194
195 #if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
196 #pragma import reset
197 #endif
198 #endif /* macintosh */
199
200 #ifndef FREECAST
201 #define FREECAST (char *)
202 #endif
203
204 /**** Tkapp Object Declaration ****/
205
206 staticforward PyTypeObject Tkapp_Type;
207
208 typedef struct {
209 PyObject_HEAD
210 Tcl_Interp *interp;
211 } TkappObject;
212
213 #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type)
214 #define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
215 #define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v))
216
217 #define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \
218 (void *) v, ((PyObject *) v)->ob_refcnt))
219
220
221
222 /**** Error Handling ****/
223
224 static PyObject *Tkinter_TclError;
225 static int quitMainLoop = 0;
226 static int errorInCmd = 0;
227 static PyObject *excInCmd;
228 static PyObject *valInCmd;
229 static PyObject *trbInCmd;
230
231
232
233 static PyObject *
Tkinter_Error(PyObject * v)234 Tkinter_Error(PyObject *v)
235 {
236 PyErr_SetString(Tkinter_TclError, Tkapp_Result(v));
237 return NULL;
238 }
239
240
241
242 /**** Utils ****/
243
244 #ifdef WITH_THREAD
245 #ifndef MS_WINDOWS
246
247 /* Millisecond sleep() for Unix platforms. */
248
249 static void
Sleep(int milli)250 Sleep(int milli)
251 {
252 /* XXX Too bad if you don't have select(). */
253 struct timeval t;
254 t.tv_sec = milli/1000;
255 t.tv_usec = (milli%1000) * 1000;
256 select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
257 }
258 #endif /* MS_WINDOWS */
259 #endif /* WITH_THREAD */
260
261
262 static char *
AsString(PyObject * value,PyObject * tmp)263 AsString(PyObject *value, PyObject *tmp)
264 {
265 if (PyString_Check(value))
266 return PyString_AsString(value);
267 else if (PyUnicode_Check(value)) {
268 PyObject *v = PyUnicode_AsUTF8String(value);
269 if (v == NULL)
270 return NULL;
271 if (PyList_Append(tmp, v) != 0) {
272 Py_DECREF(v);
273 return NULL;
274 }
275 Py_DECREF(v);
276 return PyString_AsString(v);
277 }
278 else {
279 PyObject *v = PyObject_Str(value);
280 if (v == NULL)
281 return NULL;
282 if (PyList_Append(tmp, v) != 0) {
283 Py_DECREF(v);
284 return NULL;
285 }
286 Py_DECREF(v);
287 return PyString_AsString(v);
288 }
289 }
290
291
292
293 #define ARGSZ 64
294
295 static char *
Merge(PyObject * args)296 Merge(PyObject *args)
297 {
298 PyObject *tmp = NULL;
299 char *argvStore[ARGSZ];
300 char **argv = NULL;
301 int fvStore[ARGSZ];
302 int *fv = NULL;
303 int argc = 0, fvc = 0, i;
304 char *res = NULL;
305
306 if (!(tmp = PyList_New(0)))
307 return NULL;
308
309 argv = argvStore;
310 fv = fvStore;
311
312 if (args == NULL)
313 argc = 0;
314
315 else if (!PyTuple_Check(args)) {
316 argc = 1;
317 fv[0] = 0;
318 if (!(argv[0] = AsString(args, tmp)))
319 goto finally;
320 }
321 else {
322 argc = PyTuple_Size(args);
323
324 if (argc > ARGSZ) {
325 argv = (char **)ckalloc(argc * sizeof(char *));
326 fv = (int *)ckalloc(argc * sizeof(int));
327 if (argv == NULL || fv == NULL) {
328 PyErr_NoMemory();
329 goto finally;
330 }
331 }
332
333 for (i = 0; i < argc; i++) {
334 PyObject *v = PyTuple_GetItem(args, i);
335 if (PyTuple_Check(v)) {
336 fv[i] = 1;
337 if (!(argv[i] = Merge(v)))
338 goto finally;
339 fvc++;
340 }
341 else if (v == Py_None) {
342 argc = i;
343 break;
344 }
345 else {
346 fv[i] = 0;
347 if (!(argv[i] = AsString(v, tmp)))
348 goto finally;
349 fvc++;
350 }
351 }
352 }
353 res = Tcl_Merge(argc, argv);
354 if (res == NULL)
355 PyErr_SetString(Tkinter_TclError, "merge failed");
356
357 finally:
358 for (i = 0; i < fvc; i++)
359 if (fv[i]) {
360 ckfree(argv[i]);
361 }
362 if (argv != argvStore)
363 ckfree(FREECAST argv);
364 if (fv != fvStore)
365 ckfree(FREECAST fv);
366
367 Py_DECREF(tmp);
368 return res;
369 }
370
371
372
373 static PyObject *
Split(char * list)374 Split(char *list)
375 {
376 int argc;
377 char **argv;
378 PyObject *v;
379
380 if (list == NULL) {
381 Py_INCREF(Py_None);
382 return Py_None;
383 }
384
385 if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) {
386 /* Not a list.
387 * Could be a quoted string containing funnies, e.g. {"}.
388 * Return the string itself.
389 */
390 return PyString_FromString(list);
391 }
392
393 if (argc == 0)
394 v = PyString_FromString("");
395 else if (argc == 1)
396 v = PyString_FromString(argv[0]);
397 else if ((v = PyTuple_New(argc)) != NULL) {
398 int i;
399 PyObject *w;
400
401 for (i = 0; i < argc; i++) {
402 if ((w = Split(argv[i])) == NULL) {
403 Py_DECREF(v);
404 v = NULL;
405 break;
406 }
407 PyTuple_SetItem(v, i, w);
408 }
409 }
410 Tcl_Free(FREECAST argv);
411 return v;
412 }
413
414
415
416 /**** Tkapp Object ****/
417
418 #ifndef WITH_APPINIT
419 int
Tcl_AppInit(Tcl_Interp * interp)420 Tcl_AppInit(Tcl_Interp *interp)
421 {
422 Tk_Window main;
423
424 main = Tk_MainWindow(interp);
425 if (Tcl_Init(interp) == TCL_ERROR) {
426 PySys_WriteStderr("Tcl_Init error: %s\n", Tcl_GetStringResult(interp));
427 return TCL_ERROR;
428 }
429 if (Tk_Init(interp) == TCL_ERROR) {
430 PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp));
431 return TCL_ERROR;
432 }
433 #ifdef WITH_TIX
434 if (Tix_Init(interp) == TCL_ERROR) {
435 PySys_WriteStderr("Tix_Init error: %s\n", Tcl_GetStringResult(interp));
436 return TCL_ERROR;
437 }
438 #endif
439 return TCL_OK;
440 }
441 #endif /* !WITH_APPINIT */
442
443
444
445
446 /* Initialize the Tk application; see the `main' function in
447 * `tkMain.c'.
448 */
449
450 static void EnableEventHook(void); /* Forward */
451 static void DisableEventHook(void); /* Forward */
452
453 static TkappObject *
Tkapp_New(char * screenName,char * baseName,char * className,int interactive)454 Tkapp_New(char *screenName, char *baseName, char *className, int interactive)
455 {
456 TkappObject *v;
457 char *argv0;
458
459 v = PyObject_New(TkappObject, &Tkapp_Type);
460 if (v == NULL)
461 return NULL;
462
463 v->interp = Tcl_CreateInterp();
464
465 #if defined(macintosh)
466 /* This seems to be needed */
467 ClearMenuBar();
468 TkMacInitMenus(v->interp);
469 #endif
470 /* Delete the 'exit' command, which can screw things up */
471 Tcl_DeleteCommand(v->interp, "exit");
472
473 if (screenName != NULL)
474 Tcl_SetVar2(v->interp, "env", "DISPLAY",
475 screenName, TCL_GLOBAL_ONLY);
476
477 if (interactive)
478 Tcl_SetVar(v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
479 else
480 Tcl_SetVar(v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
481
482 /* This is used to get the application class for Tk 4.1 and up */
483 argv0 = (char*)ckalloc(strlen(className) + 1);
484 if (!argv0) {
485 PyErr_NoMemory();
486 Py_DECREF(v);
487 return NULL;
488 }
489
490 strcpy(argv0, className);
491 if (isupper((int)(argv0[0])))
492 argv0[0] = tolower(argv0[0]);
493 Tcl_SetVar(v->interp, "argv0", argv0, TCL_GLOBAL_ONLY);
494 ckfree(argv0);
495
496 if (Tcl_AppInit(v->interp) != TCL_OK)
497 return (TkappObject *)Tkinter_Error((PyObject *)v);
498
499 EnableEventHook();
500
501 return v;
502 }
503
504
505
506 /** Tcl Eval **/
507
508 #if TKMAJORMINOR >= 8001
509 #define USING_OBJECTS
510 #endif
511
512 #ifdef USING_OBJECTS
513
514 static Tcl_Obj*
AsObj(PyObject * value)515 AsObj(PyObject *value)
516 {
517 Tcl_Obj *result;
518
519 if (PyString_Check(value))
520 return Tcl_NewStringObj(PyString_AS_STRING(value),
521 PyString_GET_SIZE(value));
522 else if (PyInt_Check(value))
523 return Tcl_NewLongObj(PyInt_AS_LONG(value));
524 else if (PyFloat_Check(value))
525 return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value));
526 else if (PyTuple_Check(value)) {
527 Tcl_Obj **argv = (Tcl_Obj**)
528 ckalloc(PyTuple_Size(value)*sizeof(Tcl_Obj*));
529 int i;
530 if(!argv)
531 return 0;
532 for(i=0;i<PyTuple_Size(value);i++)
533 argv[i] = AsObj(PyTuple_GetItem(value,i));
534 result = Tcl_NewListObj(PyTuple_Size(value), argv);
535 ckfree(FREECAST argv);
536 return result;
537 }
538 else if (PyUnicode_Check(value)) {
539 #if TKMAJORMINOR <= 8001
540 /* In Tcl 8.1 we must use UTF-8 */
541 PyObject* utf8 = PyUnicode_AsUTF8String(value);
542 if (!utf8)
543 return 0;
544 result = Tcl_NewStringObj(PyString_AS_STRING(utf8),
545 PyString_GET_SIZE(utf8));
546 Py_DECREF(utf8);
547 return result;
548 #else /* TKMAJORMINOR > 8001 */
549 /* In Tcl 8.2 and later, use Tcl_NewUnicodeObj() */
550 if (sizeof(Py_UNICODE) != sizeof(Tcl_UniChar)) {
551 /* XXX Should really test this at compile time */
552 PyErr_SetString(PyExc_SystemError,
553 "Py_UNICODE and Tcl_UniChar differ in size");
554 return 0;
555 }
556 return Tcl_NewUnicodeObj(PyUnicode_AS_UNICODE(value),
557 PyUnicode_GET_SIZE(value));
558 #endif /* TKMAJORMINOR > 8001 */
559 }
560 else {
561 PyObject *v = PyObject_Str(value);
562 if (!v)
563 return 0;
564 result = AsObj(v);
565 Py_DECREF(v);
566 return result;
567 }
568 }
569
570 static PyObject *
Tkapp_Call(PyObject * self,PyObject * args)571 Tkapp_Call(PyObject *self, PyObject *args)
572 {
573 Tcl_Obj *objStore[ARGSZ];
574 Tcl_Obj **objv = NULL;
575 int objc = 0, i;
576 PyObject *res = NULL;
577 Tcl_Interp *interp = Tkapp_Interp(self);
578 /* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */
579 int flags = TCL_EVAL_DIRECT;
580
581 objv = objStore;
582
583 if (args == NULL)
584 objc = 0;
585
586 else if (!PyTuple_Check(args)) {
587 objc = 1;
588 objv[0] = AsObj(args);
589 if (objv[0] == 0)
590 goto finally;
591 Tcl_IncrRefCount(objv[0]);
592 }
593 else {
594 objc = PyTuple_Size(args);
595
596 if (objc > ARGSZ) {
597 objv = (Tcl_Obj **)ckalloc(objc * sizeof(char *));
598 if (objv == NULL) {
599 PyErr_NoMemory();
600 goto finally;
601 }
602 }
603
604 for (i = 0; i < objc; i++) {
605 PyObject *v = PyTuple_GetItem(args, i);
606 if (v == Py_None) {
607 objc = i;
608 break;
609 }
610 objv[i] = AsObj(v);
611 if (!objv[i])
612 goto finally;
613 Tcl_IncrRefCount(objv[i]);
614 }
615 }
616
617 ENTER_TCL
618
619 i = Tcl_EvalObjv(interp, objc, objv, flags);
620
621 ENTER_OVERLAP
622 if (i == TCL_ERROR)
623 Tkinter_Error(self);
624 else {
625 /* We could request the object result here, but doing
626 so would confuse applications that expect a string. */
627 char *s = Tcl_GetStringResult(interp);
628 char *p = s;
629 /* If the result contains any bytes with the top bit set,
630 it's UTF-8 and we should decode it to Unicode */
631 while (*p != '\0') {
632 if (*p & 0x80)
633 break;
634 p++;
635 }
636 if (*p == '\0')
637 res = PyString_FromStringAndSize(s, (int)(p-s));
638 else {
639 /* Convert UTF-8 to Unicode string */
640 p = strchr(p, '\0');
641 res = PyUnicode_DecodeUTF8(s, (int)(p-s), "strict");
642 if (res == NULL) {
643 PyErr_Clear();
644 res = PyString_FromStringAndSize(s, (int)(p-s));
645 }
646 }
647 }
648
649 LEAVE_OVERLAP_TCL
650
651 finally:
652 for (i = 0; i < objc; i++)
653 Tcl_DecrRefCount(objv[i]);
654 if (objv != objStore)
655 ckfree(FREECAST objv);
656 return res;
657 }
658
659 #else /* !USING_OBJECTS */
660
661 static PyObject *
Tkapp_Call(PyObject * self,PyObject * args)662 Tkapp_Call(PyObject *self, PyObject *args)
663 {
664 /* This is copied from Merge() */
665 PyObject *tmp = NULL;
666 char *argvStore[ARGSZ];
667 char **argv = NULL;
668 int fvStore[ARGSZ];
669 int *fv = NULL;
670 int argc = 0, fvc = 0, i;
671 PyObject *res = NULL; /* except this has a different type */
672 Tcl_CmdInfo info; /* and this is added */
673 Tcl_Interp *interp = Tkapp_Interp(self); /* and this too */
674
675 if (!(tmp = PyList_New(0)))
676 return NULL;
677
678 argv = argvStore;
679 fv = fvStore;
680
681 if (args == NULL)
682 argc = 0;
683
684 else if (!PyTuple_Check(args)) {
685 argc = 1;
686 fv[0] = 0;
687 if (!(argv[0] = AsString(args, tmp)))
688 goto finally;
689 }
690 else {
691 argc = PyTuple_Size(args);
692
693 if (argc > ARGSZ) {
694 argv = (char **)ckalloc(argc * sizeof(char *));
695 fv = (int *)ckalloc(argc * sizeof(int));
696 if (argv == NULL || fv == NULL) {
697 PyErr_NoMemory();
698 goto finally;
699 }
700 }
701
702 for (i = 0; i < argc; i++) {
703 PyObject *v = PyTuple_GetItem(args, i);
704 if (PyTuple_Check(v)) {
705 fv[i] = 1;
706 if (!(argv[i] = Merge(v)))
707 goto finally;
708 fvc++;
709 }
710 else if (v == Py_None) {
711 argc = i;
712 break;
713 }
714 else {
715 fv[i] = 0;
716 if (!(argv[i] = AsString(v, tmp)))
717 goto finally;
718 fvc++;
719 }
720 }
721 }
722 /* End code copied from Merge() */
723
724 /* All this to avoid a call to Tcl_Merge() and the corresponding call
725 to Tcl_SplitList() inside Tcl_Eval()... It can save a bundle! */
726 if (Py_VerboseFlag >= 2) {
727 for (i = 0; i < argc; i++)
728 PySys_WriteStderr("%s ", argv[i]);
729 }
730 ENTER_TCL
731 info.proc = NULL;
732 if (argc < 1 ||
733 !Tcl_GetCommandInfo(interp, argv[0], &info) ||
734 info.proc == NULL)
735 {
736 char *cmd;
737 cmd = Tcl_Merge(argc, argv);
738 i = Tcl_Eval(interp, cmd);
739 ckfree(cmd);
740 }
741 else {
742 Tcl_ResetResult(interp);
743 i = (*info.proc)(info.clientData, interp, argc, argv);
744 }
745 ENTER_OVERLAP
746 if (info.proc == NULL && Py_VerboseFlag >= 2)
747 PySys_WriteStderr("... use TclEval ");
748 if (i == TCL_ERROR) {
749 if (Py_VerboseFlag >= 2)
750 PySys_WriteStderr("... error: '%s'\n",
751 Tcl_GetStringResult(interp));
752 Tkinter_Error(self);
753 }
754 else {
755 if (Py_VerboseFlag >= 2)
756 PySys_WriteStderr("-> '%s'\n", Tcl_GetStringResult(interp));
757 res = PyString_FromString(Tcl_GetStringResult(interp));
758 }
759 LEAVE_OVERLAP_TCL
760
761 /* Copied from Merge() again */
762 finally:
763 for (i = 0; i < fvc; i++)
764 if (fv[i]) {
765 ckfree(argv[i]);
766 }
767 if (argv != argvStore)
768 ckfree(FREECAST argv);
769 if (fv != fvStore)
770 ckfree(FREECAST fv);
771
772 Py_DECREF(tmp);
773 return res;
774 }
775
776 #endif /* !USING_OBJECTS */
777
778 static PyObject *
Tkapp_GlobalCall(PyObject * self,PyObject * args)779 Tkapp_GlobalCall(PyObject *self, PyObject *args)
780 {
781 /* Could do the same here as for Tkapp_Call(), but this is not used
782 much, so I can't be bothered. Unfortunately Tcl doesn't export a
783 way for the user to do what all its Global* variants do (save and
784 reset the scope pointer, call the local version, restore the saved
785 scope pointer). */
786
787 char *cmd;
788 PyObject *res = NULL;
789
790 cmd = Merge(args);
791 if (cmd) {
792 int err;
793 ENTER_TCL
794 err = Tcl_GlobalEval(Tkapp_Interp(self), cmd);
795 ENTER_OVERLAP
796 if (err == TCL_ERROR)
797 res = Tkinter_Error(self);
798 else
799 res = PyString_FromString(Tkapp_Result(self));
800 LEAVE_OVERLAP_TCL
801 ckfree(cmd);
802 }
803
804 return res;
805 }
806
807 static PyObject *
Tkapp_Eval(PyObject * self,PyObject * args)808 Tkapp_Eval(PyObject *self, PyObject *args)
809 {
810 char *script;
811 PyObject *res = NULL;
812 int err;
813
814 if (!PyArg_ParseTuple(args, "s:eval", &script))
815 return NULL;
816
817 ENTER_TCL
818 err = Tcl_Eval(Tkapp_Interp(self), script);
819 ENTER_OVERLAP
820 if (err == TCL_ERROR)
821 res = Tkinter_Error(self);
822 else
823 res = PyString_FromString(Tkapp_Result(self));
824 LEAVE_OVERLAP_TCL
825 return res;
826 }
827
828 static PyObject *
Tkapp_GlobalEval(PyObject * self,PyObject * args)829 Tkapp_GlobalEval(PyObject *self, PyObject *args)
830 {
831 char *script;
832 PyObject *res = NULL;
833 int err;
834
835 if (!PyArg_ParseTuple(args, "s:globaleval", &script))
836 return NULL;
837
838 ENTER_TCL
839 err = Tcl_GlobalEval(Tkapp_Interp(self), script);
840 ENTER_OVERLAP
841 if (err == TCL_ERROR)
842 res = Tkinter_Error(self);
843 else
844 res = PyString_FromString(Tkapp_Result(self));
845 LEAVE_OVERLAP_TCL
846 return res;
847 }
848
849 static PyObject *
Tkapp_EvalFile(PyObject * self,PyObject * args)850 Tkapp_EvalFile(PyObject *self, PyObject *args)
851 {
852 char *fileName;
853 PyObject *res = NULL;
854 int err;
855
856 if (!PyArg_ParseTuple(args, "s:evalfile", &fileName))
857 return NULL;
858
859 ENTER_TCL
860 err = Tcl_EvalFile(Tkapp_Interp(self), fileName);
861 ENTER_OVERLAP
862 if (err == TCL_ERROR)
863 res = Tkinter_Error(self);
864
865 else
866 res = PyString_FromString(Tkapp_Result(self));
867 LEAVE_OVERLAP_TCL
868 return res;
869 }
870
871 static PyObject *
Tkapp_Record(PyObject * self,PyObject * args)872 Tkapp_Record(PyObject *self, PyObject *args)
873 {
874 char *script;
875 PyObject *res = NULL;
876 int err;
877
878 if (!PyArg_ParseTuple(args, "s", &script))
879 return NULL;
880
881 ENTER_TCL
882 err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL);
883 ENTER_OVERLAP
884 if (err == TCL_ERROR)
885 res = Tkinter_Error(self);
886 else
887 res = PyString_FromString(Tkapp_Result(self));
888 LEAVE_OVERLAP_TCL
889 return res;
890 }
891
892 static PyObject *
Tkapp_AddErrorInfo(PyObject * self,PyObject * args)893 Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
894 {
895 char *msg;
896
897 if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg))
898 return NULL;
899 ENTER_TCL
900 Tcl_AddErrorInfo(Tkapp_Interp(self), msg);
901 LEAVE_TCL
902
903 Py_INCREF(Py_None);
904 return Py_None;
905 }
906
907
908
909 /** Tcl Variable **/
910
911 static PyObject *
SetVar(PyObject * self,PyObject * args,int flags)912 SetVar(PyObject *self, PyObject *args, int flags)
913 {
914 char *name1, *name2, *ok, *s;
915 PyObject *newValue;
916 PyObject *tmp;
917
918 tmp = PyList_New(0);
919 if (!tmp)
920 return NULL;
921
922 if (PyArg_ParseTuple(args, "sO:setvar", &name1, &newValue)) {
923 /* XXX Merge? */
924 s = AsString(newValue, tmp);
925 if (s == NULL)
926 return NULL;
927 ENTER_TCL
928 ok = Tcl_SetVar(Tkapp_Interp(self), name1, s, flags);
929 LEAVE_TCL
930 }
931 else {
932 PyErr_Clear();
933 if (PyArg_ParseTuple(args, "ssO:setvar",
934 &name1, &name2, &newValue)) {
935 s = AsString(newValue, tmp);
936 if (s == NULL)
937 return NULL;
938 ENTER_TCL
939 ok = Tcl_SetVar2(Tkapp_Interp(self), name1, name2,
940 s, flags);
941 LEAVE_TCL
942 }
943 else {
944 Py_DECREF(tmp);
945 return NULL;
946 }
947 }
948 Py_DECREF(tmp);
949
950 if (!ok)
951 return Tkinter_Error(self);
952
953 Py_INCREF(Py_None);
954 return Py_None;
955 }
956
957 static PyObject *
Tkapp_SetVar(PyObject * self,PyObject * args)958 Tkapp_SetVar(PyObject *self, PyObject *args)
959 {
960 return SetVar(self, args, TCL_LEAVE_ERR_MSG);
961 }
962
963 static PyObject *
Tkapp_GlobalSetVar(PyObject * self,PyObject * args)964 Tkapp_GlobalSetVar(PyObject *self, PyObject *args)
965 {
966 return SetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
967 }
968
969
970
971 static PyObject *
GetVar(PyObject * self,PyObject * args,int flags)972 GetVar(PyObject *self, PyObject *args, int flags)
973 {
974 char *name1, *name2=NULL, *s;
975 PyObject *res = NULL;
976
977 if (!PyArg_ParseTuple(args, "s|s:getvar", &name1, &name2))
978 return NULL;
979 ENTER_TCL
980 if (name2 == NULL)
981 s = Tcl_GetVar(Tkapp_Interp(self), name1, flags);
982
983 else
984 s = Tcl_GetVar2(Tkapp_Interp(self), name1, name2, flags);
985 ENTER_OVERLAP
986
987 if (s == NULL)
988 res = Tkinter_Error(self);
989 else
990 res = PyString_FromString(s);
991 LEAVE_OVERLAP_TCL
992 return res;
993 }
994
995 static PyObject *
Tkapp_GetVar(PyObject * self,PyObject * args)996 Tkapp_GetVar(PyObject *self, PyObject *args)
997 {
998 return GetVar(self, args, TCL_LEAVE_ERR_MSG);
999 }
1000
1001 static PyObject *
Tkapp_GlobalGetVar(PyObject * self,PyObject * args)1002 Tkapp_GlobalGetVar(PyObject *self, PyObject *args)
1003 {
1004 return GetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1005 }
1006
1007
1008
1009 static PyObject *
UnsetVar(PyObject * self,PyObject * args,int flags)1010 UnsetVar(PyObject *self, PyObject *args, int flags)
1011 {
1012 char *name1, *name2=NULL;
1013 PyObject *res = NULL;
1014 int code;
1015
1016 if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2))
1017 return NULL;
1018 ENTER_TCL
1019 if (name2 == NULL)
1020 code = Tcl_UnsetVar(Tkapp_Interp(self), name1, flags);
1021
1022 else
1023 code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags);
1024 ENTER_OVERLAP
1025
1026 if (code == TCL_ERROR)
1027 res = Tkinter_Error(self);
1028 else {
1029 Py_INCREF(Py_None);
1030 res = Py_None;
1031 }
1032 LEAVE_OVERLAP_TCL
1033 return res;
1034 }
1035
1036 static PyObject *
Tkapp_UnsetVar(PyObject * self,PyObject * args)1037 Tkapp_UnsetVar(PyObject *self, PyObject *args)
1038 {
1039 return UnsetVar(self, args, TCL_LEAVE_ERR_MSG);
1040 }
1041
1042 static PyObject *
Tkapp_GlobalUnsetVar(PyObject * self,PyObject * args)1043 Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args)
1044 {
1045 return UnsetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1046 }
1047
1048
1049
1050 /** Tcl to Python **/
1051
1052 static PyObject *
Tkapp_GetInt(PyObject * self,PyObject * args)1053 Tkapp_GetInt(PyObject *self, PyObject *args)
1054 {
1055 char *s;
1056 int v;
1057
1058 if (!PyArg_ParseTuple(args, "s:getint", &s))
1059 return NULL;
1060 if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1061 return Tkinter_Error(self);
1062 return Py_BuildValue("i", v);
1063 }
1064
1065 static PyObject *
Tkapp_GetDouble(PyObject * self,PyObject * args)1066 Tkapp_GetDouble(PyObject *self, PyObject *args)
1067 {
1068 char *s;
1069 double v;
1070
1071 if (!PyArg_ParseTuple(args, "s:getdouble", &s))
1072 return NULL;
1073 if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1074 return Tkinter_Error(self);
1075 return Py_BuildValue("d", v);
1076 }
1077
1078 static PyObject *
Tkapp_GetBoolean(PyObject * self,PyObject * args)1079 Tkapp_GetBoolean(PyObject *self, PyObject *args)
1080 {
1081 char *s;
1082 int v;
1083
1084 if (!PyArg_ParseTuple(args, "s:getboolean", &s))
1085 return NULL;
1086 if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1087 return Tkinter_Error(self);
1088 return Py_BuildValue("i", v);
1089 }
1090
1091 static PyObject *
Tkapp_ExprString(PyObject * self,PyObject * args)1092 Tkapp_ExprString(PyObject *self, PyObject *args)
1093 {
1094 char *s;
1095 PyObject *res = NULL;
1096 int retval;
1097
1098 if (!PyArg_ParseTuple(args, "s:exprstring", &s))
1099 return NULL;
1100 ENTER_TCL
1101 retval = Tcl_ExprString(Tkapp_Interp(self), s);
1102 ENTER_OVERLAP
1103 if (retval == TCL_ERROR)
1104 res = Tkinter_Error(self);
1105 else
1106 res = Py_BuildValue("s", Tkapp_Result(self));
1107 LEAVE_OVERLAP_TCL
1108 return res;
1109 }
1110
1111 static PyObject *
Tkapp_ExprLong(PyObject * self,PyObject * args)1112 Tkapp_ExprLong(PyObject *self, PyObject *args)
1113 {
1114 char *s;
1115 PyObject *res = NULL;
1116 int retval;
1117 long v;
1118
1119 if (!PyArg_ParseTuple(args, "s:exprlong", &s))
1120 return NULL;
1121 ENTER_TCL
1122 retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v);
1123 ENTER_OVERLAP
1124 if (retval == TCL_ERROR)
1125 res = Tkinter_Error(self);
1126 else
1127 res = Py_BuildValue("l", v);
1128 LEAVE_OVERLAP_TCL
1129 return res;
1130 }
1131
1132 static PyObject *
Tkapp_ExprDouble(PyObject * self,PyObject * args)1133 Tkapp_ExprDouble(PyObject *self, PyObject *args)
1134 {
1135 char *s;
1136 PyObject *res = NULL;
1137 double v;
1138 int retval;
1139
1140 if (!PyArg_ParseTuple(args, "s:exprdouble", &s))
1141 return NULL;
1142 PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
1143 ENTER_TCL
1144 retval = Tcl_ExprDouble(Tkapp_Interp(self), s, &v);
1145 ENTER_OVERLAP
1146 PyFPE_END_PROTECT(retval)
1147 if (retval == TCL_ERROR)
1148 res = Tkinter_Error(self);
1149 else
1150 res = Py_BuildValue("d", v);
1151 LEAVE_OVERLAP_TCL
1152 return res;
1153 }
1154
1155 static PyObject *
Tkapp_ExprBoolean(PyObject * self,PyObject * args)1156 Tkapp_ExprBoolean(PyObject *self, PyObject *args)
1157 {
1158 char *s;
1159 PyObject *res = NULL;
1160 int retval;
1161 int v;
1162
1163 if (!PyArg_ParseTuple(args, "s:exprboolean", &s))
1164 return NULL;
1165 ENTER_TCL
1166 retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v);
1167 ENTER_OVERLAP
1168 if (retval == TCL_ERROR)
1169 res = Tkinter_Error(self);
1170 else
1171 res = Py_BuildValue("i", v);
1172 LEAVE_OVERLAP_TCL
1173 return res;
1174 }
1175
1176
1177
1178 static PyObject *
Tkapp_SplitList(PyObject * self,PyObject * args)1179 Tkapp_SplitList(PyObject *self, PyObject *args)
1180 {
1181 char *list;
1182 int argc;
1183 char **argv;
1184 PyObject *v;
1185 int i;
1186
1187 if (!PyArg_ParseTuple(args, "s:splitlist", &list))
1188 return NULL;
1189
1190 if (Tcl_SplitList(Tkapp_Interp(self), list, &argc, &argv) == TCL_ERROR)
1191 return Tkinter_Error(self);
1192
1193 if (!(v = PyTuple_New(argc)))
1194 return NULL;
1195
1196 for (i = 0; i < argc; i++) {
1197 PyObject *s = PyString_FromString(argv[i]);
1198 if (!s || PyTuple_SetItem(v, i, s)) {
1199 Py_DECREF(v);
1200 v = NULL;
1201 goto finally;
1202 }
1203 }
1204
1205 finally:
1206 ckfree(FREECAST argv);
1207 return v;
1208 }
1209
1210 static PyObject *
Tkapp_Split(PyObject * self,PyObject * args)1211 Tkapp_Split(PyObject *self, PyObject *args)
1212 {
1213 char *list;
1214
1215 if (!PyArg_ParseTuple(args, "s:split", &list))
1216 return NULL;
1217 return Split(list);
1218 }
1219
1220 static PyObject *
Tkapp_Merge(PyObject * self,PyObject * args)1221 Tkapp_Merge(PyObject *self, PyObject *args)
1222 {
1223 char *s = Merge(args);
1224 PyObject *res = NULL;
1225
1226 if (s) {
1227 res = PyString_FromString(s);
1228 ckfree(s);
1229 }
1230
1231 return res;
1232 }
1233
1234
1235
1236 /** Tcl Command **/
1237
1238 /* Client data struct */
1239 typedef struct {
1240 PyObject *self;
1241 PyObject *func;
1242 } PythonCmd_ClientData;
1243
1244 static int
PythonCmd_Error(Tcl_Interp * interp)1245 PythonCmd_Error(Tcl_Interp *interp)
1246 {
1247 errorInCmd = 1;
1248 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1249 LEAVE_PYTHON
1250 return TCL_ERROR;
1251 }
1252
1253 /* This is the Tcl command that acts as a wrapper for Python
1254 * function or method.
1255 */
1256 static int
PythonCmd(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])1257 PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1258 {
1259 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
1260 PyObject *self, *func, *arg, *res, *tmp;
1261 int i, rv;
1262 char *s;
1263
1264 ENTER_PYTHON
1265
1266 /* TBD: no error checking here since we know, via the
1267 * Tkapp_CreateCommand() that the client data is a two-tuple
1268 */
1269 self = data->self;
1270 func = data->func;
1271
1272 /* Create argument list (argv1, ..., argvN) */
1273 if (!(arg = PyTuple_New(argc - 1)))
1274 return PythonCmd_Error(interp);
1275
1276 for (i = 0; i < (argc - 1); i++) {
1277 PyObject *s = PyString_FromString(argv[i + 1]);
1278 if (!s || PyTuple_SetItem(arg, i, s)) {
1279 Py_DECREF(arg);
1280 return PythonCmd_Error(interp);
1281 }
1282 }
1283 res = PyEval_CallObject(func, arg);
1284 Py_DECREF(arg);
1285
1286 if (res == NULL)
1287 return PythonCmd_Error(interp);
1288
1289 if (!(tmp = PyList_New(0))) {
1290 Py_DECREF(res);
1291 return PythonCmd_Error(interp);
1292 }
1293
1294 s = AsString(res, tmp);
1295 if (s == NULL) {
1296 rv = PythonCmd_Error(interp);
1297 }
1298 else {
1299 Tcl_SetResult(Tkapp_Interp(self), s, TCL_VOLATILE);
1300 rv = TCL_OK;
1301 }
1302
1303 Py_DECREF(res);
1304 Py_DECREF(tmp);
1305
1306 LEAVE_PYTHON
1307
1308 return rv;
1309 }
1310
1311 static void
PythonCmdDelete(ClientData clientData)1312 PythonCmdDelete(ClientData clientData)
1313 {
1314 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
1315
1316 ENTER_PYTHON
1317 Py_XDECREF(data->self);
1318 Py_XDECREF(data->func);
1319 PyMem_DEL(data);
1320 LEAVE_PYTHON
1321 }
1322
1323
1324
1325 static PyObject *
Tkapp_CreateCommand(PyObject * self,PyObject * args)1326 Tkapp_CreateCommand(PyObject *self, PyObject *args)
1327 {
1328 PythonCmd_ClientData *data;
1329 char *cmdName;
1330 PyObject *func;
1331 Tcl_Command err;
1332
1333 if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func))
1334 return NULL;
1335 if (!PyCallable_Check(func)) {
1336 PyErr_SetString(PyExc_TypeError, "command not callable");
1337 return NULL;
1338 }
1339
1340 data = PyMem_NEW(PythonCmd_ClientData, 1);
1341 if (!data)
1342 return NULL;
1343 Py_XINCREF(self);
1344 Py_XINCREF(func);
1345 data->self = self;
1346 data->func = func;
1347
1348 ENTER_TCL
1349 err = Tcl_CreateCommand(Tkapp_Interp(self), cmdName, PythonCmd,
1350 (ClientData)data, PythonCmdDelete);
1351 LEAVE_TCL
1352 if (err == NULL) {
1353 PyErr_SetString(Tkinter_TclError, "can't create Tcl command");
1354 PyMem_DEL(data);
1355 return NULL;
1356 }
1357
1358 Py_INCREF(Py_None);
1359 return Py_None;
1360 }
1361
1362
1363
1364 static PyObject *
Tkapp_DeleteCommand(PyObject * self,PyObject * args)1365 Tkapp_DeleteCommand(PyObject *self, PyObject *args)
1366 {
1367 char *cmdName;
1368 int err;
1369
1370 if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName))
1371 return NULL;
1372 ENTER_TCL
1373 err = Tcl_DeleteCommand(Tkapp_Interp(self), cmdName);
1374 LEAVE_TCL
1375 if (err == -1) {
1376 PyErr_SetString(Tkinter_TclError, "can't delete Tcl command");
1377 return NULL;
1378 }
1379 Py_INCREF(Py_None);
1380 return Py_None;
1381 }
1382
1383
1384
1385 #ifdef HAVE_CREATEFILEHANDLER
1386 /** File Handler **/
1387
1388 typedef struct _fhcdata {
1389 PyObject *func;
1390 PyObject *file;
1391 int id;
1392 struct _fhcdata *next;
1393 } FileHandler_ClientData;
1394
1395 static FileHandler_ClientData *HeadFHCD;
1396
1397 static FileHandler_ClientData *
NewFHCD(PyObject * func,PyObject * file,int id)1398 NewFHCD(PyObject *func, PyObject *file, int id)
1399 {
1400 FileHandler_ClientData *p;
1401 p = PyMem_NEW(FileHandler_ClientData, 1);
1402 if (p != NULL) {
1403 Py_XINCREF(func);
1404 Py_XINCREF(file);
1405 p->func = func;
1406 p->file = file;
1407 p->id = id;
1408 p->next = HeadFHCD;
1409 HeadFHCD = p;
1410 }
1411 return p;
1412 }
1413
1414 static void
DeleteFHCD(int id)1415 DeleteFHCD(int id)
1416 {
1417 FileHandler_ClientData *p, **pp;
1418
1419 pp = &HeadFHCD;
1420 while ((p = *pp) != NULL) {
1421 if (p->id == id) {
1422 *pp = p->next;
1423 Py_XDECREF(p->func);
1424 Py_XDECREF(p->file);
1425 PyMem_DEL(p);
1426 }
1427 else
1428 pp = &p->next;
1429 }
1430 }
1431
1432 static void
FileHandler(ClientData clientData,int mask)1433 FileHandler(ClientData clientData, int mask)
1434 {
1435 FileHandler_ClientData *data = (FileHandler_ClientData *)clientData;
1436 PyObject *func, *file, *arg, *res;
1437
1438 ENTER_PYTHON
1439 func = data->func;
1440 file = data->file;
1441
1442 arg = Py_BuildValue("(Oi)", file, (long) mask);
1443 res = PyEval_CallObject(func, arg);
1444 Py_DECREF(arg);
1445
1446 if (res == NULL) {
1447 errorInCmd = 1;
1448 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1449 }
1450 Py_XDECREF(res);
1451 LEAVE_PYTHON
1452 }
1453
1454 static PyObject *
Tkapp_CreateFileHandler(PyObject * self,PyObject * args)1455 Tkapp_CreateFileHandler(PyObject *self, PyObject *args)
1456 /* args is (file, mask, func) */
1457 {
1458 FileHandler_ClientData *data;
1459 PyObject *file, *func;
1460 int mask, tfile;
1461
1462 if (!PyArg_ParseTuple(args, "OiO:createfilehandler",
1463 &file, &mask, &func))
1464 return NULL;
1465 tfile = PyObject_AsFileDescriptor(file);
1466 if (tfile < 0)
1467 return NULL;
1468 if (!PyCallable_Check(func)) {
1469 PyErr_SetString(PyExc_TypeError, "bad argument list");
1470 return NULL;
1471 }
1472
1473 data = NewFHCD(func, file, tfile);
1474 if (data == NULL)
1475 return NULL;
1476
1477 /* Ought to check for null Tcl_File object... */
1478 ENTER_TCL
1479 Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data);
1480 LEAVE_TCL
1481 Py_INCREF(Py_None);
1482 return Py_None;
1483 }
1484
1485 static PyObject *
Tkapp_DeleteFileHandler(PyObject * self,PyObject * args)1486 Tkapp_DeleteFileHandler(PyObject *self, PyObject *args)
1487 {
1488 PyObject *file;
1489 int tfile;
1490
1491 if (!PyArg_ParseTuple(args, "O:deletefilehandler", &file))
1492 return NULL;
1493 tfile = PyObject_AsFileDescriptor(file);
1494 if (tfile < 0)
1495 return NULL;
1496
1497 DeleteFHCD(tfile);
1498
1499 /* Ought to check for null Tcl_File object... */
1500 ENTER_TCL
1501 Tcl_DeleteFileHandler(tfile);
1502 LEAVE_TCL
1503 Py_INCREF(Py_None);
1504 return Py_None;
1505 }
1506 #endif /* HAVE_CREATEFILEHANDLER */
1507
1508
1509 /**** Tktt Object (timer token) ****/
1510
1511 staticforward PyTypeObject Tktt_Type;
1512
1513 typedef struct {
1514 PyObject_HEAD
1515 Tcl_TimerToken token;
1516 PyObject *func;
1517 } TkttObject;
1518
1519 static PyObject *
Tktt_DeleteTimerHandler(PyObject * self,PyObject * args)1520 Tktt_DeleteTimerHandler(PyObject *self, PyObject *args)
1521 {
1522 TkttObject *v = (TkttObject *)self;
1523 PyObject *func = v->func;
1524
1525 if (!PyArg_ParseTuple(args, ":deletetimerhandler"))
1526 return NULL;
1527 if (v->token != NULL) {
1528 Tcl_DeleteTimerHandler(v->token);
1529 v->token = NULL;
1530 }
1531 if (func != NULL) {
1532 v->func = NULL;
1533 Py_DECREF(func);
1534 Py_DECREF(v); /* See Tktt_New() */
1535 }
1536 Py_INCREF(Py_None);
1537 return Py_None;
1538 }
1539
1540 static PyMethodDef Tktt_methods[] =
1541 {
1542 {"deletetimerhandler", Tktt_DeleteTimerHandler, 1},
1543 {NULL, NULL}
1544 };
1545
1546 static TkttObject *
Tktt_New(PyObject * func)1547 Tktt_New(PyObject *func)
1548 {
1549 TkttObject *v;
1550
1551 v = PyObject_New(TkttObject, &Tktt_Type);
1552 if (v == NULL)
1553 return NULL;
1554
1555 Py_INCREF(func);
1556 v->token = NULL;
1557 v->func = func;
1558
1559 /* Extra reference, deleted when called or when handler is deleted */
1560 Py_INCREF(v);
1561 return v;
1562 }
1563
1564 static void
Tktt_Dealloc(PyObject * self)1565 Tktt_Dealloc(PyObject *self)
1566 {
1567 TkttObject *v = (TkttObject *)self;
1568 PyObject *func = v->func;
1569
1570 Py_XDECREF(func);
1571
1572 PyObject_Del(self);
1573 }
1574
1575 static PyObject *
Tktt_Repr(PyObject * self)1576 Tktt_Repr(PyObject *self)
1577 {
1578 TkttObject *v = (TkttObject *)self;
1579 char buf[100];
1580
1581 sprintf(buf, "<tktimertoken at %p%s>", v,
1582 v->func == NULL ? ", handler deleted" : "");
1583 return PyString_FromString(buf);
1584 }
1585
1586 static PyObject *
Tktt_GetAttr(PyObject * self,char * name)1587 Tktt_GetAttr(PyObject *self, char *name)
1588 {
1589 return Py_FindMethod(Tktt_methods, self, name);
1590 }
1591
1592 static PyTypeObject Tktt_Type =
1593 {
1594 PyObject_HEAD_INIT(NULL)
1595 0, /*ob_size */
1596 "tktimertoken", /*tp_name */
1597 sizeof(TkttObject), /*tp_basicsize */
1598 0, /*tp_itemsize */
1599 Tktt_Dealloc, /*tp_dealloc */
1600 0, /*tp_print */
1601 Tktt_GetAttr, /*tp_getattr */
1602 0, /*tp_setattr */
1603 0, /*tp_compare */
1604 Tktt_Repr, /*tp_repr */
1605 0, /*tp_as_number */
1606 0, /*tp_as_sequence */
1607 0, /*tp_as_mapping */
1608 0, /*tp_hash */
1609 };
1610
1611
1612
1613 /** Timer Handler **/
1614
1615 static void
TimerHandler(ClientData clientData)1616 TimerHandler(ClientData clientData)
1617 {
1618 TkttObject *v = (TkttObject *)clientData;
1619 PyObject *func = v->func;
1620 PyObject *res;
1621
1622 if (func == NULL)
1623 return;
1624
1625 v->func = NULL;
1626
1627 ENTER_PYTHON
1628
1629 res = PyEval_CallObject(func, NULL);
1630 Py_DECREF(func);
1631 Py_DECREF(v); /* See Tktt_New() */
1632
1633 if (res == NULL) {
1634 errorInCmd = 1;
1635 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1636 }
1637 else
1638 Py_DECREF(res);
1639
1640 LEAVE_PYTHON
1641 }
1642
1643 static PyObject *
Tkapp_CreateTimerHandler(PyObject * self,PyObject * args)1644 Tkapp_CreateTimerHandler(PyObject *self, PyObject *args)
1645 {
1646 int milliseconds;
1647 PyObject *func;
1648 TkttObject *v;
1649
1650 if (!PyArg_ParseTuple(args, "iO:createtimerhandler",
1651 &milliseconds, &func))
1652 return NULL;
1653 if (!PyCallable_Check(func)) {
1654 PyErr_SetString(PyExc_TypeError, "bad argument list");
1655 return NULL;
1656 }
1657 v = Tktt_New(func);
1658 v->token = Tcl_CreateTimerHandler(milliseconds, TimerHandler,
1659 (ClientData)v);
1660
1661 return (PyObject *) v;
1662 }
1663
1664
1665 /** Event Loop **/
1666
1667 static PyObject *
Tkapp_MainLoop(PyObject * self,PyObject * args)1668 Tkapp_MainLoop(PyObject *self, PyObject *args)
1669 {
1670 int threshold = 0;
1671 #ifdef WITH_THREAD
1672 PyThreadState *tstate = PyThreadState_Get();
1673 #endif
1674
1675 if (!PyArg_ParseTuple(args, "|i:mainloop", &threshold))
1676 return NULL;
1677
1678 quitMainLoop = 0;
1679 while (Tk_GetNumMainWindows() > threshold &&
1680 !quitMainLoop &&
1681 !errorInCmd)
1682 {
1683 int result;
1684
1685 #ifdef WITH_THREAD
1686 Py_BEGIN_ALLOW_THREADS
1687 PyThread_acquire_lock(tcl_lock, 1);
1688 tcl_tstate = tstate;
1689 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
1690 tcl_tstate = NULL;
1691 PyThread_release_lock(tcl_lock);
1692 if (result == 0)
1693 Sleep(20);
1694 Py_END_ALLOW_THREADS
1695 #else
1696 result = Tcl_DoOneEvent(0);
1697 #endif
1698
1699 if (PyErr_CheckSignals() != 0)
1700 return NULL;
1701 if (result < 0)
1702 break;
1703 }
1704 quitMainLoop = 0;
1705
1706 if (errorInCmd) {
1707 errorInCmd = 0;
1708 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
1709 excInCmd = valInCmd = trbInCmd = NULL;
1710 return NULL;
1711 }
1712 Py_INCREF(Py_None);
1713 return Py_None;
1714 }
1715
1716 static PyObject *
Tkapp_DoOneEvent(PyObject * self,PyObject * args)1717 Tkapp_DoOneEvent(PyObject *self, PyObject *args)
1718 {
1719 int flags = 0;
1720 int rv;
1721
1722 if (!PyArg_ParseTuple(args, "|i:dooneevent", &flags))
1723 return NULL;
1724
1725 ENTER_TCL
1726 rv = Tcl_DoOneEvent(flags);
1727 LEAVE_TCL
1728 return Py_BuildValue("i", rv);
1729 }
1730
1731 static PyObject *
Tkapp_Quit(PyObject * self,PyObject * args)1732 Tkapp_Quit(PyObject *self, PyObject *args)
1733 {
1734
1735 if (!PyArg_ParseTuple(args, ":quit"))
1736 return NULL;
1737
1738 quitMainLoop = 1;
1739 Py_INCREF(Py_None);
1740 return Py_None;
1741 }
1742
1743 static PyObject *
Tkapp_InterpAddr(PyObject * self,PyObject * args)1744 Tkapp_InterpAddr(PyObject *self, PyObject *args)
1745 {
1746
1747 if (!PyArg_ParseTuple(args, ":interpaddr"))
1748 return NULL;
1749
1750 return PyInt_FromLong((long)Tkapp_Interp(self));
1751 }
1752
1753
1754
1755 /**** Tkapp Method List ****/
1756
1757 static PyMethodDef Tkapp_methods[] =
1758 {
1759 {"call", Tkapp_Call, 0},
1760 {"globalcall", Tkapp_GlobalCall, 0},
1761 {"eval", Tkapp_Eval, 1},
1762 {"globaleval", Tkapp_GlobalEval, 1},
1763 {"evalfile", Tkapp_EvalFile, 1},
1764 {"record", Tkapp_Record, 1},
1765 {"adderrorinfo", Tkapp_AddErrorInfo, 1},
1766 {"setvar", Tkapp_SetVar, 1},
1767 {"globalsetvar", Tkapp_GlobalSetVar, 1},
1768 {"getvar", Tkapp_GetVar, 1},
1769 {"globalgetvar", Tkapp_GlobalGetVar, 1},
1770 {"unsetvar", Tkapp_UnsetVar, 1},
1771 {"globalunsetvar", Tkapp_GlobalUnsetVar, 1},
1772 {"getint", Tkapp_GetInt, 1},
1773 {"getdouble", Tkapp_GetDouble, 1},
1774 {"getboolean", Tkapp_GetBoolean, 1},
1775 {"exprstring", Tkapp_ExprString, 1},
1776 {"exprlong", Tkapp_ExprLong, 1},
1777 {"exprdouble", Tkapp_ExprDouble, 1},
1778 {"exprboolean", Tkapp_ExprBoolean, 1},
1779 {"splitlist", Tkapp_SplitList, 1},
1780 {"split", Tkapp_Split, 1},
1781 {"merge", Tkapp_Merge, 0},
1782 {"createcommand", Tkapp_CreateCommand, 1},
1783 {"deletecommand", Tkapp_DeleteCommand, 1},
1784 #ifdef HAVE_CREATEFILEHANDLER
1785 {"createfilehandler", Tkapp_CreateFileHandler, 1},
1786 {"deletefilehandler", Tkapp_DeleteFileHandler, 1},
1787 #endif
1788 {"createtimerhandler", Tkapp_CreateTimerHandler, 1},
1789 {"mainloop", Tkapp_MainLoop, 1},
1790 {"dooneevent", Tkapp_DoOneEvent, 1},
1791 {"quit", Tkapp_Quit, 1},
1792 {"interpaddr", Tkapp_InterpAddr, 1},
1793 {NULL, NULL}
1794 };
1795
1796
1797
1798 /**** Tkapp Type Methods ****/
1799
1800 static void
Tkapp_Dealloc(PyObject * self)1801 Tkapp_Dealloc(PyObject *self)
1802 {
1803 ENTER_TCL
1804 Tcl_DeleteInterp(Tkapp_Interp(self));
1805 LEAVE_TCL
1806 PyObject_Del(self);
1807 DisableEventHook();
1808 }
1809
1810 static PyObject *
Tkapp_GetAttr(PyObject * self,char * name)1811 Tkapp_GetAttr(PyObject *self, char *name)
1812 {
1813 return Py_FindMethod(Tkapp_methods, self, name);
1814 }
1815
1816 static PyTypeObject Tkapp_Type =
1817 {
1818 PyObject_HEAD_INIT(NULL)
1819 0, /*ob_size */
1820 "tkapp", /*tp_name */
1821 sizeof(TkappObject), /*tp_basicsize */
1822 0, /*tp_itemsize */
1823 Tkapp_Dealloc, /*tp_dealloc */
1824 0, /*tp_print */
1825 Tkapp_GetAttr, /*tp_getattr */
1826 0, /*tp_setattr */
1827 0, /*tp_compare */
1828 0, /*tp_repr */
1829 0, /*tp_as_number */
1830 0, /*tp_as_sequence */
1831 0, /*tp_as_mapping */
1832 0, /*tp_hash */
1833 };
1834
1835
1836
1837 /**** Tkinter Module ****/
1838
1839 typedef struct {
1840 PyObject* tuple;
1841 int size; /* current size */
1842 int maxsize; /* allocated size */
1843 } FlattenContext;
1844
1845 static int
_bump(FlattenContext * context,int size)1846 _bump(FlattenContext* context, int size)
1847 {
1848 /* expand tuple to hold (at least) size new items.
1849 return true if successful, false if an exception was raised */
1850
1851 int maxsize = context->maxsize * 2;
1852
1853 if (maxsize < context->size + size)
1854 maxsize = context->size + size;
1855
1856 context->maxsize = maxsize;
1857
1858 return _PyTuple_Resize(&context->tuple, maxsize, 0) >= 0;
1859 }
1860
1861 static int
_flatten1(FlattenContext * context,PyObject * item,int depth)1862 _flatten1(FlattenContext* context, PyObject* item, int depth)
1863 {
1864 /* add tuple or list to argument tuple (recursively) */
1865
1866 int i, size;
1867
1868 if (depth > 1000) {
1869 PyErr_SetString(PyExc_ValueError,
1870 "nesting too deep in _flatten");
1871 return 0;
1872 } else if (PyList_Check(item)) {
1873 size = PyList_GET_SIZE(item);
1874 /* preallocate (assume no nesting) */
1875 if (context->size + size > context->maxsize &&
1876 !_bump(context, size))
1877 return 0;
1878 /* copy items to output tuple */
1879 for (i = 0; i < size; i++) {
1880 PyObject *o = PyList_GET_ITEM(item, i);
1881 if (PyList_Check(o) || PyTuple_Check(o)) {
1882 if (!_flatten1(context, o, depth + 1))
1883 return 0;
1884 } else if (o != Py_None) {
1885 if (context->size + 1 > context->maxsize &&
1886 !_bump(context, 1))
1887 return 0;
1888 Py_INCREF(o);
1889 PyTuple_SET_ITEM(context->tuple,
1890 context->size++, o);
1891 }
1892 }
1893 } else if (PyTuple_Check(item)) {
1894 /* same, for tuples */
1895 size = PyTuple_GET_SIZE(item);
1896 if (context->size + size > context->maxsize &&
1897 !_bump(context, size))
1898 return 0;
1899 for (i = 0; i < size; i++) {
1900 PyObject *o = PyTuple_GET_ITEM(item, i);
1901 if (PyList_Check(o) || PyTuple_Check(o)) {
1902 if (!_flatten1(context, o, depth + 1))
1903 return 0;
1904 } else if (o != Py_None) {
1905 if (context->size + 1 > context->maxsize &&
1906 !_bump(context, 1))
1907 return 0;
1908 Py_INCREF(o);
1909 PyTuple_SET_ITEM(context->tuple,
1910 context->size++, o);
1911 }
1912 }
1913 } else {
1914 PyErr_SetString(PyExc_TypeError, "argument must be sequence");
1915 return 0;
1916 }
1917 return 1;
1918 }
1919
1920 static PyObject *
Tkinter_Flatten(PyObject * self,PyObject * args)1921 Tkinter_Flatten(PyObject* self, PyObject* args)
1922 {
1923 FlattenContext context;
1924 PyObject* item;
1925
1926 if (!PyArg_ParseTuple(args, "O:_flatten", &item))
1927 return NULL;
1928
1929 context.maxsize = PySequence_Size(item);
1930 if (context.maxsize <= 0)
1931 return PyTuple_New(0);
1932
1933 context.tuple = PyTuple_New(context.maxsize);
1934 if (!context.tuple)
1935 return NULL;
1936
1937 context.size = 0;
1938
1939 if (!_flatten1(&context, item,0))
1940 return NULL;
1941
1942 if (_PyTuple_Resize(&context.tuple, context.size, 0))
1943 return NULL;
1944
1945 return context.tuple;
1946 }
1947
1948 static PyObject *
Tkinter_Create(PyObject * self,PyObject * args)1949 Tkinter_Create(PyObject *self, PyObject *args)
1950 {
1951 char *screenName = NULL;
1952 char *baseName = NULL;
1953 char *className = NULL;
1954 int interactive = 0;
1955
1956 baseName = strrchr(Py_GetProgramName(), '/');
1957 if (baseName != NULL)
1958 baseName++;
1959 else
1960 baseName = Py_GetProgramName();
1961 className = "Tk";
1962
1963 if (!PyArg_ParseTuple(args, "|zssi:create",
1964 &screenName, &baseName, &className,
1965 &interactive))
1966 return NULL;
1967
1968 return (PyObject *) Tkapp_New(screenName, baseName, className,
1969 interactive);
1970 }
1971
1972 static PyMethodDef moduleMethods[] =
1973 {
1974 {"_flatten", Tkinter_Flatten, 1},
1975 {"create", Tkinter_Create, 1},
1976 #ifdef HAVE_CREATEFILEHANDLER
1977 {"createfilehandler", Tkapp_CreateFileHandler, 1},
1978 {"deletefilehandler", Tkapp_DeleteFileHandler, 1},
1979 #endif
1980 {"createtimerhandler", Tkapp_CreateTimerHandler, 1},
1981 {"mainloop", Tkapp_MainLoop, 1},
1982 {"dooneevent", Tkapp_DoOneEvent, 1},
1983 {"quit", Tkapp_Quit, 1},
1984 {NULL, NULL}
1985 };
1986
1987 #ifdef WAIT_FOR_STDIN
1988
1989 static int stdin_ready = 0;
1990
1991 #ifndef MS_WINDOWS
1992 static void
MyFileProc(void * clientData,int mask)1993 MyFileProc(void *clientData, int mask)
1994 {
1995 stdin_ready = 1;
1996 }
1997 #endif
1998
1999 static PyThreadState *event_tstate = NULL;
2000
2001 static int
EventHook(void)2002 EventHook(void)
2003 {
2004 #ifndef MS_WINDOWS
2005 int tfile;
2006 #endif
2007 #ifdef WITH_THREAD
2008 PyEval_RestoreThread(event_tstate);
2009 #endif
2010 stdin_ready = 0;
2011 errorInCmd = 0;
2012 #ifndef MS_WINDOWS
2013 tfile = fileno(stdin);
2014 Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL);
2015 #endif
2016 while (!errorInCmd && !stdin_ready) {
2017 int result;
2018 #ifdef MS_WINDOWS
2019 if (_kbhit()) {
2020 stdin_ready = 1;
2021 break;
2022 }
2023 #endif
2024 #if defined(WITH_THREAD) || defined(MS_WINDOWS)
2025 Py_BEGIN_ALLOW_THREADS
2026 PyThread_acquire_lock(tcl_lock, 1);
2027 tcl_tstate = event_tstate;
2028
2029 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
2030
2031 tcl_tstate = NULL;
2032 PyThread_release_lock(tcl_lock);
2033 if (result == 0)
2034 Sleep(20);
2035 Py_END_ALLOW_THREADS
2036 #else
2037 result = Tcl_DoOneEvent(0);
2038 #endif
2039
2040 if (result < 0)
2041 break;
2042 }
2043 #ifndef MS_WINDOWS
2044 Tcl_DeleteFileHandler(tfile);
2045 #endif
2046 if (errorInCmd) {
2047 errorInCmd = 0;
2048 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
2049 excInCmd = valInCmd = trbInCmd = NULL;
2050 PyErr_Print();
2051 }
2052 #ifdef WITH_THREAD
2053 PyEval_SaveThread();
2054 #endif
2055 return 0;
2056 }
2057
2058 #endif
2059
2060 static void
EnableEventHook(void)2061 EnableEventHook(void)
2062 {
2063 #ifdef WAIT_FOR_STDIN
2064 if (PyOS_InputHook == NULL) {
2065 #ifdef WITH_THREAD
2066 event_tstate = PyThreadState_Get();
2067 #endif
2068 PyOS_InputHook = EventHook;
2069 }
2070 #endif
2071 }
2072
2073 static void
DisableEventHook(void)2074 DisableEventHook(void)
2075 {
2076 #ifdef WAIT_FOR_STDIN
2077 if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) {
2078 PyOS_InputHook = NULL;
2079 }
2080 #endif
2081 }
2082
2083
2084 /* all errors will be checked in one fell swoop in init_tkinter() */
2085 static void
ins_long(PyObject * d,char * name,long val)2086 ins_long(PyObject *d, char *name, long val)
2087 {
2088 PyObject *v = PyInt_FromLong(val);
2089 if (v) {
2090 PyDict_SetItemString(d, name, v);
2091 Py_DECREF(v);
2092 }
2093 }
2094 static void
ins_string(PyObject * d,char * name,char * val)2095 ins_string(PyObject *d, char *name, char *val)
2096 {
2097 PyObject *v = PyString_FromString(val);
2098 if (v) {
2099 PyDict_SetItemString(d, name, v);
2100 Py_DECREF(v);
2101 }
2102 }
2103
2104
2105 DL_EXPORT(void)
init_tkinter(void)2106 init_tkinter(void)
2107 {
2108 PyObject *m, *d;
2109
2110 Tkapp_Type.ob_type = &PyType_Type;
2111
2112 #ifdef WITH_THREAD
2113 tcl_lock = PyThread_allocate_lock();
2114 #endif
2115
2116 m = Py_InitModule("_tkinter", moduleMethods);
2117
2118 d = PyModule_GetDict(m);
2119 Tkinter_TclError = Py_BuildValue("s", "TclError");
2120 PyDict_SetItemString(d, "TclError", Tkinter_TclError);
2121
2122 ins_long(d, "READABLE", TCL_READABLE);
2123 ins_long(d, "WRITABLE", TCL_WRITABLE);
2124 ins_long(d, "EXCEPTION", TCL_EXCEPTION);
2125 ins_long(d, "WINDOW_EVENTS", TCL_WINDOW_EVENTS);
2126 ins_long(d, "FILE_EVENTS", TCL_FILE_EVENTS);
2127 ins_long(d, "TIMER_EVENTS", TCL_TIMER_EVENTS);
2128 ins_long(d, "IDLE_EVENTS", TCL_IDLE_EVENTS);
2129 ins_long(d, "ALL_EVENTS", TCL_ALL_EVENTS);
2130 ins_long(d, "DONT_WAIT", TCL_DONT_WAIT);
2131 ins_string(d, "TK_VERSION", TK_VERSION);
2132 ins_string(d, "TCL_VERSION", TCL_VERSION);
2133 #ifdef WITH_TIX
2134 ins_string(d, "TIX_VERSION", TIX_VERSION);
2135 #endif
2136
2137 PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type);
2138
2139 Tktt_Type.ob_type = &PyType_Type;
2140 PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type);
2141
2142 /* This helps the dynamic loader; in Unicode aware Tcl versions
2143 it also helps Tcl find its encodings. */
2144 Tcl_FindExecutable(Py_GetProgramName());
2145
2146 if (PyErr_Occurred())
2147 return;
2148
2149 #if 0
2150 /* This was not a good idea; through <Destroy> bindings,
2151 Tcl_Finalize() may invoke Python code but at that point the
2152 interpreter and thread state have already been destroyed! */
2153 Py_AtExit(Tcl_Finalize);
2154 #endif
2155
2156 #ifdef macintosh
2157 /*
2158 ** Part of this code is stolen from MacintoshInit in tkMacAppInit.
2159 ** Most of the initializations in that routine (toolbox init calls and
2160 ** such) have already been done for us, so we only need these.
2161 */
2162 tcl_macQdPtr = &qd;
2163
2164 Tcl_MacSetEventProc(PyMacConvertEvent);
2165 #if GENERATINGCFM
2166 mac_addlibresources();
2167 #endif /* GENERATINGCFM */
2168 #endif /* macintosh */
2169 }
2170
2171
2172
2173 #ifdef macintosh
2174
2175 /*
2176 ** Anyone who embeds Tcl/Tk on the Mac must define panic().
2177 */
2178
2179 void
panic(char * format,...)2180 panic(char * format, ...)
2181 {
2182 va_list varg;
2183
2184 va_start(varg, format);
2185
2186 vfprintf(stderr, format, varg);
2187 (void) fflush(stderr);
2188
2189 va_end(varg);
2190
2191 Py_FatalError("Tcl/Tk panic");
2192 }
2193
2194 /*
2195 ** Pass events to SIOUX before passing them to Tk.
2196 */
2197
2198 static int
PyMacConvertEvent(EventRecord * eventPtr)2199 PyMacConvertEvent(EventRecord *eventPtr)
2200 {
2201 WindowPtr frontwin;
2202 /*
2203 ** Sioux eats too many events, so we don't pass it everything. We
2204 ** always pass update events to Sioux, and we only pass other events if
2205 ** the Sioux window is frontmost. This means that Tk menus don't work
2206 ** in that case, but at least we can scroll the sioux window.
2207 ** Note that the SIOUXIsAppWindow() routine we use here is not really
2208 ** part of the external interface of Sioux...
2209 */
2210 frontwin = FrontWindow();
2211 if ( eventPtr->what == updateEvt || SIOUXIsAppWindow(frontwin) ) {
2212 if (SIOUXHandleOneEvent(eventPtr))
2213 return 0; /* Nothing happened to the Tcl event queue */
2214 }
2215 return TkMacConvertEvent(eventPtr);
2216 }
2217
2218 #if GENERATINGCFM
2219
2220 /*
2221 ** Additional Mac specific code for dealing with shared libraries.
2222 */
2223
2224 #include <Resources.h>
2225 #include <CodeFragments.h>
2226
2227 static int loaded_from_shlib = 0;
2228 static FSSpec library_fss;
2229
2230 /*
2231 ** If this module is dynamically loaded the following routine should
2232 ** be the init routine. It takes care of adding the shared library to
2233 ** the resource-file chain, so that the tk routines can find their
2234 ** resources.
2235 */
2236 OSErr pascal
init_tkinter_shlib(CFragInitBlockPtr data)2237 init_tkinter_shlib(CFragInitBlockPtr data)
2238 {
2239 __initialize();
2240 if ( data == nil ) return noErr;
2241 if ( data->fragLocator.where == kDataForkCFragLocator ) {
2242 library_fss = *data->fragLocator.u.onDisk.fileSpec;
2243 loaded_from_shlib = 1;
2244 } else if ( data->fragLocator.where == kResourceCFragLocator ) {
2245 library_fss = *data->fragLocator.u.inSegs.fileSpec;
2246 loaded_from_shlib = 1;
2247 }
2248 return noErr;
2249 }
2250
2251 /*
2252 ** Insert the library resources into the search path. Put them after
2253 ** the resources from the application. Again, we ignore errors.
2254 */
2255 static
mac_addlibresources(void)2256 mac_addlibresources(void)
2257 {
2258 if ( !loaded_from_shlib )
2259 return;
2260 (void)FSpOpenResFile(&library_fss, fsRdPerm);
2261 }
2262
2263 #endif /* GENERATINGCFM */
2264 #endif /* macintosh */
2265