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