This commit was manufactured by cvs2svn to create tag 'r23a1-fork'.
[python/dscho.git] / Modules / _tkinter.c
blob0c3d088c8294dcb4e355221253d9b6dc5a211240
1 /***********************************************************
2 Copyright (C) 1994 Steen Lumholt.
4 All Rights Reserved
6 ******************************************************************/
8 /* _tkinter.c -- Interface to libtk.a and libtcl.a. */
10 /* TCL/TK VERSION INFO:
12 Only Tcl/Tk 8.2 and later are supported. Older versions are not
13 supported. (Use Python 2.2 if you cannot upgrade your Tcl/Tk
14 libraries.)
17 /* XXX Further speed-up ideas, involving Tcl 8.0 features:
19 - Register a new Tcl type, "Python callable", which can be called more
20 efficiently and passed to Tcl_EvalObj() directly (if this is possible).
25 #include "Python.h"
26 #include <ctype.h>
28 #ifdef WITH_THREAD
29 #include "pythread.h"
30 #endif
32 #ifdef MS_WINDOWS
33 #include <windows.h>
34 #endif
36 #ifdef macintosh
37 #define MAC_TCL
38 #endif
40 /* Starting with Tcl 8.4, many APIs offer const-correctness. Unfortunately,
41 making _tkinter correct for this API means to break earlier
42 versions. USE_COMPAT_CONST allows to make _tkinter work with both 8.4 and
43 earlier versions. Once Tcl releases before 8.4 don't need to be supported
44 anymore, this should go. */
45 #define USE_COMPAT_CONST
47 /* If Tcl is compiled for threads, we must also define TCL_THREAD. We define
48 it always; if Tcl is not threaded, the thread functions in
49 Tcl are empty. */
50 #define TCL_THREADS
52 #ifdef TK_FRAMEWORK
53 #include <Tcl/tcl.h>
54 #include <Tk/tk.h>
55 #else
56 #include <tcl.h>
57 #include <tk.h>
58 #endif
60 /* For Tcl 8.2 and 8.3, CONST* is not defined. */
61 #ifndef CONST84_RETURN
62 #define CONST84_RETURN
63 #define CONST
64 #endif
66 #define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION)
68 #if TKMAJORMINOR < 8002
69 #error "Tk older than 8.2 not supported"
70 #endif
72 /* Unicode conversion assumes that Tcl_UniChar is two bytes.
73 We cannot test this directly, so we test UTF-8 size instead,
74 expecting that TCL_UTF_MAX is changed if Tcl ever supports
75 either UTF-16 or UCS-4. */
76 #if TCL_UTF_MAX != 3
77 #error "unsupported Tcl configuration"
78 #endif
80 #if defined(macintosh)
81 /* Sigh, we have to include this to get at the tcl qd pointer */
82 #include <tkMac.h>
83 /* And this one we need to clear the menu bar */
84 #include <Menus.h>
85 #endif
87 #if !(defined(MS_WINDOWS) || defined(__CYGWIN__) || defined(macintosh))
88 /* Mac has it, but it doesn't really work:-( */
89 #define HAVE_CREATEFILEHANDLER
90 #endif
92 #ifdef HAVE_CREATEFILEHANDLER
94 /* Tcl_CreateFileHandler() changed several times; these macros deal with the
95 messiness. In Tcl 8.0 and later, it is not available on Windows (and on
96 Unix, only because Jack added it back); when available on Windows, it only
97 applies to sockets. */
99 #ifdef MS_WINDOWS
100 #define FHANDLETYPE TCL_WIN_SOCKET
101 #else
102 #define FHANDLETYPE TCL_UNIX_FD
103 #endif
105 /* If Tcl can wait for a Unix file descriptor, define the EventHook() routine
106 which uses this to handle Tcl events while the user is typing commands. */
108 #if FHANDLETYPE == TCL_UNIX_FD
109 #define WAIT_FOR_STDIN
110 #endif
112 #endif /* HAVE_CREATEFILEHANDLER */
114 #ifdef MS_WINDOWS
115 #include <conio.h>
116 #define WAIT_FOR_STDIN
117 #endif
119 #ifdef WITH_THREAD
121 /* The threading situation is complicated. Tcl is not thread-safe, except
122 when configured with --enable-threads.
123 So we need to use a lock around all uses of Tcl. Previously, the Python
124 interpreter lock was used for this. However, this causes problems when
125 other Python threads need to run while Tcl is blocked waiting for events.
127 To solve this problem, a separate lock for Tcl is introduced. Holding it
128 is incompatible with holding Python's interpreter lock. The following four
129 macros manipulate both locks together.
131 ENTER_TCL and LEAVE_TCL are brackets, just like Py_BEGIN_ALLOW_THREADS and
132 Py_END_ALLOW_THREADS. They should be used whenever a call into Tcl is made
133 that could call an event handler, or otherwise affect the state of a Tcl
134 interpreter. These assume that the surrounding code has the Python
135 interpreter lock; inside the brackets, the Python interpreter lock has been
136 released and the lock for Tcl has been acquired.
138 Sometimes, it is necessary to have both the Python lock and the Tcl lock.
139 (For example, when transferring data from the Tcl interpreter result to a
140 Python string object.) This can be done by using different macros to close
141 the ENTER_TCL block: ENTER_OVERLAP reacquires the Python lock (and restores
142 the thread state) but doesn't release the Tcl lock; LEAVE_OVERLAP_TCL
143 releases the Tcl lock.
145 By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event
146 handlers when the handler needs to use Python. Such event handlers are
147 entered while the lock for Tcl is held; the event handler presumably needs
148 to use Python. ENTER_PYTHON releases the lock for Tcl and acquires
149 the Python interpreter lock, restoring the appropriate thread state, and
150 LEAVE_PYTHON releases the Python interpreter lock and re-acquires the lock
151 for Tcl. It is okay for ENTER_TCL/LEAVE_TCL pairs to be contained inside
152 the code between ENTER_PYTHON and LEAVE_PYTHON.
154 These locks expand to several statements and brackets; they should not be
155 used in branches of if statements and the like.
157 If Tcl is threaded, this approach won't work anymore. The Tcl interpreter is
158 only valid in the thread that created it, and all Tk activity must happen in this
159 thread, also. That means that the mainloop must be invoked in the thread that
160 created the interpreter. Invoking commands from other threads is possible;
161 _tkinter will queue an event for the interpreter thread, which will then
162 execute the command and pass back the result. If the main thread is not in the
163 mainloop, and invoking commands causes an exception; if the main loop is running
164 but not processing events, the command invocation will block.
166 In addition, for a threaded Tcl, a single global tcl_tstate won't be sufficient
167 anymore, since multiple Tcl interpreters may simultaneously dispatch in different
168 threads. So we use the Tcl TLS API.
172 static PyThread_type_lock tcl_lock = 0;
174 #ifdef TCL_THREADS
175 static Tcl_ThreadDataKey state_key;
176 typedef PyThreadState *ThreadSpecificData;
177 #define tcl_tstate (*(PyThreadState**)Tcl_GetThreadData(&state_key, sizeof(PyThreadState*)))
178 #else
179 static PyThreadState *tcl_tstate = NULL;
180 #endif
182 #define ENTER_TCL \
183 { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \
184 if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
186 #define LEAVE_TCL \
187 tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
189 #define ENTER_OVERLAP \
190 Py_END_ALLOW_THREADS
192 #define LEAVE_OVERLAP_TCL \
193 tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); }
195 #define ENTER_PYTHON \
196 { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
197 if(tcl_lock)PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
199 #define LEAVE_PYTHON \
200 { PyThreadState *tstate = PyEval_SaveThread(); \
201 if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }
203 #define CHECK_TCL_APPARTMENT \
204 if (((TkappObject *)self)->threaded && \
205 ((TkappObject *)self)->thread_id != Tcl_GetCurrentThread()) { \
206 PyErr_SetString(PyExc_RuntimeError, "Calling Tcl from different appartment"); \
207 return 0; \
210 #else
212 #define ENTER_TCL
213 #define LEAVE_TCL
214 #define ENTER_OVERLAP
215 #define LEAVE_OVERLAP_TCL
216 #define ENTER_PYTHON
217 #define LEAVE_PYTHON
218 #define CHECK_TCL_APPARTMENT
220 #endif
222 #ifdef macintosh
225 ** Additional cruft needed by Tcl/Tk on the Mac.
226 ** This is for Tcl 7.5 and Tk 4.1 (patch release 1).
229 /* ckfree() expects a char* */
230 #define FREECAST (char *)
232 #include <Events.h> /* For EventRecord */
234 typedef int (*TclMacConvertEventPtr) (EventRecord *eventPtr);
235 void Tcl_MacSetEventProc(TclMacConvertEventPtr procPtr);
236 int TkMacConvertEvent(EventRecord *eventPtr);
238 static int PyMacConvertEvent(EventRecord *eventPtr);
240 #include <SIOUX.h>
241 extern int SIOUXIsAppWindow(WindowPtr);
243 #endif /* macintosh */
245 #ifndef FREECAST
246 #define FREECAST (char *)
247 #endif
249 /**** Tkapp Object Declaration ****/
251 static PyTypeObject Tkapp_Type;
253 typedef struct {
254 PyObject_HEAD
255 Tcl_Interp *interp;
256 int wantobjects;
257 int threaded; /* True if tcl_platform[threaded] */
258 Tcl_ThreadId thread_id;
259 int dispatching;
260 /* We cannot include tclInt.h, as this is internal.
261 So we cache interesting types here. */
262 Tcl_ObjType *BooleanType;
263 Tcl_ObjType *ByteArrayType;
264 Tcl_ObjType *DoubleType;
265 Tcl_ObjType *IntType;
266 Tcl_ObjType *ListType;
267 Tcl_ObjType *ProcBodyType;
268 Tcl_ObjType *StringType;
269 } TkappObject;
271 #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type)
272 #define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
273 #define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v))
275 #define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \
276 (void *) v, ((PyObject *) v)->ob_refcnt))
280 /**** Error Handling ****/
282 static PyObject *Tkinter_TclError;
283 static int quitMainLoop = 0;
284 static int errorInCmd = 0;
285 static PyObject *excInCmd;
286 static PyObject *valInCmd;
287 static PyObject *trbInCmd;
291 static PyObject *
292 Tkinter_Error(PyObject *v)
294 PyErr_SetString(Tkinter_TclError, Tkapp_Result(v));
295 return NULL;
300 /**** Utils ****/
302 #ifdef WITH_THREAD
303 #ifndef MS_WINDOWS
305 /* Millisecond sleep() for Unix platforms. */
307 static void
308 Sleep(int milli)
310 /* XXX Too bad if you don't have select(). */
311 struct timeval t;
312 t.tv_sec = milli/1000;
313 t.tv_usec = (milli%1000) * 1000;
314 select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
316 #endif /* MS_WINDOWS */
317 #endif /* WITH_THREAD */
319 /* Wait up to 1s for the mainloop to come up. */
321 static int
322 WaitForMainloop(TkappObject* self)
324 int i;
325 for (i = 0; i < 10; i++) {
326 if (self->dispatching)
327 return 1;
328 Py_BEGIN_ALLOW_THREADS
329 Sleep(100);
330 Py_END_ALLOW_THREADS
332 if (self->dispatching)
333 return 1;
334 PyErr_SetString(PyExc_RuntimeError, "main thread is not in main loop");
335 return 0;
339 static char *
340 AsString(PyObject *value, PyObject *tmp)
342 if (PyString_Check(value))
343 return PyString_AsString(value);
344 #ifdef Py_USING_UNICODE
345 else if (PyUnicode_Check(value)) {
346 PyObject *v = PyUnicode_AsUTF8String(value);
347 if (v == NULL)
348 return NULL;
349 if (PyList_Append(tmp, v) != 0) {
350 Py_DECREF(v);
351 return NULL;
353 Py_DECREF(v);
354 return PyString_AsString(v);
356 #endif
357 else {
358 PyObject *v = PyObject_Str(value);
359 if (v == NULL)
360 return NULL;
361 if (PyList_Append(tmp, v) != 0) {
362 Py_DECREF(v);
363 return NULL;
365 Py_DECREF(v);
366 return PyString_AsString(v);
372 #define ARGSZ 64
374 static char *
375 Merge(PyObject *args)
377 PyObject *tmp = NULL;
378 char *argvStore[ARGSZ];
379 char **argv = NULL;
380 int fvStore[ARGSZ];
381 int *fv = NULL;
382 int argc = 0, fvc = 0, i;
383 char *res = NULL;
385 if (!(tmp = PyList_New(0)))
386 return NULL;
388 argv = argvStore;
389 fv = fvStore;
391 if (args == NULL)
392 argc = 0;
394 else if (!PyTuple_Check(args)) {
395 argc = 1;
396 fv[0] = 0;
397 if (!(argv[0] = AsString(args, tmp)))
398 goto finally;
400 else {
401 argc = PyTuple_Size(args);
403 if (argc > ARGSZ) {
404 argv = (char **)ckalloc(argc * sizeof(char *));
405 fv = (int *)ckalloc(argc * sizeof(int));
406 if (argv == NULL || fv == NULL) {
407 PyErr_NoMemory();
408 goto finally;
412 for (i = 0; i < argc; i++) {
413 PyObject *v = PyTuple_GetItem(args, i);
414 if (PyTuple_Check(v)) {
415 fv[i] = 1;
416 if (!(argv[i] = Merge(v)))
417 goto finally;
418 fvc++;
420 else if (v == Py_None) {
421 argc = i;
422 break;
424 else {
425 fv[i] = 0;
426 if (!(argv[i] = AsString(v, tmp)))
427 goto finally;
428 fvc++;
432 res = Tcl_Merge(argc, argv);
433 if (res == NULL)
434 PyErr_SetString(Tkinter_TclError, "merge failed");
436 finally:
437 for (i = 0; i < fvc; i++)
438 if (fv[i]) {
439 ckfree(argv[i]);
441 if (argv != argvStore)
442 ckfree(FREECAST argv);
443 if (fv != fvStore)
444 ckfree(FREECAST fv);
446 Py_DECREF(tmp);
447 return res;
452 static PyObject *
453 Split(char *list)
455 int argc;
456 char **argv;
457 PyObject *v;
459 if (list == NULL) {
460 Py_INCREF(Py_None);
461 return Py_None;
464 if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) {
465 /* Not a list.
466 * Could be a quoted string containing funnies, e.g. {"}.
467 * Return the string itself.
469 return PyString_FromString(list);
472 if (argc == 0)
473 v = PyString_FromString("");
474 else if (argc == 1)
475 v = PyString_FromString(argv[0]);
476 else if ((v = PyTuple_New(argc)) != NULL) {
477 int i;
478 PyObject *w;
480 for (i = 0; i < argc; i++) {
481 if ((w = Split(argv[i])) == NULL) {
482 Py_DECREF(v);
483 v = NULL;
484 break;
486 PyTuple_SetItem(v, i, w);
489 Tcl_Free(FREECAST argv);
490 return v;
493 /* In some cases, Tcl will still return strings that are supposed to be
494 lists. SplitObj walks through a nested tuple, finding string objects that
495 need to be split. */
497 PyObject *
498 SplitObj(PyObject *arg)
500 if (PyTuple_Check(arg)) {
501 int i, size;
502 PyObject *elem, *newelem, *result;
504 size = PyTuple_Size(arg);
505 result = NULL;
506 /* Recursively invoke SplitObj for all tuple items.
507 If this does not return a new object, no action is
508 needed. */
509 for(i = 0; i < size; i++) {
510 elem = PyTuple_GetItem(arg, i);
511 newelem = SplitObj(elem);
512 if (!newelem) {
513 Py_XDECREF(result);
514 return NULL;
516 if (!result) {
517 int k;
518 if (newelem == elem) {
519 Py_DECREF(newelem);
520 continue;
522 result = PyTuple_New(size);
523 if (!result)
524 return NULL;
525 for(k = 0; k < i; k++) {
526 elem = PyTuple_GetItem(arg, k);
527 Py_INCREF(elem);
528 PyTuple_SetItem(result, k, elem);
531 PyTuple_SetItem(result, i, newelem);
533 if (result)
534 return result;
535 /* Fall through, returning arg. */
537 else if (PyString_Check(arg)) {
538 int argc;
539 char **argv;
540 char *list = PyString_AsString(arg);
542 if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) {
543 Py_INCREF(arg);
544 return arg;
546 Tcl_Free(FREECAST argv);
547 if (argc > 1)
548 return Split(PyString_AsString(arg));
549 /* Fall through, returning arg. */
551 Py_INCREF(arg);
552 return arg;
556 /**** Tkapp Object ****/
558 #ifndef WITH_APPINIT
560 Tcl_AppInit(Tcl_Interp *interp)
562 Tk_Window main;
564 main = Tk_MainWindow(interp);
565 if (Tcl_Init(interp) == TCL_ERROR) {
566 PySys_WriteStderr("Tcl_Init error: %s\n", Tcl_GetStringResult(interp));
567 return TCL_ERROR;
569 if (Tk_Init(interp) == TCL_ERROR) {
570 PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp));
571 return TCL_ERROR;
573 return TCL_OK;
575 #endif /* !WITH_APPINIT */
580 /* Initialize the Tk application; see the `main' function in
581 * `tkMain.c'.
584 static void EnableEventHook(void); /* Forward */
585 static void DisableEventHook(void); /* Forward */
587 static TkappObject *
588 Tkapp_New(char *screenName, char *baseName, char *className,
589 int interactive, int wantobjects)
591 TkappObject *v;
592 char *argv0;
594 v = PyObject_New(TkappObject, &Tkapp_Type);
595 if (v == NULL)
596 return NULL;
598 v->interp = Tcl_CreateInterp();
599 v->wantobjects = wantobjects;
600 v->threaded = Tcl_GetVar2Ex(v->interp, "tcl_platform", "threaded",
601 TCL_GLOBAL_ONLY) != NULL;
602 v->thread_id = Tcl_GetCurrentThread();
603 v->dispatching = 0;
605 #ifndef TCL_THREADS
606 if (v->threaded) {
607 PyErr_SetString(PyExc_RuntimeError, "Tcl is threaded but _tkinter is not");
608 Py_DECREF(v);
609 return 0;
611 #endif
612 if (v->threaded && tcl_lock) {
613 /* If Tcl is threaded, we don't need the lock. */
614 PyThread_free_lock(tcl_lock);
615 tcl_lock = NULL;
618 v->BooleanType = Tcl_GetObjType("boolean");
619 v->ByteArrayType = Tcl_GetObjType("bytearray");
620 v->DoubleType = Tcl_GetObjType("double");
621 v->IntType = Tcl_GetObjType("int");
622 v->ListType = Tcl_GetObjType("list");
623 v->ProcBodyType = Tcl_GetObjType("procbody");
624 v->StringType = Tcl_GetObjType("string");
626 #if defined(macintosh)
627 /* This seems to be needed */
628 ClearMenuBar();
629 TkMacInitMenus(v->interp);
630 #endif
632 /* Delete the 'exit' command, which can screw things up */
633 Tcl_DeleteCommand(v->interp, "exit");
635 if (screenName != NULL)
636 Tcl_SetVar2(v->interp, "env", "DISPLAY",
637 screenName, TCL_GLOBAL_ONLY);
639 if (interactive)
640 Tcl_SetVar(v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
641 else
642 Tcl_SetVar(v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
644 /* This is used to get the application class for Tk 4.1 and up */
645 argv0 = (char*)ckalloc(strlen(className) + 1);
646 if (!argv0) {
647 PyErr_NoMemory();
648 Py_DECREF(v);
649 return NULL;
652 strcpy(argv0, className);
653 if (isupper((int)(argv0[0])))
654 argv0[0] = tolower(argv0[0]);
655 Tcl_SetVar(v->interp, "argv0", argv0, TCL_GLOBAL_ONLY);
656 ckfree(argv0);
658 if (Tcl_AppInit(v->interp) != TCL_OK)
659 return (TkappObject *)Tkinter_Error((PyObject *)v);
661 EnableEventHook();
663 return v;
667 static void
668 Tkapp_ThreadSend(TkappObject *self, Tcl_Event *ev,
669 Tcl_Condition *cond, Tcl_Mutex *mutex)
671 Py_BEGIN_ALLOW_THREADS;
672 Tcl_MutexLock(mutex);
673 Tcl_ThreadQueueEvent(self->thread_id, ev, TCL_QUEUE_TAIL);
674 Tcl_ThreadAlert(self->thread_id);
675 Tcl_ConditionWait(cond, mutex, NULL);
676 Tcl_MutexUnlock(mutex);
677 Py_END_ALLOW_THREADS
681 /** Tcl Eval **/
683 typedef struct {
684 PyObject_HEAD
685 Tcl_Obj *value;
686 } PyTclObject;
688 staticforward PyTypeObject PyTclObject_Type;
689 #define PyTclObject_Check(v) ((v)->ob_type == &PyTclObject_Type)
691 static PyObject *
692 newPyTclObject(Tcl_Obj *arg)
694 PyTclObject *self;
695 self = PyObject_New(PyTclObject, &PyTclObject_Type);
696 if (self == NULL)
697 return NULL;
698 Tcl_IncrRefCount(arg);
699 self->value = arg;
700 return (PyObject*)self;
703 static void
704 PyTclObject_dealloc(PyTclObject *self)
706 Tcl_DecrRefCount(self->value);
707 PyObject_Del(self);
710 static PyObject *
711 PyTclObject_str(PyTclObject *self)
713 return PyString_FromString(Tcl_GetString(self->value));
716 static PyObject *
717 PyTclObject_repr(PyTclObject *self)
719 char buf[50];
720 PyOS_snprintf(buf, 50, "<%s object at 0x%.8x>",
721 self->value->typePtr->name, (int)self->value);
722 return PyString_FromString(buf);
725 static PyObject*
726 get_typename(PyTclObject* obj, void* ignored)
728 return PyString_FromString(obj->value->typePtr->name);
731 static PyGetSetDef PyTclObject_getsetlist[] = {
732 {"typename", (getter)get_typename, NULL, "name of the Tcl type"},
733 {0},
736 statichere PyTypeObject PyTclObject_Type = {
737 PyObject_HEAD_INIT(NULL)
738 0, /*ob_size*/
739 "_tkinter.Tcl_Obj", /*tp_name*/
740 sizeof(PyTclObject), /*tp_basicsize*/
741 0, /*tp_itemsize*/
742 /* methods */
743 (destructor)PyTclObject_dealloc, /*tp_dealloc*/
744 0, /*tp_print*/
745 0, /*tp_getattr*/
746 0, /*tp_setattr*/
747 0, /*tp_compare*/
748 (reprfunc)PyTclObject_repr, /*tp_repr*/
749 0, /*tp_as_number*/
750 0, /*tp_as_sequence*/
751 0, /*tp_as_mapping*/
752 0, /*tp_hash*/
753 0, /*tp_call*/
754 (reprfunc)PyTclObject_str, /*tp_str*/
755 PyObject_GenericGetAttr,/*tp_getattro*/
756 0, /*tp_setattro*/
757 0, /*tp_as_buffer*/
758 Py_TPFLAGS_DEFAULT, /*tp_flags*/
759 0, /*tp_doc*/
760 0, /*tp_traverse*/
761 0, /*tp_clear*/
762 0, /*tp_richcompare*/
763 0, /*tp_weaklistoffset*/
764 0, /*tp_iter*/
765 0, /*tp_iternext*/
766 0, /*tp_methods*/
767 0, /*tp_members*/
768 PyTclObject_getsetlist, /*tp_getset*/
769 0, /*tp_base*/
770 0, /*tp_dict*/
771 0, /*tp_descr_get*/
772 0, /*tp_descr_set*/
773 0, /*tp_dictoffset*/
774 0, /*tp_init*/
775 0, /*tp_alloc*/
776 0, /*tp_new*/
777 0, /*tp_free*/
778 0, /*tp_is_gc*/
781 static Tcl_Obj*
782 AsObj(PyObject *value)
784 Tcl_Obj *result;
786 if (PyString_Check(value))
787 return Tcl_NewStringObj(PyString_AS_STRING(value),
788 PyString_GET_SIZE(value));
789 else if (PyInt_Check(value))
790 return Tcl_NewLongObj(PyInt_AS_LONG(value));
791 else if (PyFloat_Check(value))
792 return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value));
793 else if (PyTuple_Check(value)) {
794 Tcl_Obj **argv = (Tcl_Obj**)
795 ckalloc(PyTuple_Size(value)*sizeof(Tcl_Obj*));
796 int i;
797 if(!argv)
798 return 0;
799 for(i=0;i<PyTuple_Size(value);i++)
800 argv[i] = AsObj(PyTuple_GetItem(value,i));
801 result = Tcl_NewListObj(PyTuple_Size(value), argv);
802 ckfree(FREECAST argv);
803 return result;
805 #ifdef Py_USING_UNICODE
806 else if (PyUnicode_Check(value)) {
807 Py_UNICODE *inbuf = PyUnicode_AS_UNICODE(value);
808 int size = PyUnicode_GET_SIZE(value);
809 /* This #ifdef assumes that Tcl uses UCS-2.
810 See TCL_UTF_MAX test above. */
811 #ifdef Py_UNICODE_WIDE
812 Tcl_UniChar *outbuf;
813 int i;
814 outbuf = (Tcl_UniChar*)ckalloc(size * sizeof(Tcl_UniChar));
815 if (!outbuf) {
816 PyErr_NoMemory();
817 return NULL;
819 for (i = 0; i < size; i++) {
820 if (inbuf[i] >= 0x10000) {
821 /* Tcl doesn't do UTF-16, yet. */
822 PyErr_SetString(PyExc_ValueError,
823 "unsupported character");
824 ckfree(FREECAST outbuf);
825 return NULL;
827 outbuf[i] = inbuf[i];
829 result = Tcl_NewUnicodeObj(outbuf, size);
830 ckfree(FREECAST outbuf);
831 return result;
832 #else
833 return Tcl_NewUnicodeObj(inbuf, size);
834 #endif
837 #endif
838 else if(PyTclObject_Check(value)) {
839 Tcl_Obj *v = ((PyTclObject*)value)->value;
840 Tcl_IncrRefCount(v);
841 return v;
843 else {
844 PyObject *v = PyObject_Str(value);
845 if (!v)
846 return 0;
847 result = AsObj(v);
848 Py_DECREF(v);
849 return result;
853 static PyObject*
854 FromObj(PyObject* tkapp, Tcl_Obj *value)
856 PyObject *result = NULL;
857 TkappObject *app = (TkappObject*)tkapp;
859 if (value->typePtr == NULL) {
860 /* If the result contains any bytes with the top bit set,
861 it's UTF-8 and we should decode it to Unicode */
862 #ifdef Py_USING_UNICODE
863 int i;
864 char *s = value->bytes;
865 int len = value->length;
866 for (i = 0; i < len; i++) {
867 if (value->bytes[i] & 0x80)
868 break;
871 if (i == value->length)
872 result = PyString_FromStringAndSize(s, len);
873 else {
874 /* Convert UTF-8 to Unicode string */
875 result = PyUnicode_DecodeUTF8(s, len, "strict");
876 if (result == NULL) {
877 PyErr_Clear();
878 result = PyString_FromStringAndSize(s, len);
881 #else
882 res = PyString_FromStringAndSize(value->bytes, value->length);
883 #endif
884 return result;
887 if (value->typePtr == app->BooleanType) {
888 result = value->internalRep.longValue ? Py_True : Py_False;
889 Py_INCREF(result);
890 return result;
893 if (value->typePtr == app->ByteArrayType) {
894 int size;
895 char *data = (char*)Tcl_GetByteArrayFromObj(value, &size);
896 return PyString_FromStringAndSize(data, size);
899 if (value->typePtr == app->DoubleType) {
900 return PyFloat_FromDouble(value->internalRep.doubleValue);
903 if (value->typePtr == app->IntType) {
904 return PyInt_FromLong(value->internalRep.longValue);
907 if (value->typePtr == app->ListType) {
908 int size;
909 int i, status;
910 PyObject *elem;
911 Tcl_Obj *tcl_elem;
913 status = Tcl_ListObjLength(Tkapp_Interp(tkapp), value, &size);
914 if (status == TCL_ERROR)
915 return Tkinter_Error(tkapp);
916 result = PyTuple_New(size);
917 if (!result)
918 return NULL;
919 for (i = 0; i < size; i++) {
920 status = Tcl_ListObjIndex(Tkapp_Interp(tkapp),
921 value, i, &tcl_elem);
922 if (status == TCL_ERROR) {
923 Py_DECREF(result);
924 return Tkinter_Error(tkapp);
926 elem = FromObj(tkapp, tcl_elem);
927 if (!elem) {
928 Py_DECREF(result);
929 return NULL;
931 PyTuple_SetItem(result, i, elem);
933 return result;
936 if (value->typePtr == app->ProcBodyType) {
937 /* fall through: return tcl object. */
940 if (value->typePtr == app->StringType) {
941 #ifdef Py_USING_UNICODE
942 #ifdef Py_UNICODE_WIDE
943 PyObject *result;
944 int size;
945 Tcl_UniChar *input;
946 Py_UNICODE *output;
948 size = Tcl_GetCharLength(value);
949 result = PyUnicode_FromUnicode(NULL, size);
950 if (!result)
951 return NULL;
952 input = Tcl_GetUnicode(value);
953 output = PyUnicode_AS_UNICODE(result);
954 while (size--)
955 *output++ = *input++;
956 return result;
957 #else
958 return PyUnicode_FromUnicode(Tcl_GetUnicode(value),
959 Tcl_GetCharLength(value));
960 #endif
961 #else
962 int size;
963 char *c;
964 c = Tcl_GetStringFromObj(value, &size);
965 return PyString_FromStringAndSize(c, size);
966 #endif
969 return newPyTclObject(value);
972 /* This mutex synchronizes inter-thread command calls. */
974 TCL_DECLARE_MUTEX(call_mutex)
976 typedef struct Tkapp_CallEvent {
977 Tcl_Event ev; /* Must be first */
978 TkappObject *self;
979 PyObject *args;
980 int flags;
981 PyObject **res;
982 PyObject **exc_type, **exc_value, **exc_tb;
983 Tcl_Condition done;
984 } Tkapp_CallEvent;
986 void
987 Tkapp_CallDeallocArgs(Tcl_Obj** objv, Tcl_Obj** objStore, int objc)
989 int i;
990 for (i = 0; i < objc; i++)
991 Tcl_DecrRefCount(objv[i]);
992 if (objv != objStore)
993 ckfree(FREECAST objv);
996 /* Convert Python objects to Tcl objects. This must happen in the
997 interpreter thread, which may or may not be the calling thread. */
999 static Tcl_Obj**
1000 Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc)
1002 Tcl_Obj **objv = objStore;
1003 int objc = 0, i;
1004 if (args == NULL)
1005 /* do nothing */;
1007 else if (!PyTuple_Check(args)) {
1008 objv[0] = AsObj(args);
1009 if (objv[0] == 0)
1010 goto finally;
1011 objc = 1;
1012 Tcl_IncrRefCount(objv[0]);
1014 else {
1015 objc = PyTuple_Size(args);
1017 if (objc > ARGSZ) {
1018 objv = (Tcl_Obj **)ckalloc(objc * sizeof(char *));
1019 if (objv == NULL) {
1020 PyErr_NoMemory();
1021 objc = 0;
1022 goto finally;
1026 for (i = 0; i < objc; i++) {
1027 PyObject *v = PyTuple_GetItem(args, i);
1028 if (v == Py_None) {
1029 objc = i;
1030 break;
1032 objv[i] = AsObj(v);
1033 if (!objv[i]) {
1034 /* Reset objc, so it attempts to clear
1035 objects only up to i. */
1036 objc = i;
1037 goto finally;
1039 Tcl_IncrRefCount(objv[i]);
1042 *pobjc = objc;
1043 return objv;
1044 finally:
1045 Tkapp_CallDeallocArgs(objv, objStore, objc);
1046 return NULL;
1049 /* Convert the results of a command call into a Python objects. */
1051 static PyObject*
1052 Tkapp_CallResult(TkappObject *self)
1054 PyObject *res = NULL;
1055 if(self->wantobjects) {
1056 Tcl_Obj *value = Tcl_GetObjResult(self->interp);
1057 /* Not sure whether the IncrRef is necessary, but something
1058 may overwrite the interpreter result while we are
1059 converting it. */
1060 Tcl_IncrRefCount(value);
1061 res = FromObj((PyObject*)self, value);
1062 Tcl_DecrRefCount(value);
1063 } else {
1064 const char *s = Tcl_GetStringResult(self->interp);
1065 const char *p = s;
1067 /* If the result contains any bytes with the top bit set,
1068 it's UTF-8 and we should decode it to Unicode */
1069 #ifdef Py_USING_UNICODE
1070 while (*p != '\0') {
1071 if (*p & 0x80)
1072 break;
1073 p++;
1076 if (*p == '\0')
1077 res = PyString_FromStringAndSize(s, (int)(p-s));
1078 else {
1079 /* Convert UTF-8 to Unicode string */
1080 p = strchr(p, '\0');
1081 res = PyUnicode_DecodeUTF8(s, (int)(p-s), "strict");
1082 if (res == NULL) {
1083 PyErr_Clear();
1084 res = PyString_FromStringAndSize(s, (int)(p-s));
1087 #else
1088 p = strchr(p, '\0');
1089 res = PyString_FromStringAndSize(s, (int)(p-s));
1090 #endif
1092 return res;
1095 /* Tkapp_CallProc is the event procedure that is executed in the context of
1096 the Tcl interpreter thread. Initially, it holds the Tcl lock, and doesn't
1097 hold the Python lock. */
1099 static int
1100 Tkapp_CallProc(Tkapp_CallEvent *e, int flags)
1102 Tcl_Obj *objStore[ARGSZ];
1103 Tcl_Obj **objv;
1104 int objc;
1105 int i;
1106 ENTER_PYTHON
1107 objv = Tkapp_CallArgs(e->args, objStore, &objc);
1108 if (!objv) {
1109 PyErr_Fetch(e->exc_type, e->exc_value, e->exc_tb);
1110 *(e->res) = NULL;
1112 LEAVE_PYTHON
1113 if (!objv)
1114 goto done;
1115 i = Tcl_EvalObjv(e->self->interp, objc, objv, e->flags);
1116 ENTER_PYTHON
1117 if (i == TCL_ERROR) {
1118 *(e->res) = NULL;
1119 *(e->exc_type) = NULL;
1120 *(e->exc_tb) = NULL;
1121 *(e->exc_value) = PyObject_CallFunction(
1122 Tkinter_TclError, "s",
1123 Tcl_GetStringResult(e->self->interp));
1125 else {
1126 *(e->res) = Tkapp_CallResult(e->self);
1128 LEAVE_PYTHON
1129 done:
1130 /* Wake up calling thread. */
1131 Tcl_MutexLock(&call_mutex);
1132 Tcl_ConditionNotify(&e->done);
1133 Tcl_MutexUnlock(&call_mutex);
1134 return 1;
1137 /* This is the main entry point for calling a Tcl command.
1138 It supports three cases, with regard to threading:
1139 1. Tcl is not threaded: Must have the Tcl lock, then can invoke command in
1140 the context of the calling thread.
1141 2. Tcl is threaded, caller of the command is in the interpreter thread:
1142 Execute the command in the calling thread. Since the Tcl lock will
1143 not be used, we can merge that with case 1.
1144 3. Tcl is threaded, caller is in a different thread: Must queue an event to
1145 the interpreter thread. Allocation of Tcl objects needs to occur in the
1146 interpreter thread, so we ship the PyObject* args to the target thread,
1147 and perform processing there. */
1149 static PyObject *
1150 Tkapp_Call(PyObject *_self, PyObject *args)
1152 Tcl_Obj *objStore[ARGSZ];
1153 Tcl_Obj **objv = NULL;
1154 int objc, i;
1155 PyObject *res = NULL;
1156 TkappObject *self = (TkappObject*)_self;
1157 /* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */
1158 int flags = TCL_EVAL_DIRECT;
1160 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
1161 /* We cannot call the command directly. Instead, we must
1162 marshal the parameters to the interpreter thread. */
1163 Tkapp_CallEvent *ev;
1164 PyObject *exc_type, *exc_value, *exc_tb;
1165 if (!WaitForMainloop(self))
1166 return NULL;
1167 ev = (Tkapp_CallEvent*)ckalloc(sizeof(Tkapp_CallEvent));
1168 ev->ev.proc = (Tcl_EventProc*)Tkapp_CallProc;
1169 ev->self = self;
1170 ev->args = args;
1171 ev->res = &res;
1172 ev->exc_type = &exc_type;
1173 ev->exc_value = &exc_value;
1174 ev->exc_tb = &exc_tb;
1175 ev->done = (Tcl_Condition)0;
1177 Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->done, &call_mutex);
1179 if (res == NULL) {
1180 if (exc_type)
1181 PyErr_Restore(exc_type, exc_value, exc_tb);
1182 else
1183 PyErr_SetObject(Tkinter_TclError, exc_value);
1186 else {
1188 objv = Tkapp_CallArgs(args, objStore, &objc);
1189 if (!objv)
1190 return NULL;
1192 ENTER_TCL
1194 i = Tcl_EvalObjv(self->interp, objc, objv, flags);
1196 ENTER_OVERLAP
1198 if (i == TCL_ERROR)
1199 Tkinter_Error(_self);
1200 else
1201 res = Tkapp_CallResult(self);
1203 LEAVE_OVERLAP_TCL
1205 Tkapp_CallDeallocArgs(objv, objStore, objc);
1207 return res;
1211 static PyObject *
1212 Tkapp_GlobalCall(PyObject *self, PyObject *args)
1214 /* Could do the same here as for Tkapp_Call(), but this is not used
1215 much, so I can't be bothered. Unfortunately Tcl doesn't export a
1216 way for the user to do what all its Global* variants do (save and
1217 reset the scope pointer, call the local version, restore the saved
1218 scope pointer). */
1220 char *cmd;
1221 PyObject *res = NULL;
1223 CHECK_TCL_APPARTMENT;
1225 cmd = Merge(args);
1226 if (cmd) {
1227 int err;
1228 ENTER_TCL
1229 err = Tcl_GlobalEval(Tkapp_Interp(self), cmd);
1230 ENTER_OVERLAP
1231 if (err == TCL_ERROR)
1232 res = Tkinter_Error(self);
1233 else
1234 res = PyString_FromString(Tkapp_Result(self));
1235 LEAVE_OVERLAP_TCL
1236 ckfree(cmd);
1239 return res;
1242 static PyObject *
1243 Tkapp_Eval(PyObject *self, PyObject *args)
1245 char *script;
1246 PyObject *res = NULL;
1247 int err;
1249 if (!PyArg_ParseTuple(args, "s:eval", &script))
1250 return NULL;
1252 CHECK_TCL_APPARTMENT;
1254 ENTER_TCL
1255 err = Tcl_Eval(Tkapp_Interp(self), script);
1256 ENTER_OVERLAP
1257 if (err == TCL_ERROR)
1258 res = Tkinter_Error(self);
1259 else
1260 res = PyString_FromString(Tkapp_Result(self));
1261 LEAVE_OVERLAP_TCL
1262 return res;
1265 static PyObject *
1266 Tkapp_GlobalEval(PyObject *self, PyObject *args)
1268 char *script;
1269 PyObject *res = NULL;
1270 int err;
1272 if (!PyArg_ParseTuple(args, "s:globaleval", &script))
1273 return NULL;
1275 CHECK_TCL_APPARTMENT;
1277 ENTER_TCL
1278 err = Tcl_GlobalEval(Tkapp_Interp(self), script);
1279 ENTER_OVERLAP
1280 if (err == TCL_ERROR)
1281 res = Tkinter_Error(self);
1282 else
1283 res = PyString_FromString(Tkapp_Result(self));
1284 LEAVE_OVERLAP_TCL
1285 return res;
1288 static PyObject *
1289 Tkapp_EvalFile(PyObject *self, PyObject *args)
1291 char *fileName;
1292 PyObject *res = NULL;
1293 int err;
1295 if (!PyArg_ParseTuple(args, "s:evalfile", &fileName))
1296 return NULL;
1298 CHECK_TCL_APPARTMENT;
1300 ENTER_TCL
1301 err = Tcl_EvalFile(Tkapp_Interp(self), fileName);
1302 ENTER_OVERLAP
1303 if (err == TCL_ERROR)
1304 res = Tkinter_Error(self);
1306 else
1307 res = PyString_FromString(Tkapp_Result(self));
1308 LEAVE_OVERLAP_TCL
1309 return res;
1312 static PyObject *
1313 Tkapp_Record(PyObject *self, PyObject *args)
1315 char *script;
1316 PyObject *res = NULL;
1317 int err;
1319 if (!PyArg_ParseTuple(args, "s", &script))
1320 return NULL;
1322 CHECK_TCL_APPARTMENT;
1324 ENTER_TCL
1325 err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL);
1326 ENTER_OVERLAP
1327 if (err == TCL_ERROR)
1328 res = Tkinter_Error(self);
1329 else
1330 res = PyString_FromString(Tkapp_Result(self));
1331 LEAVE_OVERLAP_TCL
1332 return res;
1335 static PyObject *
1336 Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
1338 char *msg;
1340 if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg))
1341 return NULL;
1342 CHECK_TCL_APPARTMENT;
1344 ENTER_TCL
1345 Tcl_AddErrorInfo(Tkapp_Interp(self), msg);
1346 LEAVE_TCL
1348 Py_INCREF(Py_None);
1349 return Py_None;
1354 /** Tcl Variable **/
1356 TCL_DECLARE_MUTEX(var_mutex)
1358 typedef CONST84_RETURN char* (*EventFunc1)(Tcl_Interp*, CONST char*, int);
1359 typedef CONST84_RETURN char* (*EventFunc2)(Tcl_Interp*, CONST char*, CONST char*, int);
1360 typedef CONST84_RETURN char* (*EventFunc3)(Tcl_Interp*, CONST char*, CONST char*, CONST char*, int);
1361 typedef struct VarEvent {
1362 Tcl_Event ev; /* must be first */
1363 TkappObject *self;
1364 char* arg1;
1365 char* arg2;
1366 char* arg3;
1367 int flags;
1368 EventFunc1 func1;
1369 EventFunc2 func2;
1370 EventFunc3 func3;
1371 PyObject **res;
1372 PyObject **exc;
1373 Tcl_Condition cond;
1374 int coderesult;
1375 } VarEvent;
1377 static const char*
1378 var_perform(VarEvent *ev)
1380 if (!ev->arg2 && !ev->arg2)
1381 return ev->func1(ev->self->interp, ev->arg1, ev->flags);
1382 if (!ev->arg3)
1383 return ev->func2(ev->self->interp, ev->arg1,
1384 ev->arg2, ev->flags);
1385 return ev->func3(ev->self->interp, ev->arg1, ev->arg2,
1386 ev->arg3, ev->flags);
1389 static void
1390 var_fill_result(VarEvent *ev, const char* res)
1392 if (ev->coderesult) {
1393 if ((int)res != TCL_ERROR) {
1394 Py_INCREF(Py_None);
1395 *(ev->res) = Py_None;
1396 return;
1399 else if (res) {
1400 *(ev->res) = PyString_FromString(res);
1401 return;
1404 *(ev->res) = NULL;
1405 *(ev->exc) = PyObject_CallFunction(
1406 Tkinter_TclError, "s",
1407 Tcl_GetStringResult(ev->self->interp));
1411 static int
1412 var_proc(VarEvent* ev, int flags)
1414 const char *result = var_perform(ev);
1415 ENTER_PYTHON
1416 var_fill_result(ev, result);
1417 Tcl_MutexLock(&var_mutex);
1418 Tcl_ConditionNotify(&ev->cond);
1419 Tcl_MutexUnlock(&var_mutex);
1420 LEAVE_PYTHON
1421 return 1;
1424 static PyObject*
1425 var_invoke(PyObject *_self, char* arg1, char* arg2, char* arg3, int flags,
1426 EventFunc1 func1, EventFunc2 func2, EventFunc3 func3,
1427 int coderesult)
1429 VarEvent _ev;
1430 TkappObject *self = (TkappObject*)_self;
1431 VarEvent *ev = self->threaded ?
1432 (VarEvent*)ckalloc(sizeof(VarEvent)) : &_ev;
1433 PyObject *res, *exc;
1435 ev->self = self;
1436 ev->arg1 = arg1;
1437 ev->arg2 = arg2;
1438 ev->arg3 = arg3;
1439 ev->flags = flags;
1440 ev->func1 = func1;
1441 ev->func2 = func2;
1442 ev->func3 = func3;
1443 ev->coderesult = coderesult;
1444 ev->res = &res;
1445 ev->exc = &exc;
1446 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
1447 /* The current thread is not the interpreter thread. Marshal
1448 the call to the interpreter thread, then wait for
1449 completion. */
1451 if (!WaitForMainloop(self))
1452 return NULL;
1453 ev->cond = NULL;
1454 ev->ev.proc = (Tcl_EventProc*)var_proc;
1455 Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->cond, &var_mutex);
1457 else {
1458 /* Tcl is not threaded, or this is the interpreter thread. To
1459 perform the call, we must hold the TCL lock. To receive the
1460 results, we must also hold the Python lock. */
1461 const char *result;
1462 ENTER_TCL
1463 result = var_perform(ev);
1464 ENTER_OVERLAP
1465 var_fill_result(ev, result);
1466 LEAVE_OVERLAP_TCL
1468 if (!res) {
1469 PyErr_SetObject(Tkinter_TclError, exc);
1470 return NULL;
1472 return res;
1475 static PyObject*
1476 var_invoke2(PyObject *_self, char* arg1, char* arg2, char* arg3, int flags,
1477 int (*func1)(Tcl_Interp*, CONST char*, int),
1478 int (*func2)(Tcl_Interp*, CONST char*, CONST char*, int),
1479 int (*func3)(Tcl_Interp*, CONST char*, CONST char*, CONST char*, int))
1481 return var_invoke(_self, arg1, arg2, arg3, flags,
1482 (EventFunc1)func1, (EventFunc2)func2,
1483 (EventFunc3)func3, 1);
1486 static PyObject *
1487 SetVar(PyObject *self, PyObject *args, int flags)
1489 char *name1, *name2, *s;
1490 PyObject *res;
1491 PyObject *newValue;
1492 PyObject *tmp;
1494 tmp = PyList_New(0);
1495 if (!tmp)
1496 return NULL;
1498 if (PyArg_ParseTuple(args, "sO:setvar", &name1, &newValue)) {
1499 /* XXX Merge? */
1500 s = AsString(newValue, tmp);
1501 if (s == NULL)
1502 return NULL;
1503 res = var_invoke(self, name1, s, NULL, flags,
1504 NULL, Tcl_SetVar, NULL, 0);
1506 else {
1507 PyErr_Clear();
1508 if (PyArg_ParseTuple(args, "ssO:setvar",
1509 &name1, &name2, &newValue)) {
1510 s = AsString(newValue, tmp);
1511 if (s == NULL)
1512 return NULL;
1513 res = var_invoke(self, name1, name2, s, flags,
1514 NULL, NULL, Tcl_SetVar2, 0);
1516 else {
1517 Py_DECREF(tmp);
1518 return NULL;
1521 Py_DECREF(tmp);
1523 if (!res)
1524 return NULL;
1526 Py_DECREF(res);
1527 Py_INCREF(Py_None);
1528 return Py_None;
1531 static PyObject *
1532 Tkapp_SetVar(PyObject *self, PyObject *args)
1534 return SetVar(self, args, TCL_LEAVE_ERR_MSG);
1537 static PyObject *
1538 Tkapp_GlobalSetVar(PyObject *self, PyObject *args)
1540 return SetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1545 static PyObject *
1546 GetVar(PyObject *self, PyObject *args, int flags)
1548 char *name1, *name2=NULL;
1549 PyObject *res = NULL;
1551 if (!PyArg_ParseTuple(args, "s|s:getvar", &name1, &name2))
1552 return NULL;
1554 res = var_invoke(self, name1, name2, NULL, flags,
1555 Tcl_GetVar, Tcl_GetVar2, NULL, 0);
1556 return res;
1559 static PyObject *
1560 Tkapp_GetVar(PyObject *self, PyObject *args)
1562 return GetVar(self, args, TCL_LEAVE_ERR_MSG);
1565 static PyObject *
1566 Tkapp_GlobalGetVar(PyObject *self, PyObject *args)
1568 return GetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1573 static PyObject *
1574 UnsetVar(PyObject *self, PyObject *args, int flags)
1576 char *name1, *name2=NULL;
1577 PyObject *res = NULL;
1579 if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2))
1580 return NULL;
1582 res = var_invoke2(self, name1, name2, NULL, flags,
1583 Tcl_UnsetVar, Tcl_UnsetVar2, NULL);
1584 return res;
1587 static PyObject *
1588 Tkapp_UnsetVar(PyObject *self, PyObject *args)
1590 return UnsetVar(self, args, TCL_LEAVE_ERR_MSG);
1593 static PyObject *
1594 Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args)
1596 return UnsetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
1601 /** Tcl to Python **/
1603 static PyObject *
1604 Tkapp_GetInt(PyObject *self, PyObject *args)
1606 char *s;
1607 int v;
1609 if (PyTuple_Size(args) == 1) {
1610 PyObject* o = PyTuple_GetItem(args, 0);
1611 if (PyInt_Check(o)) {
1612 Py_INCREF(o);
1613 return o;
1616 if (!PyArg_ParseTuple(args, "s:getint", &s))
1617 return NULL;
1618 if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1619 return Tkinter_Error(self);
1620 return Py_BuildValue("i", v);
1623 static PyObject *
1624 Tkapp_GetDouble(PyObject *self, PyObject *args)
1626 char *s;
1627 double v;
1629 if (PyTuple_Size(args) == 1) {
1630 PyObject *o = PyTuple_GetItem(args, 0);
1631 if (PyFloat_Check(o)) {
1632 Py_INCREF(o);
1633 return o;
1636 if (!PyArg_ParseTuple(args, "s:getdouble", &s))
1637 return NULL;
1638 if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1639 return Tkinter_Error(self);
1640 return Py_BuildValue("d", v);
1643 static PyObject *
1644 Tkapp_GetBoolean(PyObject *self, PyObject *args)
1646 char *s;
1647 int v;
1649 if (PyTuple_Size(args) == 1) {
1650 PyObject *o = PyTuple_GetItem(args, 0);
1651 if (PyInt_Check(o)) {
1652 Py_INCREF(o);
1653 return o;
1656 if (!PyArg_ParseTuple(args, "s:getboolean", &s))
1657 return NULL;
1658 if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
1659 return Tkinter_Error(self);
1660 return Py_BuildValue("i", v);
1663 static PyObject *
1664 Tkapp_ExprString(PyObject *self, PyObject *args)
1666 char *s;
1667 PyObject *res = NULL;
1668 int retval;
1670 if (!PyArg_ParseTuple(args, "s:exprstring", &s))
1671 return NULL;
1673 CHECK_TCL_APPARTMENT;
1675 ENTER_TCL
1676 retval = Tcl_ExprString(Tkapp_Interp(self), s);
1677 ENTER_OVERLAP
1678 if (retval == TCL_ERROR)
1679 res = Tkinter_Error(self);
1680 else
1681 res = Py_BuildValue("s", Tkapp_Result(self));
1682 LEAVE_OVERLAP_TCL
1683 return res;
1686 static PyObject *
1687 Tkapp_ExprLong(PyObject *self, PyObject *args)
1689 char *s;
1690 PyObject *res = NULL;
1691 int retval;
1692 long v;
1694 if (!PyArg_ParseTuple(args, "s:exprlong", &s))
1695 return NULL;
1697 CHECK_TCL_APPARTMENT;
1699 ENTER_TCL
1700 retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v);
1701 ENTER_OVERLAP
1702 if (retval == TCL_ERROR)
1703 res = Tkinter_Error(self);
1704 else
1705 res = Py_BuildValue("l", v);
1706 LEAVE_OVERLAP_TCL
1707 return res;
1710 static PyObject *
1711 Tkapp_ExprDouble(PyObject *self, PyObject *args)
1713 char *s;
1714 PyObject *res = NULL;
1715 double v;
1716 int retval;
1718 if (!PyArg_ParseTuple(args, "s:exprdouble", &s))
1719 return NULL;
1720 CHECK_TCL_APPARTMENT;
1721 PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
1722 ENTER_TCL
1723 retval = Tcl_ExprDouble(Tkapp_Interp(self), s, &v);
1724 ENTER_OVERLAP
1725 PyFPE_END_PROTECT(retval)
1726 if (retval == TCL_ERROR)
1727 res = Tkinter_Error(self);
1728 else
1729 res = Py_BuildValue("d", v);
1730 LEAVE_OVERLAP_TCL
1731 return res;
1734 static PyObject *
1735 Tkapp_ExprBoolean(PyObject *self, PyObject *args)
1737 char *s;
1738 PyObject *res = NULL;
1739 int retval;
1740 int v;
1742 if (!PyArg_ParseTuple(args, "s:exprboolean", &s))
1743 return NULL;
1744 CHECK_TCL_APPARTMENT;
1745 ENTER_TCL
1746 retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v);
1747 ENTER_OVERLAP
1748 if (retval == TCL_ERROR)
1749 res = Tkinter_Error(self);
1750 else
1751 res = Py_BuildValue("i", v);
1752 LEAVE_OVERLAP_TCL
1753 return res;
1758 static PyObject *
1759 Tkapp_SplitList(PyObject *self, PyObject *args)
1761 char *list;
1762 int argc;
1763 char **argv;
1764 PyObject *v;
1765 int i;
1767 if (PyTuple_Size(args) == 1) {
1768 v = PyTuple_GetItem(args, 0);
1769 if (PyTuple_Check(v)) {
1770 Py_INCREF(v);
1771 return v;
1774 if (!PyArg_ParseTuple(args, "et:splitlist", "utf-8", &list))
1775 return NULL;
1777 if (Tcl_SplitList(Tkapp_Interp(self), list, &argc, &argv) == TCL_ERROR)
1778 return Tkinter_Error(self);
1780 if (!(v = PyTuple_New(argc)))
1781 return NULL;
1783 for (i = 0; i < argc; i++) {
1784 PyObject *s = PyString_FromString(argv[i]);
1785 if (!s || PyTuple_SetItem(v, i, s)) {
1786 Py_DECREF(v);
1787 v = NULL;
1788 goto finally;
1792 finally:
1793 ckfree(FREECAST argv);
1794 return v;
1797 static PyObject *
1798 Tkapp_Split(PyObject *self, PyObject *args)
1800 char *list;
1802 if (PyTuple_Size(args) == 1) {
1803 PyObject* o = PyTuple_GetItem(args, 0);
1804 if (PyTuple_Check(o)) {
1805 o = SplitObj(o);
1806 return o;
1809 if (!PyArg_ParseTuple(args, "et:split", "utf-8", &list))
1810 return NULL;
1811 return Split(list);
1814 static PyObject *
1815 Tkapp_Merge(PyObject *self, PyObject *args)
1817 char *s = Merge(args);
1818 PyObject *res = NULL;
1820 if (s) {
1821 res = PyString_FromString(s);
1822 ckfree(s);
1825 return res;
1830 /** Tcl Command **/
1832 /* Client data struct */
1833 typedef struct {
1834 PyObject *self;
1835 PyObject *func;
1836 } PythonCmd_ClientData;
1838 static int
1839 PythonCmd_Error(Tcl_Interp *interp)
1841 errorInCmd = 1;
1842 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
1843 LEAVE_PYTHON
1844 return TCL_ERROR;
1847 /* This is the Tcl command that acts as a wrapper for Python
1848 * function or method.
1850 static int
1851 PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1853 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
1854 PyObject *self, *func, *arg, *res, *tmp;
1855 int i, rv;
1856 char *s;
1858 ENTER_PYTHON
1860 /* TBD: no error checking here since we know, via the
1861 * Tkapp_CreateCommand() that the client data is a two-tuple
1863 self = data->self;
1864 func = data->func;
1866 /* Create argument list (argv1, ..., argvN) */
1867 if (!(arg = PyTuple_New(argc - 1)))
1868 return PythonCmd_Error(interp);
1870 for (i = 0; i < (argc - 1); i++) {
1871 PyObject *s = PyString_FromString(argv[i + 1]);
1872 if (!s || PyTuple_SetItem(arg, i, s)) {
1873 Py_DECREF(arg);
1874 return PythonCmd_Error(interp);
1877 res = PyEval_CallObject(func, arg);
1878 Py_DECREF(arg);
1880 if (res == NULL)
1881 return PythonCmd_Error(interp);
1883 if (!(tmp = PyList_New(0))) {
1884 Py_DECREF(res);
1885 return PythonCmd_Error(interp);
1888 s = AsString(res, tmp);
1889 if (s == NULL) {
1890 rv = PythonCmd_Error(interp);
1892 else {
1893 Tcl_SetResult(Tkapp_Interp(self), s, TCL_VOLATILE);
1894 rv = TCL_OK;
1897 Py_DECREF(res);
1898 Py_DECREF(tmp);
1900 LEAVE_PYTHON
1902 return rv;
1905 static void
1906 PythonCmdDelete(ClientData clientData)
1908 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
1910 ENTER_PYTHON
1911 Py_XDECREF(data->self);
1912 Py_XDECREF(data->func);
1913 PyMem_DEL(data);
1914 LEAVE_PYTHON
1920 TCL_DECLARE_MUTEX(command_mutex)
1922 typedef struct CommandEvent{
1923 Tcl_Event ev;
1924 Tcl_Interp* interp;
1925 char *name;
1926 int create;
1927 int *status;
1928 ClientData *data;
1929 Tcl_Condition done;
1930 } CommandEvent;
1932 static int
1933 Tkapp_CommandProc(CommandEvent *ev, int flags)
1935 if (ev->create)
1936 *ev->status = Tcl_CreateCommand(
1937 ev->interp, ev->name, PythonCmd,
1938 ev->data, PythonCmdDelete) == NULL;
1939 else
1940 *ev->status = Tcl_DeleteCommand(ev->interp, ev->name);
1941 Tcl_MutexLock(&command_mutex);
1942 Tcl_ConditionNotify(&ev->done);
1943 Tcl_MutexUnlock(&command_mutex);
1944 return 1;
1947 static PyObject *
1948 Tkapp_CreateCommand(PyObject *_self, PyObject *args)
1950 TkappObject *self = (TkappObject*)_self;
1951 PythonCmd_ClientData *data;
1952 char *cmdName;
1953 PyObject *func;
1954 int err;
1956 if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func))
1957 return NULL;
1958 if (!PyCallable_Check(func)) {
1959 PyErr_SetString(PyExc_TypeError, "command not callable");
1960 return NULL;
1963 if (self->threaded && self->thread_id != Tcl_GetCurrentThread() &&
1964 !WaitForMainloop(self))
1965 return NULL;
1967 data = PyMem_NEW(PythonCmd_ClientData, 1);
1968 if (!data)
1969 return NULL;
1970 Py_XINCREF(self);
1971 Py_XINCREF(func);
1972 data->self = _self;
1973 data->func = func;
1975 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
1976 CommandEvent *ev = (CommandEvent*)ckalloc(sizeof(CommandEvent));
1977 ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc;
1978 ev->interp = self->interp;
1979 ev->create = 1;
1980 ev->name = cmdName;
1981 ev->data = (ClientData)data;
1982 ev->status = &err;
1983 ev->done = NULL;
1984 Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->done, &command_mutex);
1986 else {
1987 ENTER_TCL
1988 err = Tcl_CreateCommand(
1989 Tkapp_Interp(self), cmdName, PythonCmd,
1990 (ClientData)data, PythonCmdDelete) == NULL;
1991 LEAVE_TCL
1993 if (err) {
1994 PyErr_SetString(Tkinter_TclError, "can't create Tcl command");
1995 PyMem_DEL(data);
1996 return NULL;
1999 Py_INCREF(Py_None);
2000 return Py_None;
2005 static PyObject *
2006 Tkapp_DeleteCommand(PyObject *_self, PyObject *args)
2008 TkappObject *self = (TkappObject*)_self;
2009 char *cmdName;
2010 int err;
2012 if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName))
2013 return NULL;
2014 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
2015 CommandEvent *ev;
2016 ev = (CommandEvent*)ckalloc(sizeof(CommandEvent));
2017 ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc;
2018 ev->interp = self->interp;
2019 ev->create = 0;
2020 ev->name = cmdName;
2021 ev->status = &err;
2022 ev->done = NULL;
2023 Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->done,
2024 &command_mutex);
2026 else {
2027 ENTER_TCL
2028 err = Tcl_DeleteCommand(self->interp, cmdName);
2029 LEAVE_TCL
2031 if (err == -1) {
2032 PyErr_SetString(Tkinter_TclError, "can't delete Tcl command");
2033 return NULL;
2035 Py_INCREF(Py_None);
2036 return Py_None;
2041 #ifdef HAVE_CREATEFILEHANDLER
2042 /** File Handler **/
2044 typedef struct _fhcdata {
2045 PyObject *func;
2046 PyObject *file;
2047 int id;
2048 struct _fhcdata *next;
2049 } FileHandler_ClientData;
2051 static FileHandler_ClientData *HeadFHCD;
2053 static FileHandler_ClientData *
2054 NewFHCD(PyObject *func, PyObject *file, int id)
2056 FileHandler_ClientData *p;
2057 p = PyMem_NEW(FileHandler_ClientData, 1);
2058 if (p != NULL) {
2059 Py_XINCREF(func);
2060 Py_XINCREF(file);
2061 p->func = func;
2062 p->file = file;
2063 p->id = id;
2064 p->next = HeadFHCD;
2065 HeadFHCD = p;
2067 return p;
2070 static void
2071 DeleteFHCD(int id)
2073 FileHandler_ClientData *p, **pp;
2075 pp = &HeadFHCD;
2076 while ((p = *pp) != NULL) {
2077 if (p->id == id) {
2078 *pp = p->next;
2079 Py_XDECREF(p->func);
2080 Py_XDECREF(p->file);
2081 PyMem_DEL(p);
2083 else
2084 pp = &p->next;
2088 static void
2089 FileHandler(ClientData clientData, int mask)
2091 FileHandler_ClientData *data = (FileHandler_ClientData *)clientData;
2092 PyObject *func, *file, *arg, *res;
2094 ENTER_PYTHON
2095 func = data->func;
2096 file = data->file;
2098 arg = Py_BuildValue("(Oi)", file, (long) mask);
2099 res = PyEval_CallObject(func, arg);
2100 Py_DECREF(arg);
2102 if (res == NULL) {
2103 errorInCmd = 1;
2104 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
2106 Py_XDECREF(res);
2107 LEAVE_PYTHON
2110 static PyObject *
2111 Tkapp_CreateFileHandler(PyObject *self, PyObject *args)
2112 /* args is (file, mask, func) */
2114 FileHandler_ClientData *data;
2115 PyObject *file, *func;
2116 int mask, tfile;
2118 if (!PyArg_ParseTuple(args, "OiO:createfilehandler",
2119 &file, &mask, &func))
2120 return NULL;
2121 CHECK_TCL_APPARTMENT;
2122 tfile = PyObject_AsFileDescriptor(file);
2123 if (tfile < 0)
2124 return NULL;
2125 if (!PyCallable_Check(func)) {
2126 PyErr_SetString(PyExc_TypeError, "bad argument list");
2127 return NULL;
2130 data = NewFHCD(func, file, tfile);
2131 if (data == NULL)
2132 return NULL;
2134 /* Ought to check for null Tcl_File object... */
2135 ENTER_TCL
2136 Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data);
2137 LEAVE_TCL
2138 Py_INCREF(Py_None);
2139 return Py_None;
2142 static PyObject *
2143 Tkapp_DeleteFileHandler(PyObject *self, PyObject *args)
2145 PyObject *file;
2146 int tfile;
2148 if (!PyArg_ParseTuple(args, "O:deletefilehandler", &file))
2149 return NULL;
2150 CHECK_TCL_APPARTMENT;
2151 tfile = PyObject_AsFileDescriptor(file);
2152 if (tfile < 0)
2153 return NULL;
2155 DeleteFHCD(tfile);
2157 /* Ought to check for null Tcl_File object... */
2158 ENTER_TCL
2159 Tcl_DeleteFileHandler(tfile);
2160 LEAVE_TCL
2161 Py_INCREF(Py_None);
2162 return Py_None;
2164 #endif /* HAVE_CREATEFILEHANDLER */
2167 /**** Tktt Object (timer token) ****/
2169 static PyTypeObject Tktt_Type;
2171 typedef struct {
2172 PyObject_HEAD
2173 Tcl_TimerToken token;
2174 PyObject *func;
2175 } TkttObject;
2177 static PyObject *
2178 Tktt_DeleteTimerHandler(PyObject *self, PyObject *args)
2180 TkttObject *v = (TkttObject *)self;
2181 PyObject *func = v->func;
2183 if (!PyArg_ParseTuple(args, ":deletetimerhandler"))
2184 return NULL;
2185 if (v->token != NULL) {
2186 Tcl_DeleteTimerHandler(v->token);
2187 v->token = NULL;
2189 if (func != NULL) {
2190 v->func = NULL;
2191 Py_DECREF(func);
2192 Py_DECREF(v); /* See Tktt_New() */
2194 Py_INCREF(Py_None);
2195 return Py_None;
2198 static PyMethodDef Tktt_methods[] =
2200 {"deletetimerhandler", Tktt_DeleteTimerHandler, METH_VARARGS},
2201 {NULL, NULL}
2204 static TkttObject *
2205 Tktt_New(PyObject *func)
2207 TkttObject *v;
2209 v = PyObject_New(TkttObject, &Tktt_Type);
2210 if (v == NULL)
2211 return NULL;
2213 Py_INCREF(func);
2214 v->token = NULL;
2215 v->func = func;
2217 /* Extra reference, deleted when called or when handler is deleted */
2218 Py_INCREF(v);
2219 return v;
2222 static void
2223 Tktt_Dealloc(PyObject *self)
2225 TkttObject *v = (TkttObject *)self;
2226 PyObject *func = v->func;
2228 Py_XDECREF(func);
2230 PyObject_Del(self);
2233 static PyObject *
2234 Tktt_Repr(PyObject *self)
2236 TkttObject *v = (TkttObject *)self;
2237 char buf[100];
2239 PyOS_snprintf(buf, sizeof(buf), "<tktimertoken at %p%s>", v,
2240 v->func == NULL ? ", handler deleted" : "");
2241 return PyString_FromString(buf);
2244 static PyObject *
2245 Tktt_GetAttr(PyObject *self, char *name)
2247 return Py_FindMethod(Tktt_methods, self, name);
2250 static PyTypeObject Tktt_Type =
2252 PyObject_HEAD_INIT(NULL)
2253 0, /*ob_size */
2254 "tktimertoken", /*tp_name */
2255 sizeof(TkttObject), /*tp_basicsize */
2256 0, /*tp_itemsize */
2257 Tktt_Dealloc, /*tp_dealloc */
2258 0, /*tp_print */
2259 Tktt_GetAttr, /*tp_getattr */
2260 0, /*tp_setattr */
2261 0, /*tp_compare */
2262 Tktt_Repr, /*tp_repr */
2263 0, /*tp_as_number */
2264 0, /*tp_as_sequence */
2265 0, /*tp_as_mapping */
2266 0, /*tp_hash */
2271 /** Timer Handler **/
2273 static void
2274 TimerHandler(ClientData clientData)
2276 TkttObject *v = (TkttObject *)clientData;
2277 PyObject *func = v->func;
2278 PyObject *res;
2280 if (func == NULL)
2281 return;
2283 v->func = NULL;
2285 ENTER_PYTHON
2287 res = PyEval_CallObject(func, NULL);
2288 Py_DECREF(func);
2289 Py_DECREF(v); /* See Tktt_New() */
2291 if (res == NULL) {
2292 errorInCmd = 1;
2293 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd);
2295 else
2296 Py_DECREF(res);
2298 LEAVE_PYTHON
2301 static PyObject *
2302 Tkapp_CreateTimerHandler(PyObject *self, PyObject *args)
2304 int milliseconds;
2305 PyObject *func;
2306 TkttObject *v;
2308 if (!PyArg_ParseTuple(args, "iO:createtimerhandler",
2309 &milliseconds, &func))
2310 return NULL;
2311 if (!PyCallable_Check(func)) {
2312 PyErr_SetString(PyExc_TypeError, "bad argument list");
2313 return NULL;
2315 v = Tktt_New(func);
2316 v->token = Tcl_CreateTimerHandler(milliseconds, TimerHandler,
2317 (ClientData)v);
2319 return (PyObject *) v;
2323 /** Event Loop **/
2325 static PyObject *
2326 Tkapp_MainLoop(PyObject *_self, PyObject *args)
2328 int threshold = 0;
2329 TkappObject *self = (TkappObject*)_self;
2330 #ifdef WITH_THREAD
2331 PyThreadState *tstate = PyThreadState_Get();
2332 #endif
2334 if (!PyArg_ParseTuple(args, "|i:mainloop", &threshold))
2335 return NULL;
2337 CHECK_TCL_APPARTMENT;
2339 quitMainLoop = 0;
2340 self->dispatching = 1;
2341 while (Tk_GetNumMainWindows() > threshold &&
2342 !quitMainLoop &&
2343 !errorInCmd)
2345 int result;
2347 #ifdef WITH_THREAD
2348 if (self->threaded) {
2349 /* Allow other Python threads to run. */
2350 ENTER_TCL
2351 result = Tcl_DoOneEvent(0);
2352 LEAVE_TCL
2354 else {
2355 Py_BEGIN_ALLOW_THREADS
2356 if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1);
2357 tcl_tstate = tstate;
2358 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
2359 tcl_tstate = NULL;
2360 if(tcl_lock)PyThread_release_lock(tcl_lock);
2361 if (result == 0)
2362 Sleep(20);
2363 Py_END_ALLOW_THREADS
2365 #else
2366 result = Tcl_DoOneEvent(0);
2367 #endif
2369 if (PyErr_CheckSignals() != 0) {
2370 self->dispatching = 0;
2371 return NULL;
2373 if (result < 0)
2374 break;
2376 self->dispatching = 0;
2377 quitMainLoop = 0;
2379 if (errorInCmd) {
2380 errorInCmd = 0;
2381 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
2382 excInCmd = valInCmd = trbInCmd = NULL;
2383 return NULL;
2385 Py_INCREF(Py_None);
2386 return Py_None;
2389 static PyObject *
2390 Tkapp_DoOneEvent(PyObject *self, PyObject *args)
2392 int flags = 0;
2393 int rv;
2395 if (!PyArg_ParseTuple(args, "|i:dooneevent", &flags))
2396 return NULL;
2397 CHECK_TCL_APPARTMENT;
2399 ENTER_TCL
2400 rv = Tcl_DoOneEvent(flags);
2401 LEAVE_TCL
2402 return Py_BuildValue("i", rv);
2405 static PyObject *
2406 Tkapp_Quit(PyObject *self, PyObject *args)
2409 if (!PyArg_ParseTuple(args, ":quit"))
2410 return NULL;
2412 quitMainLoop = 1;
2413 Py_INCREF(Py_None);
2414 return Py_None;
2417 static PyObject *
2418 Tkapp_InterpAddr(PyObject *self, PyObject *args)
2421 if (!PyArg_ParseTuple(args, ":interpaddr"))
2422 return NULL;
2424 return PyInt_FromLong((long)Tkapp_Interp(self));
2428 static PyObject *
2429 Tkapp_WantObjects(PyObject *self, PyObject *args)
2432 int wantobjects;
2433 if (!PyArg_ParseTuple(args, "i:wantobjects", &wantobjects))
2434 return NULL;
2435 ((TkappObject*)self)->wantobjects = wantobjects;
2437 Py_INCREF(Py_None);
2438 return Py_None;
2441 static PyObject *
2442 Tkapp_WillDispatch(PyObject *self, PyObject *args)
2445 ((TkappObject*)self)->dispatching = 1;
2447 Py_INCREF(Py_None);
2448 return Py_None;
2452 /**** Tkapp Method List ****/
2454 static PyMethodDef Tkapp_methods[] =
2456 {"willdispatch", Tkapp_WillDispatch, METH_NOARGS},
2457 {"wantobjects", Tkapp_WantObjects, METH_VARARGS},
2458 {"call", Tkapp_Call, METH_OLDARGS},
2459 {"globalcall", Tkapp_GlobalCall, METH_OLDARGS},
2460 {"eval", Tkapp_Eval, METH_VARARGS},
2461 {"globaleval", Tkapp_GlobalEval, METH_VARARGS},
2462 {"evalfile", Tkapp_EvalFile, METH_VARARGS},
2463 {"record", Tkapp_Record, METH_VARARGS},
2464 {"adderrorinfo", Tkapp_AddErrorInfo, METH_VARARGS},
2465 {"setvar", Tkapp_SetVar, METH_VARARGS},
2466 {"globalsetvar", Tkapp_GlobalSetVar, METH_VARARGS},
2467 {"getvar", Tkapp_GetVar, METH_VARARGS},
2468 {"globalgetvar", Tkapp_GlobalGetVar, METH_VARARGS},
2469 {"unsetvar", Tkapp_UnsetVar, METH_VARARGS},
2470 {"globalunsetvar", Tkapp_GlobalUnsetVar, METH_VARARGS},
2471 {"getint", Tkapp_GetInt, METH_VARARGS},
2472 {"getdouble", Tkapp_GetDouble, METH_VARARGS},
2473 {"getboolean", Tkapp_GetBoolean, METH_VARARGS},
2474 {"exprstring", Tkapp_ExprString, METH_VARARGS},
2475 {"exprlong", Tkapp_ExprLong, METH_VARARGS},
2476 {"exprdouble", Tkapp_ExprDouble, METH_VARARGS},
2477 {"exprboolean", Tkapp_ExprBoolean, METH_VARARGS},
2478 {"splitlist", Tkapp_SplitList, METH_VARARGS},
2479 {"split", Tkapp_Split, METH_VARARGS},
2480 {"merge", Tkapp_Merge, METH_OLDARGS},
2481 {"createcommand", Tkapp_CreateCommand, METH_VARARGS},
2482 {"deletecommand", Tkapp_DeleteCommand, METH_VARARGS},
2483 #ifdef HAVE_CREATEFILEHANDLER
2484 {"createfilehandler", Tkapp_CreateFileHandler, METH_VARARGS},
2485 {"deletefilehandler", Tkapp_DeleteFileHandler, METH_VARARGS},
2486 #endif
2487 {"createtimerhandler", Tkapp_CreateTimerHandler, METH_VARARGS},
2488 {"mainloop", Tkapp_MainLoop, METH_VARARGS},
2489 {"dooneevent", Tkapp_DoOneEvent, METH_VARARGS},
2490 {"quit", Tkapp_Quit, METH_VARARGS},
2491 {"interpaddr", Tkapp_InterpAddr, METH_VARARGS},
2492 {NULL, NULL}
2497 /**** Tkapp Type Methods ****/
2499 static void
2500 Tkapp_Dealloc(PyObject *self)
2502 /*CHECK_TCL_APPARTMENT;*/
2503 ENTER_TCL
2504 Tcl_DeleteInterp(Tkapp_Interp(self));
2505 LEAVE_TCL
2506 PyObject_Del(self);
2507 DisableEventHook();
2510 static PyObject *
2511 Tkapp_GetAttr(PyObject *self, char *name)
2513 return Py_FindMethod(Tkapp_methods, self, name);
2516 static PyTypeObject Tkapp_Type =
2518 PyObject_HEAD_INIT(NULL)
2519 0, /*ob_size */
2520 "tkapp", /*tp_name */
2521 sizeof(TkappObject), /*tp_basicsize */
2522 0, /*tp_itemsize */
2523 Tkapp_Dealloc, /*tp_dealloc */
2524 0, /*tp_print */
2525 Tkapp_GetAttr, /*tp_getattr */
2526 0, /*tp_setattr */
2527 0, /*tp_compare */
2528 0, /*tp_repr */
2529 0, /*tp_as_number */
2530 0, /*tp_as_sequence */
2531 0, /*tp_as_mapping */
2532 0, /*tp_hash */
2537 /**** Tkinter Module ****/
2539 typedef struct {
2540 PyObject* tuple;
2541 int size; /* current size */
2542 int maxsize; /* allocated size */
2543 } FlattenContext;
2545 static int
2546 _bump(FlattenContext* context, int size)
2548 /* expand tuple to hold (at least) size new items.
2549 return true if successful, false if an exception was raised */
2551 int maxsize = context->maxsize * 2;
2553 if (maxsize < context->size + size)
2554 maxsize = context->size + size;
2556 context->maxsize = maxsize;
2558 return _PyTuple_Resize(&context->tuple, maxsize) >= 0;
2561 static int
2562 _flatten1(FlattenContext* context, PyObject* item, int depth)
2564 /* add tuple or list to argument tuple (recursively) */
2566 int i, size;
2568 if (depth > 1000) {
2569 PyErr_SetString(PyExc_ValueError,
2570 "nesting too deep in _flatten");
2571 return 0;
2572 } else if (PyList_Check(item)) {
2573 size = PyList_GET_SIZE(item);
2574 /* preallocate (assume no nesting) */
2575 if (context->size + size > context->maxsize &&
2576 !_bump(context, size))
2577 return 0;
2578 /* copy items to output tuple */
2579 for (i = 0; i < size; i++) {
2580 PyObject *o = PyList_GET_ITEM(item, i);
2581 if (PyList_Check(o) || PyTuple_Check(o)) {
2582 if (!_flatten1(context, o, depth + 1))
2583 return 0;
2584 } else if (o != Py_None) {
2585 if (context->size + 1 > context->maxsize &&
2586 !_bump(context, 1))
2587 return 0;
2588 Py_INCREF(o);
2589 PyTuple_SET_ITEM(context->tuple,
2590 context->size++, o);
2593 } else if (PyTuple_Check(item)) {
2594 /* same, for tuples */
2595 size = PyTuple_GET_SIZE(item);
2596 if (context->size + size > context->maxsize &&
2597 !_bump(context, size))
2598 return 0;
2599 for (i = 0; i < size; i++) {
2600 PyObject *o = PyTuple_GET_ITEM(item, i);
2601 if (PyList_Check(o) || PyTuple_Check(o)) {
2602 if (!_flatten1(context, o, depth + 1))
2603 return 0;
2604 } else if (o != Py_None) {
2605 if (context->size + 1 > context->maxsize &&
2606 !_bump(context, 1))
2607 return 0;
2608 Py_INCREF(o);
2609 PyTuple_SET_ITEM(context->tuple,
2610 context->size++, o);
2613 } else {
2614 PyErr_SetString(PyExc_TypeError, "argument must be sequence");
2615 return 0;
2617 return 1;
2620 static PyObject *
2621 Tkinter_Flatten(PyObject* self, PyObject* args)
2623 FlattenContext context;
2624 PyObject* item;
2626 if (!PyArg_ParseTuple(args, "O:_flatten", &item))
2627 return NULL;
2629 context.maxsize = PySequence_Size(item);
2630 if (context.maxsize <= 0)
2631 return PyTuple_New(0);
2633 context.tuple = PyTuple_New(context.maxsize);
2634 if (!context.tuple)
2635 return NULL;
2637 context.size = 0;
2639 if (!_flatten1(&context, item,0))
2640 return NULL;
2642 if (_PyTuple_Resize(&context.tuple, context.size))
2643 return NULL;
2645 return context.tuple;
2648 static PyObject *
2649 Tkinter_Create(PyObject *self, PyObject *args)
2651 char *screenName = NULL;
2652 char *baseName = NULL;
2653 char *className = NULL;
2654 int interactive = 0;
2655 int wantobjects = 0;
2657 baseName = strrchr(Py_GetProgramName(), '/');
2658 if (baseName != NULL)
2659 baseName++;
2660 else
2661 baseName = Py_GetProgramName();
2662 className = "Tk";
2664 if (!PyArg_ParseTuple(args, "|zssii:create",
2665 &screenName, &baseName, &className,
2666 &interactive, &wantobjects))
2667 return NULL;
2669 return (PyObject *) Tkapp_New(screenName, baseName, className,
2670 interactive, wantobjects);
2673 static PyMethodDef moduleMethods[] =
2675 {"_flatten", Tkinter_Flatten, METH_VARARGS},
2676 {"create", Tkinter_Create, METH_VARARGS},
2677 #ifdef HAVE_CREATEFILEHANDLER
2678 {"createfilehandler", Tkapp_CreateFileHandler, METH_VARARGS},
2679 {"deletefilehandler", Tkapp_DeleteFileHandler, METH_VARARGS},
2680 #endif
2681 {"createtimerhandler", Tkapp_CreateTimerHandler, METH_VARARGS},
2682 {"mainloop", Tkapp_MainLoop, METH_VARARGS},
2683 {"dooneevent", Tkapp_DoOneEvent, METH_VARARGS},
2684 {"quit", Tkapp_Quit, METH_VARARGS},
2685 {NULL, NULL}
2688 #ifdef WAIT_FOR_STDIN
2690 static int stdin_ready = 0;
2692 #ifndef MS_WINDOWS
2693 static void
2694 MyFileProc(void *clientData, int mask)
2696 stdin_ready = 1;
2698 #endif
2700 static PyThreadState *event_tstate = NULL;
2702 static int
2703 EventHook(void)
2705 #ifndef MS_WINDOWS
2706 int tfile;
2707 #endif
2708 #ifdef WITH_THREAD
2709 PyEval_RestoreThread(event_tstate);
2710 #endif
2711 stdin_ready = 0;
2712 errorInCmd = 0;
2713 #ifndef MS_WINDOWS
2714 tfile = fileno(stdin);
2715 Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL);
2716 #endif
2717 while (!errorInCmd && !stdin_ready) {
2718 int result;
2719 #ifdef MS_WINDOWS
2720 if (_kbhit()) {
2721 stdin_ready = 1;
2722 break;
2724 #endif
2725 #if defined(WITH_THREAD) || defined(MS_WINDOWS)
2726 Py_BEGIN_ALLOW_THREADS
2727 if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1);
2728 tcl_tstate = event_tstate;
2730 result = Tcl_DoOneEvent(TCL_DONT_WAIT);
2732 tcl_tstate = NULL;
2733 if(tcl_lock)PyThread_release_lock(tcl_lock);
2734 if (result == 0)
2735 Sleep(20);
2736 Py_END_ALLOW_THREADS
2737 #else
2738 result = Tcl_DoOneEvent(0);
2739 #endif
2741 if (result < 0)
2742 break;
2744 #ifndef MS_WINDOWS
2745 Tcl_DeleteFileHandler(tfile);
2746 #endif
2747 if (errorInCmd) {
2748 errorInCmd = 0;
2749 PyErr_Restore(excInCmd, valInCmd, trbInCmd);
2750 excInCmd = valInCmd = trbInCmd = NULL;
2751 PyErr_Print();
2753 #ifdef WITH_THREAD
2754 PyEval_SaveThread();
2755 #endif
2756 return 0;
2759 #endif
2761 static void
2762 EnableEventHook(void)
2764 #ifdef WAIT_FOR_STDIN
2765 if (PyOS_InputHook == NULL) {
2766 #ifdef WITH_THREAD
2767 event_tstate = PyThreadState_Get();
2768 #endif
2769 PyOS_InputHook = EventHook;
2771 #endif
2774 static void
2775 DisableEventHook(void)
2777 #ifdef WAIT_FOR_STDIN
2778 if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) {
2779 PyOS_InputHook = NULL;
2781 #endif
2785 /* all errors will be checked in one fell swoop in init_tkinter() */
2786 static void
2787 ins_long(PyObject *d, char *name, long val)
2789 PyObject *v = PyInt_FromLong(val);
2790 if (v) {
2791 PyDict_SetItemString(d, name, v);
2792 Py_DECREF(v);
2795 static void
2796 ins_string(PyObject *d, char *name, char *val)
2798 PyObject *v = PyString_FromString(val);
2799 if (v) {
2800 PyDict_SetItemString(d, name, v);
2801 Py_DECREF(v);
2806 PyMODINIT_FUNC
2807 init_tkinter(void)
2809 PyObject *m, *d;
2811 Tkapp_Type.ob_type = &PyType_Type;
2813 #ifdef WITH_THREAD
2814 tcl_lock = PyThread_allocate_lock();
2815 #endif
2817 m = Py_InitModule("_tkinter", moduleMethods);
2819 d = PyModule_GetDict(m);
2820 Tkinter_TclError = PyErr_NewException("_tkinter.TclError", NULL, NULL);
2821 PyDict_SetItemString(d, "TclError", Tkinter_TclError);
2823 ins_long(d, "READABLE", TCL_READABLE);
2824 ins_long(d, "WRITABLE", TCL_WRITABLE);
2825 ins_long(d, "EXCEPTION", TCL_EXCEPTION);
2826 ins_long(d, "WINDOW_EVENTS", TCL_WINDOW_EVENTS);
2827 ins_long(d, "FILE_EVENTS", TCL_FILE_EVENTS);
2828 ins_long(d, "TIMER_EVENTS", TCL_TIMER_EVENTS);
2829 ins_long(d, "IDLE_EVENTS", TCL_IDLE_EVENTS);
2830 ins_long(d, "ALL_EVENTS", TCL_ALL_EVENTS);
2831 ins_long(d, "DONT_WAIT", TCL_DONT_WAIT);
2832 ins_string(d, "TK_VERSION", TK_VERSION);
2833 ins_string(d, "TCL_VERSION", TCL_VERSION);
2835 PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type);
2837 Tktt_Type.ob_type = &PyType_Type;
2838 PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type);
2840 PyTclObject_Type.ob_type = &PyType_Type;
2841 PyDict_SetItemString(d, "Tcl_Obj", (PyObject *)&PyTclObject_Type);
2843 #ifdef TK_AQUA
2844 /* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems
2845 * start waking up. Note that Tcl_FindExecutable will do this, this
2846 * code must be above it! The original warning from
2847 * tkMacOSXAppInit.c is copied below.
2849 * NB - You have to swap in the Tk Notifier BEFORE you start up the
2850 * Tcl interpreter for now. It probably should work to do this
2851 * in the other order, but for now it doesn't seem to.
2854 Tk_MacOSXSetupTkNotifier();
2855 #endif
2858 /* This helps the dynamic loader; in Unicode aware Tcl versions
2859 it also helps Tcl find its encodings. */
2860 Tcl_FindExecutable(Py_GetProgramName());
2862 if (PyErr_Occurred())
2863 return;
2865 #if 0
2866 /* This was not a good idea; through <Destroy> bindings,
2867 Tcl_Finalize() may invoke Python code but at that point the
2868 interpreter and thread state have already been destroyed! */
2869 Py_AtExit(Tcl_Finalize);
2870 #endif
2872 #ifdef macintosh
2874 ** Part of this code is stolen from MacintoshInit in tkMacAppInit.
2875 ** Most of the initializations in that routine (toolbox init calls and
2876 ** such) have already been done for us, so we only need these.
2878 tcl_macQdPtr = &qd;
2880 Tcl_MacSetEventProc(PyMacConvertEvent);
2881 #if GENERATINGCFM
2882 mac_addlibresources();
2883 #endif /* GENERATINGCFM */
2884 #endif /* macintosh */
2889 #ifdef macintosh
2892 ** Anyone who embeds Tcl/Tk on the Mac must define panic().
2895 void
2896 panic(char * format, ...)
2898 va_list varg;
2900 va_start(varg, format);
2902 vfprintf(stderr, format, varg);
2903 (void) fflush(stderr);
2905 va_end(varg);
2907 Py_FatalError("Tcl/Tk panic");
2911 ** Pass events to SIOUX before passing them to Tk.
2914 static int
2915 PyMacConvertEvent(EventRecord *eventPtr)
2917 WindowPtr frontwin;
2919 ** Sioux eats too many events, so we don't pass it everything. We
2920 ** always pass update events to Sioux, and we only pass other events if
2921 ** the Sioux window is frontmost. This means that Tk menus don't work
2922 ** in that case, but at least we can scroll the sioux window.
2923 ** Note that the SIOUXIsAppWindow() routine we use here is not really
2924 ** part of the external interface of Sioux...
2926 frontwin = FrontWindow();
2927 if ( eventPtr->what == updateEvt || SIOUXIsAppWindow(frontwin) ) {
2928 if (SIOUXHandleOneEvent(eventPtr))
2929 return 0; /* Nothing happened to the Tcl event queue */
2931 return TkMacConvertEvent(eventPtr);
2934 #if GENERATINGCFM
2937 ** Additional Mac specific code for dealing with shared libraries.
2940 #include <Resources.h>
2941 #include <CodeFragments.h>
2943 static int loaded_from_shlib = 0;
2944 static FSSpec library_fss;
2947 ** If this module is dynamically loaded the following routine should
2948 ** be the init routine. It takes care of adding the shared library to
2949 ** the resource-file chain, so that the tk routines can find their
2950 ** resources.
2952 OSErr pascal
2953 init_tkinter_shlib(CFragInitBlockPtr data)
2955 __initialize();
2956 if ( data == nil ) return noErr;
2957 if ( data->fragLocator.where == kDataForkCFragLocator ) {
2958 library_fss = *data->fragLocator.u.onDisk.fileSpec;
2959 loaded_from_shlib = 1;
2960 } else if ( data->fragLocator.where == kResourceCFragLocator ) {
2961 library_fss = *data->fragLocator.u.inSegs.fileSpec;
2962 loaded_from_shlib = 1;
2964 return noErr;
2968 ** Insert the library resources into the search path. Put them after
2969 ** the resources from the application. Again, we ignore errors.
2971 static
2972 mac_addlibresources(void)
2974 if ( !loaded_from_shlib )
2975 return;
2976 (void)FSpOpenResFile(&library_fss, fsRdPerm);
2979 #endif /* GENERATINGCFM */
2980 #endif /* macintosh */