|
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.2 and later are supported. Older versions are not |
|
13 supported. (Use Python 2.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 - Register a new Tcl type, "Python callable", which can be called more |
|
20 efficiently and passed to Tcl_EvalObj() directly (if this is possible). |
|
21 |
|
22 */ |
|
23 |
|
24 |
|
25 #include "Python.h" |
|
26 #include <ctype.h> |
|
27 |
|
28 #ifdef WITH_THREAD |
|
29 #include "pythread.h" |
|
30 #endif |
|
31 |
|
32 #ifdef MS_WINDOWS |
|
33 #include <windows.h> |
|
34 #endif |
|
35 |
|
36 /* Allow using this code in Python 2.[12] */ |
|
37 #ifndef PyDoc_STRVAR |
|
38 #define PyDoc_STRVAR(name,str) static char name[] = str |
|
39 #endif |
|
40 |
|
41 #ifndef PyMODINIT_FUNC |
|
42 #define PyMODINIT_FUNC void |
|
43 #endif |
|
44 |
|
45 #ifndef PyBool_Check |
|
46 #define PyBool_Check(o) 0 |
|
47 #define PyBool_FromLong PyInt_FromLong |
|
48 #endif |
|
49 |
|
50 /* Starting with Tcl 8.4, many APIs offer const-correctness. Unfortunately, |
|
51 making _tkinter correct for this API means to break earlier |
|
52 versions. USE_COMPAT_CONST allows to make _tkinter work with both 8.4 and |
|
53 earlier versions. Once Tcl releases before 8.4 don't need to be supported |
|
54 anymore, this should go. */ |
|
55 #define USE_COMPAT_CONST |
|
56 |
|
57 /* If Tcl is compiled for threads, we must also define TCL_THREAD. We define |
|
58 it always; if Tcl is not threaded, the thread functions in |
|
59 Tcl are empty. */ |
|
60 #define TCL_THREADS |
|
61 |
|
62 #ifdef TK_FRAMEWORK |
|
63 #include <Tcl/tcl.h> |
|
64 #include <Tk/tk.h> |
|
65 #else |
|
66 #include <tcl.h> |
|
67 #include <tk.h> |
|
68 #endif |
|
69 |
|
70 /* For Tcl 8.2 and 8.3, CONST* is not defined (except on Cygwin). */ |
|
71 #ifndef CONST84_RETURN |
|
72 #define CONST84_RETURN |
|
73 #undef CONST |
|
74 #define CONST |
|
75 #endif |
|
76 |
|
77 #define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION) |
|
78 |
|
79 #if TKMAJORMINOR < 8002 |
|
80 #error "Tk older than 8.2 not supported" |
|
81 #endif |
|
82 |
|
83 /* Unicode conversion assumes that Tcl_UniChar is two bytes. |
|
84 We cannot test this directly, so we test UTF-8 size instead, |
|
85 expecting that TCL_UTF_MAX is changed if Tcl ever supports |
|
86 either UTF-16 or UCS-4. |
|
87 Redhat 8 sets TCL_UTF_MAX to 6, and uses wchar_t for |
|
88 Tcl_Unichar. This is also ok as long as Python uses UCS-4, |
|
89 as well. |
|
90 */ |
|
91 #if TCL_UTF_MAX != 3 && !(defined(Py_UNICODE_WIDE) && TCL_UTF_MAX==6) |
|
92 #error "unsupported Tcl configuration" |
|
93 #endif |
|
94 |
|
95 #if !(defined(MS_WINDOWS) || defined(__CYGWIN__)) |
|
96 #define HAVE_CREATEFILEHANDLER |
|
97 #endif |
|
98 |
|
99 #ifdef HAVE_CREATEFILEHANDLER |
|
100 |
|
101 /* This bit is to ensure that TCL_UNIX_FD is defined and doesn't interfere |
|
102 with the proper calculation of FHANDLETYPE == TCL_UNIX_FD below. */ |
|
103 #ifndef TCL_UNIX_FD |
|
104 # ifdef TCL_WIN_SOCKET |
|
105 # define TCL_UNIX_FD (! TCL_WIN_SOCKET) |
|
106 # else |
|
107 # define TCL_UNIX_FD 1 |
|
108 # endif |
|
109 #endif |
|
110 |
|
111 /* Tcl_CreateFileHandler() changed several times; these macros deal with the |
|
112 messiness. In Tcl 8.0 and later, it is not available on Windows (and on |
|
113 Unix, only because Jack added it back); when available on Windows, it only |
|
114 applies to sockets. */ |
|
115 |
|
116 #ifdef MS_WINDOWS |
|
117 #define FHANDLETYPE TCL_WIN_SOCKET |
|
118 #else |
|
119 #define FHANDLETYPE TCL_UNIX_FD |
|
120 #endif |
|
121 |
|
122 /* If Tcl can wait for a Unix file descriptor, define the EventHook() routine |
|
123 which uses this to handle Tcl events while the user is typing commands. */ |
|
124 |
|
125 #if FHANDLETYPE == TCL_UNIX_FD |
|
126 #define WAIT_FOR_STDIN |
|
127 #endif |
|
128 |
|
129 #endif /* HAVE_CREATEFILEHANDLER */ |
|
130 |
|
131 #ifdef MS_WINDOWS |
|
132 #include <conio.h> |
|
133 #define WAIT_FOR_STDIN |
|
134 #endif |
|
135 |
|
136 #ifdef WITH_THREAD |
|
137 |
|
138 /* The threading situation is complicated. Tcl is not thread-safe, except |
|
139 when configured with --enable-threads. |
|
140 So we need to use a lock around all uses of Tcl. Previously, the Python |
|
141 interpreter lock was used for this. However, this causes problems when |
|
142 other Python threads need to run while Tcl is blocked waiting for events. |
|
143 |
|
144 To solve this problem, a separate lock for Tcl is introduced. Holding it |
|
145 is incompatible with holding Python's interpreter lock. The following four |
|
146 macros manipulate both locks together. |
|
147 |
|
148 ENTER_TCL and LEAVE_TCL are brackets, just like Py_BEGIN_ALLOW_THREADS and |
|
149 Py_END_ALLOW_THREADS. They should be used whenever a call into Tcl is made |
|
150 that could call an event handler, or otherwise affect the state of a Tcl |
|
151 interpreter. These assume that the surrounding code has the Python |
|
152 interpreter lock; inside the brackets, the Python interpreter lock has been |
|
153 released and the lock for Tcl has been acquired. |
|
154 |
|
155 Sometimes, it is necessary to have both the Python lock and the Tcl lock. |
|
156 (For example, when transferring data from the Tcl interpreter result to a |
|
157 Python string object.) This can be done by using different macros to close |
|
158 the ENTER_TCL block: ENTER_OVERLAP reacquires the Python lock (and restores |
|
159 the thread state) but doesn't release the Tcl lock; LEAVE_OVERLAP_TCL |
|
160 releases the Tcl lock. |
|
161 |
|
162 By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event |
|
163 handlers when the handler needs to use Python. Such event handlers are |
|
164 entered while the lock for Tcl is held; the event handler presumably needs |
|
165 to use Python. ENTER_PYTHON releases the lock for Tcl and acquires |
|
166 the Python interpreter lock, restoring the appropriate thread state, and |
|
167 LEAVE_PYTHON releases the Python interpreter lock and re-acquires the lock |
|
168 for Tcl. It is okay for ENTER_TCL/LEAVE_TCL pairs to be contained inside |
|
169 the code between ENTER_PYTHON and LEAVE_PYTHON. |
|
170 |
|
171 These locks expand to several statements and brackets; they should not be |
|
172 used in branches of if statements and the like. |
|
173 |
|
174 If Tcl is threaded, this approach won't work anymore. The Tcl interpreter is |
|
175 only valid in the thread that created it, and all Tk activity must happen in this |
|
176 thread, also. That means that the mainloop must be invoked in the thread that |
|
177 created the interpreter. Invoking commands from other threads is possible; |
|
178 _tkinter will queue an event for the interpreter thread, which will then |
|
179 execute the command and pass back the result. If the main thread is not in the |
|
180 mainloop, and invoking commands causes an exception; if the main loop is running |
|
181 but not processing events, the command invocation will block. |
|
182 |
|
183 In addition, for a threaded Tcl, a single global tcl_tstate won't be sufficient |
|
184 anymore, since multiple Tcl interpreters may simultaneously dispatch in different |
|
185 threads. So we use the Tcl TLS API. |
|
186 |
|
187 */ |
|
188 |
|
189 static PyThread_type_lock tcl_lock = 0; |
|
190 |
|
191 #ifdef TCL_THREADS |
|
192 static Tcl_ThreadDataKey state_key; |
|
193 typedef PyThreadState *ThreadSpecificData; |
|
194 #define tcl_tstate (*(PyThreadState**)Tcl_GetThreadData(&state_key, sizeof(PyThreadState*))) |
|
195 #else |
|
196 static PyThreadState *tcl_tstate = NULL; |
|
197 #endif |
|
198 |
|
199 #define ENTER_TCL \ |
|
200 { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \ |
|
201 if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; |
|
202 |
|
203 #define LEAVE_TCL \ |
|
204 tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS} |
|
205 |
|
206 #define ENTER_OVERLAP \ |
|
207 Py_END_ALLOW_THREADS |
|
208 |
|
209 #define LEAVE_OVERLAP_TCL \ |
|
210 tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); } |
|
211 |
|
212 #define ENTER_PYTHON \ |
|
213 { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \ |
|
214 if(tcl_lock)PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); } |
|
215 |
|
216 #define LEAVE_PYTHON \ |
|
217 { PyThreadState *tstate = PyEval_SaveThread(); \ |
|
218 if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; } |
|
219 |
|
220 #define CHECK_TCL_APPARTMENT \ |
|
221 if (((TkappObject *)self)->threaded && \ |
|
222 ((TkappObject *)self)->thread_id != Tcl_GetCurrentThread()) { \ |
|
223 PyErr_SetString(PyExc_RuntimeError, "Calling Tcl from different appartment"); \ |
|
224 return 0; \ |
|
225 } |
|
226 |
|
227 #else |
|
228 |
|
229 #define ENTER_TCL |
|
230 #define LEAVE_TCL |
|
231 #define ENTER_OVERLAP |
|
232 #define LEAVE_OVERLAP_TCL |
|
233 #define ENTER_PYTHON |
|
234 #define LEAVE_PYTHON |
|
235 #define CHECK_TCL_APPARTMENT |
|
236 |
|
237 #endif |
|
238 |
|
239 #ifndef FREECAST |
|
240 #define FREECAST (char *) |
|
241 #endif |
|
242 |
|
243 /**** Tkapp Object Declaration ****/ |
|
244 |
|
245 static PyTypeObject Tkapp_Type; |
|
246 |
|
247 typedef struct { |
|
248 PyObject_HEAD |
|
249 Tcl_Interp *interp; |
|
250 int wantobjects; |
|
251 int threaded; /* True if tcl_platform[threaded] */ |
|
252 Tcl_ThreadId thread_id; |
|
253 int dispatching; |
|
254 /* We cannot include tclInt.h, as this is internal. |
|
255 So we cache interesting types here. */ |
|
256 Tcl_ObjType *BooleanType; |
|
257 Tcl_ObjType *ByteArrayType; |
|
258 Tcl_ObjType *DoubleType; |
|
259 Tcl_ObjType *IntType; |
|
260 Tcl_ObjType *ListType; |
|
261 Tcl_ObjType *ProcBodyType; |
|
262 Tcl_ObjType *StringType; |
|
263 } TkappObject; |
|
264 |
|
265 #define Tkapp_Check(v) (Py_TYPE(v) == &Tkapp_Type) |
|
266 #define Tkapp_Interp(v) (((TkappObject *) (v))->interp) |
|
267 #define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v)) |
|
268 |
|
269 #define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \ |
|
270 (void *) v, Py_REFCNT(v))) |
|
271 |
|
272 |
|
273 |
|
274 /**** Error Handling ****/ |
|
275 |
|
276 static PyObject *Tkinter_TclError; |
|
277 static int quitMainLoop = 0; |
|
278 static int errorInCmd = 0; |
|
279 static PyObject *excInCmd; |
|
280 static PyObject *valInCmd; |
|
281 static PyObject *trbInCmd; |
|
282 |
|
283 |
|
284 |
|
285 static PyObject * |
|
286 Tkinter_Error(PyObject *v) |
|
287 { |
|
288 PyErr_SetString(Tkinter_TclError, Tkapp_Result(v)); |
|
289 return NULL; |
|
290 } |
|
291 |
|
292 |
|
293 |
|
294 /**** Utils ****/ |
|
295 |
|
296 static int Tkinter_busywaitinterval = 20; |
|
297 |
|
298 #ifdef WITH_THREAD |
|
299 #ifndef MS_WINDOWS |
|
300 |
|
301 /* Millisecond sleep() for Unix platforms. */ |
|
302 |
|
303 static void |
|
304 Sleep(int milli) |
|
305 { |
|
306 /* XXX Too bad if you don't have select(). */ |
|
307 struct timeval t; |
|
308 t.tv_sec = milli/1000; |
|
309 t.tv_usec = (milli%1000) * 1000; |
|
310 select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t); |
|
311 } |
|
312 #endif /* MS_WINDOWS */ |
|
313 |
|
314 /* Wait up to 1s for the mainloop to come up. */ |
|
315 |
|
316 static int |
|
317 WaitForMainloop(TkappObject* self) |
|
318 { |
|
319 int i; |
|
320 for (i = 0; i < 10; i++) { |
|
321 if (self->dispatching) |
|
322 return 1; |
|
323 Py_BEGIN_ALLOW_THREADS |
|
324 Sleep(100); |
|
325 Py_END_ALLOW_THREADS |
|
326 } |
|
327 if (self->dispatching) |
|
328 return 1; |
|
329 PyErr_SetString(PyExc_RuntimeError, "main thread is not in main loop"); |
|
330 return 0; |
|
331 } |
|
332 #endif /* WITH_THREAD */ |
|
333 |
|
334 |
|
335 static char * |
|
336 AsString(PyObject *value, PyObject *tmp) |
|
337 { |
|
338 if (PyString_Check(value)) |
|
339 return PyString_AsString(value); |
|
340 #ifdef Py_USING_UNICODE |
|
341 else if (PyUnicode_Check(value)) { |
|
342 PyObject *v = PyUnicode_AsUTF8String(value); |
|
343 if (v == NULL) |
|
344 return NULL; |
|
345 if (PyList_Append(tmp, v) != 0) { |
|
346 Py_DECREF(v); |
|
347 return NULL; |
|
348 } |
|
349 Py_DECREF(v); |
|
350 return PyString_AsString(v); |
|
351 } |
|
352 #endif |
|
353 else { |
|
354 PyObject *v = PyObject_Str(value); |
|
355 if (v == NULL) |
|
356 return NULL; |
|
357 if (PyList_Append(tmp, v) != 0) { |
|
358 Py_DECREF(v); |
|
359 return NULL; |
|
360 } |
|
361 Py_DECREF(v); |
|
362 return PyString_AsString(v); |
|
363 } |
|
364 } |
|
365 |
|
366 |
|
367 |
|
368 #define ARGSZ 64 |
|
369 |
|
370 static char * |
|
371 Merge(PyObject *args) |
|
372 { |
|
373 PyObject *tmp = NULL; |
|
374 char *argvStore[ARGSZ]; |
|
375 char **argv = NULL; |
|
376 int fvStore[ARGSZ]; |
|
377 int *fv = NULL; |
|
378 int argc = 0, fvc = 0, i; |
|
379 char *res = NULL; |
|
380 |
|
381 if (!(tmp = PyList_New(0))) |
|
382 return NULL; |
|
383 |
|
384 argv = argvStore; |
|
385 fv = fvStore; |
|
386 |
|
387 if (args == NULL) |
|
388 argc = 0; |
|
389 |
|
390 else if (!PyTuple_Check(args)) { |
|
391 argc = 1; |
|
392 fv[0] = 0; |
|
393 if (!(argv[0] = AsString(args, tmp))) |
|
394 goto finally; |
|
395 } |
|
396 else { |
|
397 argc = PyTuple_Size(args); |
|
398 |
|
399 if (argc > ARGSZ) { |
|
400 argv = (char **)ckalloc(argc * sizeof(char *)); |
|
401 fv = (int *)ckalloc(argc * sizeof(int)); |
|
402 if (argv == NULL || fv == NULL) { |
|
403 PyErr_NoMemory(); |
|
404 goto finally; |
|
405 } |
|
406 } |
|
407 |
|
408 for (i = 0; i < argc; i++) { |
|
409 PyObject *v = PyTuple_GetItem(args, i); |
|
410 if (PyTuple_Check(v)) { |
|
411 fv[i] = 1; |
|
412 if (!(argv[i] = Merge(v))) |
|
413 goto finally; |
|
414 fvc++; |
|
415 } |
|
416 else if (v == Py_None) { |
|
417 argc = i; |
|
418 break; |
|
419 } |
|
420 else { |
|
421 fv[i] = 0; |
|
422 if (!(argv[i] = AsString(v, tmp))) |
|
423 goto finally; |
|
424 fvc++; |
|
425 } |
|
426 } |
|
427 } |
|
428 res = Tcl_Merge(argc, argv); |
|
429 if (res == NULL) |
|
430 PyErr_SetString(Tkinter_TclError, "merge failed"); |
|
431 |
|
432 finally: |
|
433 for (i = 0; i < fvc; i++) |
|
434 if (fv[i]) { |
|
435 ckfree(argv[i]); |
|
436 } |
|
437 if (argv != argvStore) |
|
438 ckfree(FREECAST argv); |
|
439 if (fv != fvStore) |
|
440 ckfree(FREECAST fv); |
|
441 |
|
442 Py_DECREF(tmp); |
|
443 return res; |
|
444 } |
|
445 |
|
446 |
|
447 |
|
448 static PyObject * |
|
449 Split(char *list) |
|
450 { |
|
451 int argc; |
|
452 char **argv; |
|
453 PyObject *v; |
|
454 |
|
455 if (list == NULL) { |
|
456 Py_INCREF(Py_None); |
|
457 return Py_None; |
|
458 } |
|
459 |
|
460 if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) { |
|
461 /* Not a list. |
|
462 * Could be a quoted string containing funnies, e.g. {"}. |
|
463 * Return the string itself. |
|
464 */ |
|
465 return PyString_FromString(list); |
|
466 } |
|
467 |
|
468 if (argc == 0) |
|
469 v = PyString_FromString(""); |
|
470 else if (argc == 1) |
|
471 v = PyString_FromString(argv[0]); |
|
472 else if ((v = PyTuple_New(argc)) != NULL) { |
|
473 int i; |
|
474 PyObject *w; |
|
475 |
|
476 for (i = 0; i < argc; i++) { |
|
477 if ((w = Split(argv[i])) == NULL) { |
|
478 Py_DECREF(v); |
|
479 v = NULL; |
|
480 break; |
|
481 } |
|
482 PyTuple_SetItem(v, i, w); |
|
483 } |
|
484 } |
|
485 Tcl_Free(FREECAST argv); |
|
486 return v; |
|
487 } |
|
488 |
|
489 /* In some cases, Tcl will still return strings that are supposed to be |
|
490 lists. SplitObj walks through a nested tuple, finding string objects that |
|
491 need to be split. */ |
|
492 |
|
493 static PyObject * |
|
494 SplitObj(PyObject *arg) |
|
495 { |
|
496 if (PyTuple_Check(arg)) { |
|
497 int i, size; |
|
498 PyObject *elem, *newelem, *result; |
|
499 |
|
500 size = PyTuple_Size(arg); |
|
501 result = NULL; |
|
502 /* Recursively invoke SplitObj for all tuple items. |
|
503 If this does not return a new object, no action is |
|
504 needed. */ |
|
505 for(i = 0; i < size; i++) { |
|
506 elem = PyTuple_GetItem(arg, i); |
|
507 newelem = SplitObj(elem); |
|
508 if (!newelem) { |
|
509 Py_XDECREF(result); |
|
510 return NULL; |
|
511 } |
|
512 if (!result) { |
|
513 int k; |
|
514 if (newelem == elem) { |
|
515 Py_DECREF(newelem); |
|
516 continue; |
|
517 } |
|
518 result = PyTuple_New(size); |
|
519 if (!result) |
|
520 return NULL; |
|
521 for(k = 0; k < i; k++) { |
|
522 elem = PyTuple_GetItem(arg, k); |
|
523 Py_INCREF(elem); |
|
524 PyTuple_SetItem(result, k, elem); |
|
525 } |
|
526 } |
|
527 PyTuple_SetItem(result, i, newelem); |
|
528 } |
|
529 if (result) |
|
530 return result; |
|
531 /* Fall through, returning arg. */ |
|
532 } |
|
533 else if (PyString_Check(arg)) { |
|
534 int argc; |
|
535 char **argv; |
|
536 char *list = PyString_AsString(arg); |
|
537 |
|
538 if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) { |
|
539 Py_INCREF(arg); |
|
540 return arg; |
|
541 } |
|
542 Tcl_Free(FREECAST argv); |
|
543 if (argc > 1) |
|
544 return Split(PyString_AsString(arg)); |
|
545 /* Fall through, returning arg. */ |
|
546 } |
|
547 Py_INCREF(arg); |
|
548 return arg; |
|
549 } |
|
550 |
|
551 |
|
552 /**** Tkapp Object ****/ |
|
553 |
|
554 #ifndef WITH_APPINIT |
|
555 int |
|
556 Tcl_AppInit(Tcl_Interp *interp) |
|
557 { |
|
558 Tk_Window main; |
|
559 const char * _tkinter_skip_tk_init; |
|
560 |
|
561 if (Tcl_Init(interp) == TCL_ERROR) { |
|
562 PySys_WriteStderr("Tcl_Init error: %s\n", Tcl_GetStringResult(interp)); |
|
563 return TCL_ERROR; |
|
564 } |
|
565 _tkinter_skip_tk_init = Tcl_GetVar(interp, "_tkinter_skip_tk_init", TCL_GLOBAL_ONLY); |
|
566 if (_tkinter_skip_tk_init == NULL || strcmp(_tkinter_skip_tk_init, "1") != 0) { |
|
567 main = Tk_MainWindow(interp); |
|
568 if (Tk_Init(interp) == TCL_ERROR) { |
|
569 PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp)); |
|
570 return TCL_ERROR; |
|
571 } |
|
572 } |
|
573 return TCL_OK; |
|
574 } |
|
575 #endif /* !WITH_APPINIT */ |
|
576 |
|
577 |
|
578 |
|
579 |
|
580 /* Initialize the Tk application; see the `main' function in |
|
581 * `tkMain.c'. |
|
582 */ |
|
583 |
|
584 static void EnableEventHook(void); /* Forward */ |
|
585 static void DisableEventHook(void); /* Forward */ |
|
586 |
|
587 static TkappObject * |
|
588 Tkapp_New(char *screenName, char *baseName, char *className, |
|
589 int interactive, int wantobjects, int wantTk, int sync, char *use) |
|
590 { |
|
591 TkappObject *v; |
|
592 char *argv0; |
|
593 |
|
594 v = PyObject_New(TkappObject, &Tkapp_Type); |
|
595 if (v == NULL) |
|
596 return NULL; |
|
597 |
|
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; |
|
604 |
|
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; |
|
610 } |
|
611 #endif |
|
612 #ifdef WITH_THREAD |
|
613 if (v->threaded && tcl_lock) { |
|
614 /* If Tcl is threaded, we don't need the lock. */ |
|
615 PyThread_free_lock(tcl_lock); |
|
616 tcl_lock = NULL; |
|
617 } |
|
618 #endif |
|
619 |
|
620 v->BooleanType = Tcl_GetObjType("boolean"); |
|
621 v->ByteArrayType = Tcl_GetObjType("bytearray"); |
|
622 v->DoubleType = Tcl_GetObjType("double"); |
|
623 v->IntType = Tcl_GetObjType("int"); |
|
624 v->ListType = Tcl_GetObjType("list"); |
|
625 v->ProcBodyType = Tcl_GetObjType("procbody"); |
|
626 v->StringType = Tcl_GetObjType("string"); |
|
627 |
|
628 /* Delete the 'exit' command, which can screw things up */ |
|
629 Tcl_DeleteCommand(v->interp, "exit"); |
|
630 |
|
631 if (screenName != NULL) |
|
632 Tcl_SetVar2(v->interp, "env", "DISPLAY", |
|
633 screenName, TCL_GLOBAL_ONLY); |
|
634 |
|
635 if (interactive) |
|
636 Tcl_SetVar(v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY); |
|
637 else |
|
638 Tcl_SetVar(v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY); |
|
639 |
|
640 /* This is used to get the application class for Tk 4.1 and up */ |
|
641 argv0 = (char*)ckalloc(strlen(className) + 1); |
|
642 if (!argv0) { |
|
643 PyErr_NoMemory(); |
|
644 Py_DECREF(v); |
|
645 return NULL; |
|
646 } |
|
647 |
|
648 strcpy(argv0, className); |
|
649 if (isupper(Py_CHARMASK(argv0[0]))) |
|
650 argv0[0] = tolower(Py_CHARMASK(argv0[0])); |
|
651 Tcl_SetVar(v->interp, "argv0", argv0, TCL_GLOBAL_ONLY); |
|
652 ckfree(argv0); |
|
653 |
|
654 if (! wantTk) { |
|
655 Tcl_SetVar(v->interp, "_tkinter_skip_tk_init", "1", TCL_GLOBAL_ONLY); |
|
656 } |
|
657 |
|
658 /* some initial arguments need to be in argv */ |
|
659 if (sync || use) { |
|
660 char *args; |
|
661 int len = 0; |
|
662 |
|
663 if (sync) |
|
664 len += sizeof "-sync"; |
|
665 if (use) |
|
666 len += strlen(use) + sizeof "-use "; |
|
667 |
|
668 args = (char*)ckalloc(len); |
|
669 if (!args) { |
|
670 PyErr_NoMemory(); |
|
671 Py_DECREF(v); |
|
672 return NULL; |
|
673 } |
|
674 |
|
675 args[0] = '\0'; |
|
676 if (sync) |
|
677 strcat(args, "-sync"); |
|
678 if (use) { |
|
679 if (sync) |
|
680 strcat(args, " "); |
|
681 strcat(args, "-use "); |
|
682 strcat(args, use); |
|
683 } |
|
684 |
|
685 Tcl_SetVar(v->interp, "argv", args, TCL_GLOBAL_ONLY); |
|
686 ckfree(args); |
|
687 } |
|
688 |
|
689 if (Tcl_AppInit(v->interp) != TCL_OK) { |
|
690 PyObject *result = Tkinter_Error((PyObject *)v); |
|
691 Py_DECREF((PyObject *)v); |
|
692 return (TkappObject *)result; |
|
693 } |
|
694 |
|
695 EnableEventHook(); |
|
696 |
|
697 return v; |
|
698 } |
|
699 |
|
700 |
|
701 static void |
|
702 Tkapp_ThreadSend(TkappObject *self, Tcl_Event *ev, |
|
703 Tcl_Condition *cond, Tcl_Mutex *mutex) |
|
704 { |
|
705 Py_BEGIN_ALLOW_THREADS; |
|
706 Tcl_MutexLock(mutex); |
|
707 Tcl_ThreadQueueEvent(self->thread_id, ev, TCL_QUEUE_TAIL); |
|
708 Tcl_ThreadAlert(self->thread_id); |
|
709 Tcl_ConditionWait(cond, mutex, NULL); |
|
710 Tcl_MutexUnlock(mutex); |
|
711 Py_END_ALLOW_THREADS |
|
712 } |
|
713 |
|
714 |
|
715 /** Tcl Eval **/ |
|
716 |
|
717 typedef struct { |
|
718 PyObject_HEAD |
|
719 Tcl_Obj *value; |
|
720 PyObject *string; /* This cannot cause cycles. */ |
|
721 } PyTclObject; |
|
722 |
|
723 staticforward PyTypeObject PyTclObject_Type; |
|
724 #define PyTclObject_Check(v) ((v)->ob_type == &PyTclObject_Type) |
|
725 |
|
726 static PyObject * |
|
727 newPyTclObject(Tcl_Obj *arg) |
|
728 { |
|
729 PyTclObject *self; |
|
730 self = PyObject_New(PyTclObject, &PyTclObject_Type); |
|
731 if (self == NULL) |
|
732 return NULL; |
|
733 Tcl_IncrRefCount(arg); |
|
734 self->value = arg; |
|
735 self->string = NULL; |
|
736 return (PyObject*)self; |
|
737 } |
|
738 |
|
739 static void |
|
740 PyTclObject_dealloc(PyTclObject *self) |
|
741 { |
|
742 Tcl_DecrRefCount(self->value); |
|
743 Py_XDECREF(self->string); |
|
744 PyObject_Del(self); |
|
745 } |
|
746 |
|
747 static PyObject * |
|
748 PyTclObject_str(PyTclObject *self) |
|
749 { |
|
750 if (self->string && PyString_Check(self->string)) { |
|
751 Py_INCREF(self->string); |
|
752 return self->string; |
|
753 } |
|
754 /* XXX Could cache value if it is an ASCII string. */ |
|
755 return PyString_FromString(Tcl_GetString(self->value)); |
|
756 } |
|
757 |
|
758 static char* |
|
759 PyTclObject_TclString(PyObject *self) |
|
760 { |
|
761 return Tcl_GetString(((PyTclObject*)self)->value); |
|
762 } |
|
763 |
|
764 /* Like _str, but create Unicode if necessary. */ |
|
765 PyDoc_STRVAR(PyTclObject_string__doc__, |
|
766 "the string representation of this object, either as string or Unicode"); |
|
767 |
|
768 static PyObject * |
|
769 PyTclObject_string(PyTclObject *self, void *ignored) |
|
770 { |
|
771 char *s; |
|
772 int i, len; |
|
773 if (!self->string) { |
|
774 s = Tcl_GetStringFromObj(self->value, &len); |
|
775 for (i = 0; i < len; i++) |
|
776 if (s[i] & 0x80) |
|
777 break; |
|
778 #ifdef Py_USING_UNICODE |
|
779 if (i == len) |
|
780 /* It is an ASCII string. */ |
|
781 self->string = PyString_FromStringAndSize(s, len); |
|
782 else { |
|
783 self->string = PyUnicode_DecodeUTF8(s, len, "strict"); |
|
784 if (!self->string) { |
|
785 PyErr_Clear(); |
|
786 self->string = PyString_FromStringAndSize(s, len); |
|
787 } |
|
788 } |
|
789 #else |
|
790 self->string = PyString_FromStringAndSize(s, len); |
|
791 #endif |
|
792 if (!self->string) |
|
793 return NULL; |
|
794 } |
|
795 Py_INCREF(self->string); |
|
796 return self->string; |
|
797 } |
|
798 |
|
799 #ifdef Py_USING_UNICODE |
|
800 PyDoc_STRVAR(PyTclObject_unicode__doc__, "convert argument to unicode"); |
|
801 |
|
802 static PyObject * |
|
803 PyTclObject_unicode(PyTclObject *self, void *ignored) |
|
804 { |
|
805 char *s; |
|
806 int len; |
|
807 if (self->string && PyUnicode_Check(self->string)) { |
|
808 Py_INCREF(self->string); |
|
809 return self->string; |
|
810 } |
|
811 /* XXX Could chache result if it is non-ASCII. */ |
|
812 s = Tcl_GetStringFromObj(self->value, &len); |
|
813 return PyUnicode_DecodeUTF8(s, len, "strict"); |
|
814 } |
|
815 #endif |
|
816 |
|
817 static PyObject * |
|
818 PyTclObject_repr(PyTclObject *self) |
|
819 { |
|
820 char buf[50]; |
|
821 PyOS_snprintf(buf, 50, "<%s object at %p>", |
|
822 self->value->typePtr->name, self->value); |
|
823 return PyString_FromString(buf); |
|
824 } |
|
825 |
|
826 static int |
|
827 PyTclObject_cmp(PyTclObject *self, PyTclObject *other) |
|
828 { |
|
829 int res; |
|
830 res = strcmp(Tcl_GetString(self->value), |
|
831 Tcl_GetString(other->value)); |
|
832 if (res < 0) return -1; |
|
833 if (res > 0) return 1; |
|
834 return 0; |
|
835 } |
|
836 |
|
837 PyDoc_STRVAR(get_typename__doc__, "name of the Tcl type"); |
|
838 |
|
839 static PyObject* |
|
840 get_typename(PyTclObject* obj, void* ignored) |
|
841 { |
|
842 return PyString_FromString(obj->value->typePtr->name); |
|
843 } |
|
844 |
|
845 |
|
846 static PyGetSetDef PyTclObject_getsetlist[] = { |
|
847 {"typename", (getter)get_typename, NULL, get_typename__doc__}, |
|
848 {"string", (getter)PyTclObject_string, NULL, |
|
849 PyTclObject_string__doc__}, |
|
850 {0}, |
|
851 }; |
|
852 |
|
853 static PyMethodDef PyTclObject_methods[] = { |
|
854 #ifdef Py_USING_UNICODE |
|
855 {"__unicode__", (PyCFunction)PyTclObject_unicode, METH_NOARGS, |
|
856 PyTclObject_unicode__doc__}, |
|
857 #endif |
|
858 {0} |
|
859 }; |
|
860 |
|
861 statichere PyTypeObject PyTclObject_Type = { |
|
862 PyObject_HEAD_INIT(NULL) |
|
863 0, /*ob_size*/ |
|
864 "_tkinter.Tcl_Obj", /*tp_name*/ |
|
865 sizeof(PyTclObject), /*tp_basicsize*/ |
|
866 0, /*tp_itemsize*/ |
|
867 /* methods */ |
|
868 (destructor)PyTclObject_dealloc, /*tp_dealloc*/ |
|
869 0, /*tp_print*/ |
|
870 0, /*tp_getattr*/ |
|
871 0, /*tp_setattr*/ |
|
872 (cmpfunc)PyTclObject_cmp, /*tp_compare*/ |
|
873 (reprfunc)PyTclObject_repr, /*tp_repr*/ |
|
874 0, /*tp_as_number*/ |
|
875 0, /*tp_as_sequence*/ |
|
876 0, /*tp_as_mapping*/ |
|
877 0, /*tp_hash*/ |
|
878 0, /*tp_call*/ |
|
879 (reprfunc)PyTclObject_str, /*tp_str*/ |
|
880 PyObject_GenericGetAttr,/*tp_getattro*/ |
|
881 0, /*tp_setattro*/ |
|
882 0, /*tp_as_buffer*/ |
|
883 Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
|
884 0, /*tp_doc*/ |
|
885 0, /*tp_traverse*/ |
|
886 0, /*tp_clear*/ |
|
887 0, /*tp_richcompare*/ |
|
888 0, /*tp_weaklistoffset*/ |
|
889 0, /*tp_iter*/ |
|
890 0, /*tp_iternext*/ |
|
891 PyTclObject_methods, /*tp_methods*/ |
|
892 0, /*tp_members*/ |
|
893 PyTclObject_getsetlist, /*tp_getset*/ |
|
894 0, /*tp_base*/ |
|
895 0, /*tp_dict*/ |
|
896 0, /*tp_descr_get*/ |
|
897 0, /*tp_descr_set*/ |
|
898 0, /*tp_dictoffset*/ |
|
899 0, /*tp_init*/ |
|
900 0, /*tp_alloc*/ |
|
901 0, /*tp_new*/ |
|
902 0, /*tp_free*/ |
|
903 0, /*tp_is_gc*/ |
|
904 }; |
|
905 |
|
906 static Tcl_Obj* |
|
907 AsObj(PyObject *value) |
|
908 { |
|
909 Tcl_Obj *result; |
|
910 |
|
911 if (PyString_Check(value)) |
|
912 return Tcl_NewStringObj(PyString_AS_STRING(value), |
|
913 PyString_GET_SIZE(value)); |
|
914 else if (PyBool_Check(value)) |
|
915 return Tcl_NewBooleanObj(PyObject_IsTrue(value)); |
|
916 else if (PyInt_Check(value)) |
|
917 return Tcl_NewLongObj(PyInt_AS_LONG(value)); |
|
918 else if (PyFloat_Check(value)) |
|
919 return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value)); |
|
920 else if (PyTuple_Check(value)) { |
|
921 Tcl_Obj **argv = (Tcl_Obj**) |
|
922 ckalloc(PyTuple_Size(value)*sizeof(Tcl_Obj*)); |
|
923 int i; |
|
924 if(!argv) |
|
925 return 0; |
|
926 for(i=0;i<PyTuple_Size(value);i++) |
|
927 argv[i] = AsObj(PyTuple_GetItem(value,i)); |
|
928 result = Tcl_NewListObj(PyTuple_Size(value), argv); |
|
929 ckfree(FREECAST argv); |
|
930 return result; |
|
931 } |
|
932 #ifdef Py_USING_UNICODE |
|
933 else if (PyUnicode_Check(value)) { |
|
934 Py_UNICODE *inbuf = PyUnicode_AS_UNICODE(value); |
|
935 Py_ssize_t size = PyUnicode_GET_SIZE(value); |
|
936 /* This #ifdef assumes that Tcl uses UCS-2. |
|
937 See TCL_UTF_MAX test above. */ |
|
938 #if defined(Py_UNICODE_WIDE) && TCL_UTF_MAX == 3 |
|
939 Tcl_UniChar *outbuf = NULL; |
|
940 Py_ssize_t i; |
|
941 size_t allocsize = ((size_t)size) * sizeof(Tcl_UniChar); |
|
942 if (allocsize >= size) |
|
943 outbuf = (Tcl_UniChar*)ckalloc(allocsize); |
|
944 /* Else overflow occurred, and we take the next exit */ |
|
945 if (!outbuf) { |
|
946 PyErr_NoMemory(); |
|
947 return NULL; |
|
948 } |
|
949 for (i = 0; i < size; i++) { |
|
950 if (inbuf[i] >= 0x10000) { |
|
951 /* Tcl doesn't do UTF-16, yet. */ |
|
952 PyErr_SetString(PyExc_ValueError, |
|
953 "unsupported character"); |
|
954 ckfree(FREECAST outbuf); |
|
955 return NULL; |
|
956 } |
|
957 outbuf[i] = inbuf[i]; |
|
958 } |
|
959 result = Tcl_NewUnicodeObj(outbuf, size); |
|
960 ckfree(FREECAST outbuf); |
|
961 return result; |
|
962 #else |
|
963 return Tcl_NewUnicodeObj(inbuf, size); |
|
964 #endif |
|
965 |
|
966 } |
|
967 #endif |
|
968 else if(PyTclObject_Check(value)) { |
|
969 Tcl_Obj *v = ((PyTclObject*)value)->value; |
|
970 Tcl_IncrRefCount(v); |
|
971 return v; |
|
972 } |
|
973 else { |
|
974 PyObject *v = PyObject_Str(value); |
|
975 if (!v) |
|
976 return 0; |
|
977 result = AsObj(v); |
|
978 Py_DECREF(v); |
|
979 return result; |
|
980 } |
|
981 } |
|
982 |
|
983 static PyObject* |
|
984 FromObj(PyObject* tkapp, Tcl_Obj *value) |
|
985 { |
|
986 PyObject *result = NULL; |
|
987 TkappObject *app = (TkappObject*)tkapp; |
|
988 |
|
989 if (value->typePtr == NULL) { |
|
990 /* If the result contains any bytes with the top bit set, |
|
991 it's UTF-8 and we should decode it to Unicode */ |
|
992 #ifdef Py_USING_UNICODE |
|
993 int i; |
|
994 char *s = value->bytes; |
|
995 int len = value->length; |
|
996 for (i = 0; i < len; i++) { |
|
997 if (value->bytes[i] & 0x80) |
|
998 break; |
|
999 } |
|
1000 |
|
1001 if (i == value->length) |
|
1002 result = PyString_FromStringAndSize(s, len); |
|
1003 else { |
|
1004 /* Convert UTF-8 to Unicode string */ |
|
1005 result = PyUnicode_DecodeUTF8(s, len, "strict"); |
|
1006 if (result == NULL) { |
|
1007 PyErr_Clear(); |
|
1008 result = PyString_FromStringAndSize(s, len); |
|
1009 } |
|
1010 } |
|
1011 #else |
|
1012 result = PyString_FromStringAndSize(value->bytes, value->length); |
|
1013 #endif |
|
1014 return result; |
|
1015 } |
|
1016 |
|
1017 if (value->typePtr == app->BooleanType) { |
|
1018 result = value->internalRep.longValue ? Py_True : Py_False; |
|
1019 Py_INCREF(result); |
|
1020 return result; |
|
1021 } |
|
1022 |
|
1023 if (value->typePtr == app->ByteArrayType) { |
|
1024 int size; |
|
1025 char *data = (char*)Tcl_GetByteArrayFromObj(value, &size); |
|
1026 return PyString_FromStringAndSize(data, size); |
|
1027 } |
|
1028 |
|
1029 if (value->typePtr == app->DoubleType) { |
|
1030 return PyFloat_FromDouble(value->internalRep.doubleValue); |
|
1031 } |
|
1032 |
|
1033 if (value->typePtr == app->IntType) { |
|
1034 return PyInt_FromLong(value->internalRep.longValue); |
|
1035 } |
|
1036 |
|
1037 if (value->typePtr == app->ListType) { |
|
1038 int size; |
|
1039 int i, status; |
|
1040 PyObject *elem; |
|
1041 Tcl_Obj *tcl_elem; |
|
1042 |
|
1043 status = Tcl_ListObjLength(Tkapp_Interp(tkapp), value, &size); |
|
1044 if (status == TCL_ERROR) |
|
1045 return Tkinter_Error(tkapp); |
|
1046 result = PyTuple_New(size); |
|
1047 if (!result) |
|
1048 return NULL; |
|
1049 for (i = 0; i < size; i++) { |
|
1050 status = Tcl_ListObjIndex(Tkapp_Interp(tkapp), |
|
1051 value, i, &tcl_elem); |
|
1052 if (status == TCL_ERROR) { |
|
1053 Py_DECREF(result); |
|
1054 return Tkinter_Error(tkapp); |
|
1055 } |
|
1056 elem = FromObj(tkapp, tcl_elem); |
|
1057 if (!elem) { |
|
1058 Py_DECREF(result); |
|
1059 return NULL; |
|
1060 } |
|
1061 PyTuple_SetItem(result, i, elem); |
|
1062 } |
|
1063 return result; |
|
1064 } |
|
1065 |
|
1066 if (value->typePtr == app->ProcBodyType) { |
|
1067 /* fall through: return tcl object. */ |
|
1068 } |
|
1069 |
|
1070 if (value->typePtr == app->StringType) { |
|
1071 #ifdef Py_USING_UNICODE |
|
1072 #if defined(Py_UNICODE_WIDE) && TCL_UTF_MAX==3 |
|
1073 PyObject *result; |
|
1074 int size; |
|
1075 Tcl_UniChar *input; |
|
1076 Py_UNICODE *output; |
|
1077 |
|
1078 size = Tcl_GetCharLength(value); |
|
1079 result = PyUnicode_FromUnicode(NULL, size); |
|
1080 if (!result) |
|
1081 return NULL; |
|
1082 input = Tcl_GetUnicode(value); |
|
1083 output = PyUnicode_AS_UNICODE(result); |
|
1084 while (size--) |
|
1085 *output++ = *input++; |
|
1086 return result; |
|
1087 #else |
|
1088 return PyUnicode_FromUnicode(Tcl_GetUnicode(value), |
|
1089 Tcl_GetCharLength(value)); |
|
1090 #endif |
|
1091 #else |
|
1092 int size; |
|
1093 char *c; |
|
1094 c = Tcl_GetStringFromObj(value, &size); |
|
1095 return PyString_FromStringAndSize(c, size); |
|
1096 #endif |
|
1097 } |
|
1098 |
|
1099 return newPyTclObject(value); |
|
1100 } |
|
1101 |
|
1102 /* This mutex synchronizes inter-thread command calls. */ |
|
1103 |
|
1104 TCL_DECLARE_MUTEX(call_mutex) |
|
1105 |
|
1106 typedef struct Tkapp_CallEvent { |
|
1107 Tcl_Event ev; /* Must be first */ |
|
1108 TkappObject *self; |
|
1109 PyObject *args; |
|
1110 int flags; |
|
1111 PyObject **res; |
|
1112 PyObject **exc_type, **exc_value, **exc_tb; |
|
1113 Tcl_Condition done; |
|
1114 } Tkapp_CallEvent; |
|
1115 |
|
1116 void |
|
1117 Tkapp_CallDeallocArgs(Tcl_Obj** objv, Tcl_Obj** objStore, int objc) |
|
1118 { |
|
1119 int i; |
|
1120 for (i = 0; i < objc; i++) |
|
1121 Tcl_DecrRefCount(objv[i]); |
|
1122 if (objv != objStore) |
|
1123 ckfree(FREECAST objv); |
|
1124 } |
|
1125 |
|
1126 /* Convert Python objects to Tcl objects. This must happen in the |
|
1127 interpreter thread, which may or may not be the calling thread. */ |
|
1128 |
|
1129 static Tcl_Obj** |
|
1130 Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc) |
|
1131 { |
|
1132 Tcl_Obj **objv = objStore; |
|
1133 int objc = 0, i; |
|
1134 if (args == NULL) |
|
1135 /* do nothing */; |
|
1136 |
|
1137 else if (!PyTuple_Check(args)) { |
|
1138 objv[0] = AsObj(args); |
|
1139 if (objv[0] == 0) |
|
1140 goto finally; |
|
1141 objc = 1; |
|
1142 Tcl_IncrRefCount(objv[0]); |
|
1143 } |
|
1144 else { |
|
1145 objc = PyTuple_Size(args); |
|
1146 |
|
1147 if (objc > ARGSZ) { |
|
1148 objv = (Tcl_Obj **)ckalloc(objc * sizeof(char *)); |
|
1149 if (objv == NULL) { |
|
1150 PyErr_NoMemory(); |
|
1151 objc = 0; |
|
1152 goto finally; |
|
1153 } |
|
1154 } |
|
1155 |
|
1156 for (i = 0; i < objc; i++) { |
|
1157 PyObject *v = PyTuple_GetItem(args, i); |
|
1158 if (v == Py_None) { |
|
1159 objc = i; |
|
1160 break; |
|
1161 } |
|
1162 objv[i] = AsObj(v); |
|
1163 if (!objv[i]) { |
|
1164 /* Reset objc, so it attempts to clear |
|
1165 objects only up to i. */ |
|
1166 objc = i; |
|
1167 goto finally; |
|
1168 } |
|
1169 Tcl_IncrRefCount(objv[i]); |
|
1170 } |
|
1171 } |
|
1172 *pobjc = objc; |
|
1173 return objv; |
|
1174 finally: |
|
1175 Tkapp_CallDeallocArgs(objv, objStore, objc); |
|
1176 return NULL; |
|
1177 } |
|
1178 |
|
1179 /* Convert the results of a command call into a Python objects. */ |
|
1180 |
|
1181 static PyObject* |
|
1182 Tkapp_CallResult(TkappObject *self) |
|
1183 { |
|
1184 PyObject *res = NULL; |
|
1185 if(self->wantobjects) { |
|
1186 Tcl_Obj *value = Tcl_GetObjResult(self->interp); |
|
1187 /* Not sure whether the IncrRef is necessary, but something |
|
1188 may overwrite the interpreter result while we are |
|
1189 converting it. */ |
|
1190 Tcl_IncrRefCount(value); |
|
1191 res = FromObj((PyObject*)self, value); |
|
1192 Tcl_DecrRefCount(value); |
|
1193 } else { |
|
1194 const char *s = Tcl_GetStringResult(self->interp); |
|
1195 const char *p = s; |
|
1196 |
|
1197 /* If the result contains any bytes with the top bit set, |
|
1198 it's UTF-8 and we should decode it to Unicode */ |
|
1199 #ifdef Py_USING_UNICODE |
|
1200 while (*p != '\0') { |
|
1201 if (*p & 0x80) |
|
1202 break; |
|
1203 p++; |
|
1204 } |
|
1205 |
|
1206 if (*p == '\0') |
|
1207 res = PyString_FromStringAndSize(s, (int)(p-s)); |
|
1208 else { |
|
1209 /* Convert UTF-8 to Unicode string */ |
|
1210 p = strchr(p, '\0'); |
|
1211 res = PyUnicode_DecodeUTF8(s, (int)(p-s), "strict"); |
|
1212 if (res == NULL) { |
|
1213 PyErr_Clear(); |
|
1214 res = PyString_FromStringAndSize(s, (int)(p-s)); |
|
1215 } |
|
1216 } |
|
1217 #else |
|
1218 p = strchr(p, '\0'); |
|
1219 res = PyString_FromStringAndSize(s, (int)(p-s)); |
|
1220 #endif |
|
1221 } |
|
1222 return res; |
|
1223 } |
|
1224 |
|
1225 /* Tkapp_CallProc is the event procedure that is executed in the context of |
|
1226 the Tcl interpreter thread. Initially, it holds the Tcl lock, and doesn't |
|
1227 hold the Python lock. */ |
|
1228 |
|
1229 static int |
|
1230 Tkapp_CallProc(Tkapp_CallEvent *e, int flags) |
|
1231 { |
|
1232 Tcl_Obj *objStore[ARGSZ]; |
|
1233 Tcl_Obj **objv; |
|
1234 int objc; |
|
1235 int i; |
|
1236 ENTER_PYTHON |
|
1237 objv = Tkapp_CallArgs(e->args, objStore, &objc); |
|
1238 if (!objv) { |
|
1239 PyErr_Fetch(e->exc_type, e->exc_value, e->exc_tb); |
|
1240 *(e->res) = NULL; |
|
1241 } |
|
1242 LEAVE_PYTHON |
|
1243 if (!objv) |
|
1244 goto done; |
|
1245 i = Tcl_EvalObjv(e->self->interp, objc, objv, e->flags); |
|
1246 ENTER_PYTHON |
|
1247 if (i == TCL_ERROR) { |
|
1248 *(e->res) = NULL; |
|
1249 *(e->exc_type) = NULL; |
|
1250 *(e->exc_tb) = NULL; |
|
1251 *(e->exc_value) = PyObject_CallFunction( |
|
1252 Tkinter_TclError, "s", |
|
1253 Tcl_GetStringResult(e->self->interp)); |
|
1254 } |
|
1255 else { |
|
1256 *(e->res) = Tkapp_CallResult(e->self); |
|
1257 } |
|
1258 LEAVE_PYTHON |
|
1259 done: |
|
1260 /* Wake up calling thread. */ |
|
1261 Tcl_MutexLock(&call_mutex); |
|
1262 Tcl_ConditionNotify(&e->done); |
|
1263 Tcl_MutexUnlock(&call_mutex); |
|
1264 return 1; |
|
1265 } |
|
1266 |
|
1267 /* This is the main entry point for calling a Tcl command. |
|
1268 It supports three cases, with regard to threading: |
|
1269 1. Tcl is not threaded: Must have the Tcl lock, then can invoke command in |
|
1270 the context of the calling thread. |
|
1271 2. Tcl is threaded, caller of the command is in the interpreter thread: |
|
1272 Execute the command in the calling thread. Since the Tcl lock will |
|
1273 not be used, we can merge that with case 1. |
|
1274 3. Tcl is threaded, caller is in a different thread: Must queue an event to |
|
1275 the interpreter thread. Allocation of Tcl objects needs to occur in the |
|
1276 interpreter thread, so we ship the PyObject* args to the target thread, |
|
1277 and perform processing there. */ |
|
1278 |
|
1279 static PyObject * |
|
1280 Tkapp_Call(PyObject *selfptr, PyObject *args) |
|
1281 { |
|
1282 Tcl_Obj *objStore[ARGSZ]; |
|
1283 Tcl_Obj **objv = NULL; |
|
1284 int objc, i; |
|
1285 PyObject *res = NULL; |
|
1286 TkappObject *self = (TkappObject*)selfptr; |
|
1287 /* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */ |
|
1288 int flags = TCL_EVAL_DIRECT; |
|
1289 |
|
1290 /* If args is a single tuple, replace with contents of tuple */ |
|
1291 if (1 == PyTuple_Size(args)){ |
|
1292 PyObject* item = PyTuple_GetItem(args, 0); |
|
1293 if (PyTuple_Check(item)) |
|
1294 args = item; |
|
1295 } |
|
1296 #ifdef WITH_THREAD |
|
1297 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { |
|
1298 /* We cannot call the command directly. Instead, we must |
|
1299 marshal the parameters to the interpreter thread. */ |
|
1300 Tkapp_CallEvent *ev; |
|
1301 PyObject *exc_type, *exc_value, *exc_tb; |
|
1302 if (!WaitForMainloop(self)) |
|
1303 return NULL; |
|
1304 ev = (Tkapp_CallEvent*)ckalloc(sizeof(Tkapp_CallEvent)); |
|
1305 ev->ev.proc = (Tcl_EventProc*)Tkapp_CallProc; |
|
1306 ev->self = self; |
|
1307 ev->args = args; |
|
1308 ev->res = &res; |
|
1309 ev->exc_type = &exc_type; |
|
1310 ev->exc_value = &exc_value; |
|
1311 ev->exc_tb = &exc_tb; |
|
1312 ev->done = (Tcl_Condition)0; |
|
1313 |
|
1314 Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->done, &call_mutex); |
|
1315 |
|
1316 if (res == NULL) { |
|
1317 if (exc_type) |
|
1318 PyErr_Restore(exc_type, exc_value, exc_tb); |
|
1319 else |
|
1320 PyErr_SetObject(Tkinter_TclError, exc_value); |
|
1321 } |
|
1322 } |
|
1323 else |
|
1324 #endif |
|
1325 { |
|
1326 |
|
1327 objv = Tkapp_CallArgs(args, objStore, &objc); |
|
1328 if (!objv) |
|
1329 return NULL; |
|
1330 |
|
1331 ENTER_TCL |
|
1332 |
|
1333 i = Tcl_EvalObjv(self->interp, objc, objv, flags); |
|
1334 |
|
1335 ENTER_OVERLAP |
|
1336 |
|
1337 if (i == TCL_ERROR) |
|
1338 Tkinter_Error(selfptr); |
|
1339 else |
|
1340 res = Tkapp_CallResult(self); |
|
1341 |
|
1342 LEAVE_OVERLAP_TCL |
|
1343 |
|
1344 Tkapp_CallDeallocArgs(objv, objStore, objc); |
|
1345 } |
|
1346 return res; |
|
1347 } |
|
1348 |
|
1349 |
|
1350 static PyObject * |
|
1351 Tkapp_GlobalCall(PyObject *self, PyObject *args) |
|
1352 { |
|
1353 /* Could do the same here as for Tkapp_Call(), but this is not used |
|
1354 much, so I can't be bothered. Unfortunately Tcl doesn't export a |
|
1355 way for the user to do what all its Global* variants do (save and |
|
1356 reset the scope pointer, call the local version, restore the saved |
|
1357 scope pointer). */ |
|
1358 |
|
1359 char *cmd; |
|
1360 PyObject *res = NULL; |
|
1361 |
|
1362 CHECK_TCL_APPARTMENT; |
|
1363 |
|
1364 cmd = Merge(args); |
|
1365 if (cmd) { |
|
1366 int err; |
|
1367 ENTER_TCL |
|
1368 err = Tcl_GlobalEval(Tkapp_Interp(self), cmd); |
|
1369 ENTER_OVERLAP |
|
1370 if (err == TCL_ERROR) |
|
1371 res = Tkinter_Error(self); |
|
1372 else |
|
1373 res = PyString_FromString(Tkapp_Result(self)); |
|
1374 LEAVE_OVERLAP_TCL |
|
1375 ckfree(cmd); |
|
1376 } |
|
1377 |
|
1378 return res; |
|
1379 } |
|
1380 |
|
1381 static PyObject * |
|
1382 Tkapp_Eval(PyObject *self, PyObject *args) |
|
1383 { |
|
1384 char *script; |
|
1385 PyObject *res = NULL; |
|
1386 int err; |
|
1387 |
|
1388 if (!PyArg_ParseTuple(args, "s:eval", &script)) |
|
1389 return NULL; |
|
1390 |
|
1391 CHECK_TCL_APPARTMENT; |
|
1392 |
|
1393 ENTER_TCL |
|
1394 err = Tcl_Eval(Tkapp_Interp(self), script); |
|
1395 ENTER_OVERLAP |
|
1396 if (err == TCL_ERROR) |
|
1397 res = Tkinter_Error(self); |
|
1398 else |
|
1399 res = PyString_FromString(Tkapp_Result(self)); |
|
1400 LEAVE_OVERLAP_TCL |
|
1401 return res; |
|
1402 } |
|
1403 |
|
1404 static PyObject * |
|
1405 Tkapp_GlobalEval(PyObject *self, PyObject *args) |
|
1406 { |
|
1407 char *script; |
|
1408 PyObject *res = NULL; |
|
1409 int err; |
|
1410 |
|
1411 if (!PyArg_ParseTuple(args, "s:globaleval", &script)) |
|
1412 return NULL; |
|
1413 |
|
1414 CHECK_TCL_APPARTMENT; |
|
1415 |
|
1416 ENTER_TCL |
|
1417 err = Tcl_GlobalEval(Tkapp_Interp(self), script); |
|
1418 ENTER_OVERLAP |
|
1419 if (err == TCL_ERROR) |
|
1420 res = Tkinter_Error(self); |
|
1421 else |
|
1422 res = PyString_FromString(Tkapp_Result(self)); |
|
1423 LEAVE_OVERLAP_TCL |
|
1424 return res; |
|
1425 } |
|
1426 |
|
1427 static PyObject * |
|
1428 Tkapp_EvalFile(PyObject *self, PyObject *args) |
|
1429 { |
|
1430 char *fileName; |
|
1431 PyObject *res = NULL; |
|
1432 int err; |
|
1433 |
|
1434 if (!PyArg_ParseTuple(args, "s:evalfile", &fileName)) |
|
1435 return NULL; |
|
1436 |
|
1437 CHECK_TCL_APPARTMENT; |
|
1438 |
|
1439 ENTER_TCL |
|
1440 err = Tcl_EvalFile(Tkapp_Interp(self), fileName); |
|
1441 ENTER_OVERLAP |
|
1442 if (err == TCL_ERROR) |
|
1443 res = Tkinter_Error(self); |
|
1444 |
|
1445 else |
|
1446 res = PyString_FromString(Tkapp_Result(self)); |
|
1447 LEAVE_OVERLAP_TCL |
|
1448 return res; |
|
1449 } |
|
1450 |
|
1451 static PyObject * |
|
1452 Tkapp_Record(PyObject *self, PyObject *args) |
|
1453 { |
|
1454 char *script; |
|
1455 PyObject *res = NULL; |
|
1456 int err; |
|
1457 |
|
1458 if (!PyArg_ParseTuple(args, "s", &script)) |
|
1459 return NULL; |
|
1460 |
|
1461 CHECK_TCL_APPARTMENT; |
|
1462 |
|
1463 ENTER_TCL |
|
1464 err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL); |
|
1465 ENTER_OVERLAP |
|
1466 if (err == TCL_ERROR) |
|
1467 res = Tkinter_Error(self); |
|
1468 else |
|
1469 res = PyString_FromString(Tkapp_Result(self)); |
|
1470 LEAVE_OVERLAP_TCL |
|
1471 return res; |
|
1472 } |
|
1473 |
|
1474 static PyObject * |
|
1475 Tkapp_AddErrorInfo(PyObject *self, PyObject *args) |
|
1476 { |
|
1477 char *msg; |
|
1478 |
|
1479 if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg)) |
|
1480 return NULL; |
|
1481 CHECK_TCL_APPARTMENT; |
|
1482 |
|
1483 ENTER_TCL |
|
1484 Tcl_AddErrorInfo(Tkapp_Interp(self), msg); |
|
1485 LEAVE_TCL |
|
1486 |
|
1487 Py_INCREF(Py_None); |
|
1488 return Py_None; |
|
1489 } |
|
1490 |
|
1491 |
|
1492 |
|
1493 /** Tcl Variable **/ |
|
1494 |
|
1495 TCL_DECLARE_MUTEX(var_mutex) |
|
1496 |
|
1497 typedef PyObject* (*EventFunc)(PyObject*, PyObject *args, int flags); |
|
1498 typedef struct VarEvent { |
|
1499 Tcl_Event ev; /* must be first */ |
|
1500 PyObject *self; |
|
1501 PyObject *args; |
|
1502 int flags; |
|
1503 EventFunc func; |
|
1504 PyObject **res; |
|
1505 PyObject **exc_type; |
|
1506 PyObject **exc_val; |
|
1507 Tcl_Condition cond; |
|
1508 } VarEvent; |
|
1509 |
|
1510 static int |
|
1511 varname_converter(PyObject *in, void *_out) |
|
1512 { |
|
1513 char **out = (char**)_out; |
|
1514 if (PyString_Check(in)) { |
|
1515 *out = PyString_AsString(in); |
|
1516 return 1; |
|
1517 } |
|
1518 if (PyTclObject_Check(in)) { |
|
1519 *out = PyTclObject_TclString(in); |
|
1520 return 1; |
|
1521 } |
|
1522 /* XXX: Should give diagnostics. */ |
|
1523 return 0; |
|
1524 } |
|
1525 |
|
1526 static void |
|
1527 var_perform(VarEvent *ev) |
|
1528 { |
|
1529 *(ev->res) = ev->func(ev->self, ev->args, ev->flags); |
|
1530 if (!*(ev->res)) { |
|
1531 PyObject *exc, *val, *tb; |
|
1532 PyErr_Fetch(&exc, &val, &tb); |
|
1533 PyErr_NormalizeException(&exc, &val, &tb); |
|
1534 *(ev->exc_type) = exc; |
|
1535 *(ev->exc_val) = val; |
|
1536 Py_DECREF(tb); |
|
1537 } |
|
1538 |
|
1539 } |
|
1540 |
|
1541 static int |
|
1542 var_proc(VarEvent* ev, int flags) |
|
1543 { |
|
1544 ENTER_PYTHON |
|
1545 var_perform(ev); |
|
1546 Tcl_MutexLock(&var_mutex); |
|
1547 Tcl_ConditionNotify(&ev->cond); |
|
1548 Tcl_MutexUnlock(&var_mutex); |
|
1549 LEAVE_PYTHON |
|
1550 return 1; |
|
1551 } |
|
1552 |
|
1553 static PyObject* |
|
1554 var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags) |
|
1555 { |
|
1556 TkappObject *self = (TkappObject*)selfptr; |
|
1557 #ifdef WITH_THREAD |
|
1558 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { |
|
1559 TkappObject *self = (TkappObject*)selfptr; |
|
1560 VarEvent *ev; |
|
1561 PyObject *res, *exc_type, *exc_val; |
|
1562 |
|
1563 /* The current thread is not the interpreter thread. Marshal |
|
1564 the call to the interpreter thread, then wait for |
|
1565 completion. */ |
|
1566 if (!WaitForMainloop(self)) |
|
1567 return NULL; |
|
1568 |
|
1569 ev = (VarEvent*)ckalloc(sizeof(VarEvent)); |
|
1570 |
|
1571 ev->self = selfptr; |
|
1572 ev->args = args; |
|
1573 ev->flags = flags; |
|
1574 ev->func = func; |
|
1575 ev->res = &res; |
|
1576 ev->exc_type = &exc_type; |
|
1577 ev->exc_val = &exc_val; |
|
1578 ev->cond = NULL; |
|
1579 ev->ev.proc = (Tcl_EventProc*)var_proc; |
|
1580 Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->cond, &var_mutex); |
|
1581 if (!res) { |
|
1582 PyErr_SetObject(exc_type, exc_val); |
|
1583 Py_DECREF(exc_type); |
|
1584 Py_DECREF(exc_val); |
|
1585 return NULL; |
|
1586 } |
|
1587 return res; |
|
1588 } |
|
1589 #endif |
|
1590 /* Tcl is not threaded, or this is the interpreter thread. */ |
|
1591 return func(selfptr, args, flags); |
|
1592 } |
|
1593 |
|
1594 static PyObject * |
|
1595 SetVar(PyObject *self, PyObject *args, int flags) |
|
1596 { |
|
1597 char *name1, *name2; |
|
1598 PyObject *newValue; |
|
1599 PyObject *res = NULL; |
|
1600 Tcl_Obj *newval, *ok; |
|
1601 |
|
1602 if (PyArg_ParseTuple(args, "O&O:setvar", |
|
1603 varname_converter, &name1, &newValue)) { |
|
1604 /* XXX Acquire tcl lock??? */ |
|
1605 newval = AsObj(newValue); |
|
1606 if (newval == NULL) |
|
1607 return NULL; |
|
1608 ENTER_TCL |
|
1609 ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, NULL, |
|
1610 newval, flags); |
|
1611 ENTER_OVERLAP |
|
1612 if (!ok) |
|
1613 Tkinter_Error(self); |
|
1614 else { |
|
1615 res = Py_None; |
|
1616 Py_INCREF(res); |
|
1617 } |
|
1618 LEAVE_OVERLAP_TCL |
|
1619 } |
|
1620 else { |
|
1621 PyErr_Clear(); |
|
1622 if (PyArg_ParseTuple(args, "ssO:setvar", |
|
1623 &name1, &name2, &newValue)) { |
|
1624 /* XXX must hold tcl lock already??? */ |
|
1625 newval = AsObj(newValue); |
|
1626 ENTER_TCL |
|
1627 ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, name2, newval, flags); |
|
1628 ENTER_OVERLAP |
|
1629 if (!ok) |
|
1630 Tkinter_Error(self); |
|
1631 else { |
|
1632 res = Py_None; |
|
1633 Py_INCREF(res); |
|
1634 } |
|
1635 LEAVE_OVERLAP_TCL |
|
1636 } |
|
1637 else { |
|
1638 return NULL; |
|
1639 } |
|
1640 } |
|
1641 return res; |
|
1642 } |
|
1643 |
|
1644 static PyObject * |
|
1645 Tkapp_SetVar(PyObject *self, PyObject *args) |
|
1646 { |
|
1647 return var_invoke(SetVar, self, args, TCL_LEAVE_ERR_MSG); |
|
1648 } |
|
1649 |
|
1650 static PyObject * |
|
1651 Tkapp_GlobalSetVar(PyObject *self, PyObject *args) |
|
1652 { |
|
1653 return var_invoke(SetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); |
|
1654 } |
|
1655 |
|
1656 |
|
1657 |
|
1658 static PyObject * |
|
1659 GetVar(PyObject *self, PyObject *args, int flags) |
|
1660 { |
|
1661 char *name1, *name2=NULL; |
|
1662 PyObject *res = NULL; |
|
1663 Tcl_Obj *tres; |
|
1664 |
|
1665 if (!PyArg_ParseTuple(args, "O&|s:getvar", |
|
1666 varname_converter, &name1, &name2)) |
|
1667 return NULL; |
|
1668 |
|
1669 ENTER_TCL |
|
1670 tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags); |
|
1671 ENTER_OVERLAP |
|
1672 if (tres == NULL) { |
|
1673 PyErr_SetString(Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self))); |
|
1674 } else { |
|
1675 if (((TkappObject*)self)->wantobjects) { |
|
1676 res = FromObj(self, tres); |
|
1677 } |
|
1678 else { |
|
1679 res = PyString_FromString(Tcl_GetString(tres)); |
|
1680 } |
|
1681 } |
|
1682 LEAVE_OVERLAP_TCL |
|
1683 return res; |
|
1684 } |
|
1685 |
|
1686 static PyObject * |
|
1687 Tkapp_GetVar(PyObject *self, PyObject *args) |
|
1688 { |
|
1689 return var_invoke(GetVar, self, args, TCL_LEAVE_ERR_MSG); |
|
1690 } |
|
1691 |
|
1692 static PyObject * |
|
1693 Tkapp_GlobalGetVar(PyObject *self, PyObject *args) |
|
1694 { |
|
1695 return var_invoke(GetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); |
|
1696 } |
|
1697 |
|
1698 |
|
1699 |
|
1700 static PyObject * |
|
1701 UnsetVar(PyObject *self, PyObject *args, int flags) |
|
1702 { |
|
1703 char *name1, *name2=NULL; |
|
1704 int code; |
|
1705 PyObject *res = NULL; |
|
1706 |
|
1707 if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2)) |
|
1708 return NULL; |
|
1709 |
|
1710 ENTER_TCL |
|
1711 code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags); |
|
1712 ENTER_OVERLAP |
|
1713 if (code == TCL_ERROR) |
|
1714 res = Tkinter_Error(self); |
|
1715 else { |
|
1716 Py_INCREF(Py_None); |
|
1717 res = Py_None; |
|
1718 } |
|
1719 LEAVE_OVERLAP_TCL |
|
1720 return res; |
|
1721 } |
|
1722 |
|
1723 static PyObject * |
|
1724 Tkapp_UnsetVar(PyObject *self, PyObject *args) |
|
1725 { |
|
1726 return var_invoke(UnsetVar, self, args, TCL_LEAVE_ERR_MSG); |
|
1727 } |
|
1728 |
|
1729 static PyObject * |
|
1730 Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args) |
|
1731 { |
|
1732 return var_invoke(UnsetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); |
|
1733 } |
|
1734 |
|
1735 |
|
1736 |
|
1737 /** Tcl to Python **/ |
|
1738 |
|
1739 static PyObject * |
|
1740 Tkapp_GetInt(PyObject *self, PyObject *args) |
|
1741 { |
|
1742 char *s; |
|
1743 int v; |
|
1744 |
|
1745 if (PyTuple_Size(args) == 1) { |
|
1746 PyObject* o = PyTuple_GetItem(args, 0); |
|
1747 if (PyInt_Check(o)) { |
|
1748 Py_INCREF(o); |
|
1749 return o; |
|
1750 } |
|
1751 } |
|
1752 if (!PyArg_ParseTuple(args, "s:getint", &s)) |
|
1753 return NULL; |
|
1754 if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR) |
|
1755 return Tkinter_Error(self); |
|
1756 return Py_BuildValue("i", v); |
|
1757 } |
|
1758 |
|
1759 static PyObject * |
|
1760 Tkapp_GetDouble(PyObject *self, PyObject *args) |
|
1761 { |
|
1762 char *s; |
|
1763 double v; |
|
1764 |
|
1765 if (PyTuple_Size(args) == 1) { |
|
1766 PyObject *o = PyTuple_GetItem(args, 0); |
|
1767 if (PyFloat_Check(o)) { |
|
1768 Py_INCREF(o); |
|
1769 return o; |
|
1770 } |
|
1771 } |
|
1772 if (!PyArg_ParseTuple(args, "s:getdouble", &s)) |
|
1773 return NULL; |
|
1774 if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR) |
|
1775 return Tkinter_Error(self); |
|
1776 return Py_BuildValue("d", v); |
|
1777 } |
|
1778 |
|
1779 static PyObject * |
|
1780 Tkapp_GetBoolean(PyObject *self, PyObject *args) |
|
1781 { |
|
1782 char *s; |
|
1783 int v; |
|
1784 |
|
1785 if (PyTuple_Size(args) == 1) { |
|
1786 PyObject *o = PyTuple_GetItem(args, 0); |
|
1787 if (PyInt_Check(o)) { |
|
1788 Py_INCREF(o); |
|
1789 return o; |
|
1790 } |
|
1791 } |
|
1792 if (!PyArg_ParseTuple(args, "s:getboolean", &s)) |
|
1793 return NULL; |
|
1794 if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR) |
|
1795 return Tkinter_Error(self); |
|
1796 return PyBool_FromLong(v); |
|
1797 } |
|
1798 |
|
1799 static PyObject * |
|
1800 Tkapp_ExprString(PyObject *self, PyObject *args) |
|
1801 { |
|
1802 char *s; |
|
1803 PyObject *res = NULL; |
|
1804 int retval; |
|
1805 |
|
1806 if (!PyArg_ParseTuple(args, "s:exprstring", &s)) |
|
1807 return NULL; |
|
1808 |
|
1809 CHECK_TCL_APPARTMENT; |
|
1810 |
|
1811 ENTER_TCL |
|
1812 retval = Tcl_ExprString(Tkapp_Interp(self), s); |
|
1813 ENTER_OVERLAP |
|
1814 if (retval == TCL_ERROR) |
|
1815 res = Tkinter_Error(self); |
|
1816 else |
|
1817 res = Py_BuildValue("s", Tkapp_Result(self)); |
|
1818 LEAVE_OVERLAP_TCL |
|
1819 return res; |
|
1820 } |
|
1821 |
|
1822 static PyObject * |
|
1823 Tkapp_ExprLong(PyObject *self, PyObject *args) |
|
1824 { |
|
1825 char *s; |
|
1826 PyObject *res = NULL; |
|
1827 int retval; |
|
1828 long v; |
|
1829 |
|
1830 if (!PyArg_ParseTuple(args, "s:exprlong", &s)) |
|
1831 return NULL; |
|
1832 |
|
1833 CHECK_TCL_APPARTMENT; |
|
1834 |
|
1835 ENTER_TCL |
|
1836 retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v); |
|
1837 ENTER_OVERLAP |
|
1838 if (retval == TCL_ERROR) |
|
1839 res = Tkinter_Error(self); |
|
1840 else |
|
1841 res = Py_BuildValue("l", v); |
|
1842 LEAVE_OVERLAP_TCL |
|
1843 return res; |
|
1844 } |
|
1845 |
|
1846 static PyObject * |
|
1847 Tkapp_ExprDouble(PyObject *self, PyObject *args) |
|
1848 { |
|
1849 char *s; |
|
1850 PyObject *res = NULL; |
|
1851 double v; |
|
1852 int retval; |
|
1853 |
|
1854 if (!PyArg_ParseTuple(args, "s:exprdouble", &s)) |
|
1855 return NULL; |
|
1856 CHECK_TCL_APPARTMENT; |
|
1857 PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0) |
|
1858 ENTER_TCL |
|
1859 retval = Tcl_ExprDouble(Tkapp_Interp(self), s, &v); |
|
1860 ENTER_OVERLAP |
|
1861 PyFPE_END_PROTECT(retval) |
|
1862 if (retval == TCL_ERROR) |
|
1863 res = Tkinter_Error(self); |
|
1864 else |
|
1865 res = Py_BuildValue("d", v); |
|
1866 LEAVE_OVERLAP_TCL |
|
1867 return res; |
|
1868 } |
|
1869 |
|
1870 static PyObject * |
|
1871 Tkapp_ExprBoolean(PyObject *self, PyObject *args) |
|
1872 { |
|
1873 char *s; |
|
1874 PyObject *res = NULL; |
|
1875 int retval; |
|
1876 int v; |
|
1877 |
|
1878 if (!PyArg_ParseTuple(args, "s:exprboolean", &s)) |
|
1879 return NULL; |
|
1880 CHECK_TCL_APPARTMENT; |
|
1881 ENTER_TCL |
|
1882 retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v); |
|
1883 ENTER_OVERLAP |
|
1884 if (retval == TCL_ERROR) |
|
1885 res = Tkinter_Error(self); |
|
1886 else |
|
1887 res = Py_BuildValue("i", v); |
|
1888 LEAVE_OVERLAP_TCL |
|
1889 return res; |
|
1890 } |
|
1891 |
|
1892 |
|
1893 |
|
1894 static PyObject * |
|
1895 Tkapp_SplitList(PyObject *self, PyObject *args) |
|
1896 { |
|
1897 char *list; |
|
1898 int argc; |
|
1899 char **argv; |
|
1900 PyObject *v; |
|
1901 int i; |
|
1902 |
|
1903 if (PyTuple_Size(args) == 1) { |
|
1904 v = PyTuple_GetItem(args, 0); |
|
1905 if (PyTuple_Check(v)) { |
|
1906 Py_INCREF(v); |
|
1907 return v; |
|
1908 } |
|
1909 } |
|
1910 if (!PyArg_ParseTuple(args, "et:splitlist", "utf-8", &list)) |
|
1911 return NULL; |
|
1912 |
|
1913 if (Tcl_SplitList(Tkapp_Interp(self), list, |
|
1914 &argc, &argv) == TCL_ERROR) { |
|
1915 PyMem_Free(list); |
|
1916 return Tkinter_Error(self); |
|
1917 } |
|
1918 |
|
1919 if (!(v = PyTuple_New(argc))) |
|
1920 goto finally; |
|
1921 |
|
1922 for (i = 0; i < argc; i++) { |
|
1923 PyObject *s = PyString_FromString(argv[i]); |
|
1924 if (!s || PyTuple_SetItem(v, i, s)) { |
|
1925 Py_DECREF(v); |
|
1926 v = NULL; |
|
1927 goto finally; |
|
1928 } |
|
1929 } |
|
1930 |
|
1931 finally: |
|
1932 ckfree(FREECAST argv); |
|
1933 PyMem_Free(list); |
|
1934 return v; |
|
1935 } |
|
1936 |
|
1937 static PyObject * |
|
1938 Tkapp_Split(PyObject *self, PyObject *args) |
|
1939 { |
|
1940 PyObject *v; |
|
1941 char *list; |
|
1942 |
|
1943 if (PyTuple_Size(args) == 1) { |
|
1944 PyObject* o = PyTuple_GetItem(args, 0); |
|
1945 if (PyTuple_Check(o)) { |
|
1946 o = SplitObj(o); |
|
1947 return o; |
|
1948 } |
|
1949 } |
|
1950 if (!PyArg_ParseTuple(args, "et:split", "utf-8", &list)) |
|
1951 return NULL; |
|
1952 v = Split(list); |
|
1953 PyMem_Free(list); |
|
1954 return v; |
|
1955 } |
|
1956 |
|
1957 static PyObject * |
|
1958 Tkapp_Merge(PyObject *self, PyObject *args) |
|
1959 { |
|
1960 char *s = Merge(args); |
|
1961 PyObject *res = NULL; |
|
1962 |
|
1963 if (s) { |
|
1964 res = PyString_FromString(s); |
|
1965 ckfree(s); |
|
1966 } |
|
1967 |
|
1968 return res; |
|
1969 } |
|
1970 |
|
1971 |
|
1972 |
|
1973 /** Tcl Command **/ |
|
1974 |
|
1975 /* Client data struct */ |
|
1976 typedef struct { |
|
1977 PyObject *self; |
|
1978 PyObject *func; |
|
1979 } PythonCmd_ClientData; |
|
1980 |
|
1981 static int |
|
1982 PythonCmd_Error(Tcl_Interp *interp) |
|
1983 { |
|
1984 errorInCmd = 1; |
|
1985 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); |
|
1986 LEAVE_PYTHON |
|
1987 return TCL_ERROR; |
|
1988 } |
|
1989 |
|
1990 /* This is the Tcl command that acts as a wrapper for Python |
|
1991 * function or method. |
|
1992 */ |
|
1993 static int |
|
1994 PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) |
|
1995 { |
|
1996 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData; |
|
1997 PyObject *self, *func, *arg, *res; |
|
1998 int i, rv; |
|
1999 Tcl_Obj *obj_res; |
|
2000 |
|
2001 ENTER_PYTHON |
|
2002 |
|
2003 /* TBD: no error checking here since we know, via the |
|
2004 * Tkapp_CreateCommand() that the client data is a two-tuple |
|
2005 */ |
|
2006 self = data->self; |
|
2007 func = data->func; |
|
2008 |
|
2009 /* Create argument list (argv1, ..., argvN) */ |
|
2010 if (!(arg = PyTuple_New(argc - 1))) |
|
2011 return PythonCmd_Error(interp); |
|
2012 |
|
2013 for (i = 0; i < (argc - 1); i++) { |
|
2014 PyObject *s = PyString_FromString(argv[i + 1]); |
|
2015 if (!s || PyTuple_SetItem(arg, i, s)) { |
|
2016 Py_DECREF(arg); |
|
2017 return PythonCmd_Error(interp); |
|
2018 } |
|
2019 } |
|
2020 res = PyEval_CallObject(func, arg); |
|
2021 Py_DECREF(arg); |
|
2022 |
|
2023 if (res == NULL) |
|
2024 return PythonCmd_Error(interp); |
|
2025 |
|
2026 obj_res = AsObj(res); |
|
2027 if (obj_res == NULL) { |
|
2028 Py_DECREF(res); |
|
2029 return PythonCmd_Error(interp); |
|
2030 } |
|
2031 else { |
|
2032 Tcl_SetObjResult(Tkapp_Interp(self), obj_res); |
|
2033 rv = TCL_OK; |
|
2034 } |
|
2035 |
|
2036 Py_DECREF(res); |
|
2037 |
|
2038 LEAVE_PYTHON |
|
2039 |
|
2040 return rv; |
|
2041 } |
|
2042 |
|
2043 static void |
|
2044 PythonCmdDelete(ClientData clientData) |
|
2045 { |
|
2046 PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData; |
|
2047 |
|
2048 ENTER_PYTHON |
|
2049 Py_XDECREF(data->self); |
|
2050 Py_XDECREF(data->func); |
|
2051 PyMem_DEL(data); |
|
2052 LEAVE_PYTHON |
|
2053 } |
|
2054 |
|
2055 |
|
2056 |
|
2057 |
|
2058 TCL_DECLARE_MUTEX(command_mutex) |
|
2059 |
|
2060 typedef struct CommandEvent{ |
|
2061 Tcl_Event ev; |
|
2062 Tcl_Interp* interp; |
|
2063 char *name; |
|
2064 int create; |
|
2065 int *status; |
|
2066 ClientData *data; |
|
2067 Tcl_Condition done; |
|
2068 } CommandEvent; |
|
2069 |
|
2070 static int |
|
2071 Tkapp_CommandProc(CommandEvent *ev, int flags) |
|
2072 { |
|
2073 if (ev->create) |
|
2074 *ev->status = Tcl_CreateCommand( |
|
2075 ev->interp, ev->name, PythonCmd, |
|
2076 ev->data, PythonCmdDelete) == NULL; |
|
2077 else |
|
2078 *ev->status = Tcl_DeleteCommand(ev->interp, ev->name); |
|
2079 Tcl_MutexLock(&command_mutex); |
|
2080 Tcl_ConditionNotify(&ev->done); |
|
2081 Tcl_MutexUnlock(&command_mutex); |
|
2082 return 1; |
|
2083 } |
|
2084 |
|
2085 static PyObject * |
|
2086 Tkapp_CreateCommand(PyObject *selfptr, PyObject *args) |
|
2087 { |
|
2088 TkappObject *self = (TkappObject*)selfptr; |
|
2089 PythonCmd_ClientData *data; |
|
2090 char *cmdName; |
|
2091 PyObject *func; |
|
2092 int err; |
|
2093 |
|
2094 if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func)) |
|
2095 return NULL; |
|
2096 if (!PyCallable_Check(func)) { |
|
2097 PyErr_SetString(PyExc_TypeError, "command not callable"); |
|
2098 return NULL; |
|
2099 } |
|
2100 |
|
2101 #ifdef WITH_THREAD |
|
2102 if (self->threaded && self->thread_id != Tcl_GetCurrentThread() && |
|
2103 !WaitForMainloop(self)) |
|
2104 return NULL; |
|
2105 #endif |
|
2106 |
|
2107 data = PyMem_NEW(PythonCmd_ClientData, 1); |
|
2108 if (!data) |
|
2109 return PyErr_NoMemory(); |
|
2110 Py_INCREF(self); |
|
2111 Py_INCREF(func); |
|
2112 data->self = selfptr; |
|
2113 data->func = func; |
|
2114 |
|
2115 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { |
|
2116 CommandEvent *ev = (CommandEvent*)ckalloc(sizeof(CommandEvent)); |
|
2117 ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc; |
|
2118 ev->interp = self->interp; |
|
2119 ev->create = 1; |
|
2120 ev->name = cmdName; |
|
2121 ev->data = (ClientData)data; |
|
2122 ev->status = &err; |
|
2123 ev->done = NULL; |
|
2124 Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->done, &command_mutex); |
|
2125 } |
|
2126 else { |
|
2127 ENTER_TCL |
|
2128 err = Tcl_CreateCommand( |
|
2129 Tkapp_Interp(self), cmdName, PythonCmd, |
|
2130 (ClientData)data, PythonCmdDelete) == NULL; |
|
2131 LEAVE_TCL |
|
2132 } |
|
2133 if (err) { |
|
2134 PyErr_SetString(Tkinter_TclError, "can't create Tcl command"); |
|
2135 PyMem_DEL(data); |
|
2136 return NULL; |
|
2137 } |
|
2138 |
|
2139 Py_INCREF(Py_None); |
|
2140 return Py_None; |
|
2141 } |
|
2142 |
|
2143 |
|
2144 |
|
2145 static PyObject * |
|
2146 Tkapp_DeleteCommand(PyObject *selfptr, PyObject *args) |
|
2147 { |
|
2148 TkappObject *self = (TkappObject*)selfptr; |
|
2149 char *cmdName; |
|
2150 int err; |
|
2151 |
|
2152 if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName)) |
|
2153 return NULL; |
|
2154 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { |
|
2155 CommandEvent *ev; |
|
2156 ev = (CommandEvent*)ckalloc(sizeof(CommandEvent)); |
|
2157 ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc; |
|
2158 ev->interp = self->interp; |
|
2159 ev->create = 0; |
|
2160 ev->name = cmdName; |
|
2161 ev->status = &err; |
|
2162 ev->done = NULL; |
|
2163 Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->done, |
|
2164 &command_mutex); |
|
2165 } |
|
2166 else { |
|
2167 ENTER_TCL |
|
2168 err = Tcl_DeleteCommand(self->interp, cmdName); |
|
2169 LEAVE_TCL |
|
2170 } |
|
2171 if (err == -1) { |
|
2172 PyErr_SetString(Tkinter_TclError, "can't delete Tcl command"); |
|
2173 return NULL; |
|
2174 } |
|
2175 Py_INCREF(Py_None); |
|
2176 return Py_None; |
|
2177 } |
|
2178 |
|
2179 |
|
2180 |
|
2181 #ifdef HAVE_CREATEFILEHANDLER |
|
2182 /** File Handler **/ |
|
2183 |
|
2184 typedef struct _fhcdata { |
|
2185 PyObject *func; |
|
2186 PyObject *file; |
|
2187 int id; |
|
2188 struct _fhcdata *next; |
|
2189 } FileHandler_ClientData; |
|
2190 |
|
2191 static FileHandler_ClientData *HeadFHCD; |
|
2192 |
|
2193 static FileHandler_ClientData * |
|
2194 NewFHCD(PyObject *func, PyObject *file, int id) |
|
2195 { |
|
2196 FileHandler_ClientData *p; |
|
2197 p = PyMem_NEW(FileHandler_ClientData, 1); |
|
2198 if (p != NULL) { |
|
2199 Py_XINCREF(func); |
|
2200 Py_XINCREF(file); |
|
2201 p->func = func; |
|
2202 p->file = file; |
|
2203 p->id = id; |
|
2204 p->next = HeadFHCD; |
|
2205 HeadFHCD = p; |
|
2206 } |
|
2207 return p; |
|
2208 } |
|
2209 |
|
2210 static void |
|
2211 DeleteFHCD(int id) |
|
2212 { |
|
2213 FileHandler_ClientData *p, **pp; |
|
2214 |
|
2215 pp = &HeadFHCD; |
|
2216 while ((p = *pp) != NULL) { |
|
2217 if (p->id == id) { |
|
2218 *pp = p->next; |
|
2219 Py_XDECREF(p->func); |
|
2220 Py_XDECREF(p->file); |
|
2221 PyMem_DEL(p); |
|
2222 } |
|
2223 else |
|
2224 pp = &p->next; |
|
2225 } |
|
2226 } |
|
2227 |
|
2228 static void |
|
2229 FileHandler(ClientData clientData, int mask) |
|
2230 { |
|
2231 FileHandler_ClientData *data = (FileHandler_ClientData *)clientData; |
|
2232 PyObject *func, *file, *arg, *res; |
|
2233 |
|
2234 ENTER_PYTHON |
|
2235 func = data->func; |
|
2236 file = data->file; |
|
2237 |
|
2238 arg = Py_BuildValue("(Oi)", file, (long) mask); |
|
2239 res = PyEval_CallObject(func, arg); |
|
2240 Py_DECREF(arg); |
|
2241 |
|
2242 if (res == NULL) { |
|
2243 errorInCmd = 1; |
|
2244 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); |
|
2245 } |
|
2246 Py_XDECREF(res); |
|
2247 LEAVE_PYTHON |
|
2248 } |
|
2249 |
|
2250 static PyObject * |
|
2251 Tkapp_CreateFileHandler(PyObject *self, PyObject *args) |
|
2252 /* args is (file, mask, func) */ |
|
2253 { |
|
2254 FileHandler_ClientData *data; |
|
2255 PyObject *file, *func; |
|
2256 int mask, tfile; |
|
2257 |
|
2258 if (!PyArg_ParseTuple(args, "OiO:createfilehandler", |
|
2259 &file, &mask, &func)) |
|
2260 return NULL; |
|
2261 |
|
2262 #ifdef WITH_THREAD |
|
2263 if (!self && !tcl_lock) { |
|
2264 /* We don't have the Tcl lock since Tcl is threaded. */ |
|
2265 PyErr_SetString(PyExc_RuntimeError, |
|
2266 "_tkinter.createfilehandler not supported " |
|
2267 "for threaded Tcl"); |
|
2268 return NULL; |
|
2269 } |
|
2270 #endif |
|
2271 |
|
2272 if (self) { |
|
2273 CHECK_TCL_APPARTMENT; |
|
2274 } |
|
2275 |
|
2276 tfile = PyObject_AsFileDescriptor(file); |
|
2277 if (tfile < 0) |
|
2278 return NULL; |
|
2279 if (!PyCallable_Check(func)) { |
|
2280 PyErr_SetString(PyExc_TypeError, "bad argument list"); |
|
2281 return NULL; |
|
2282 } |
|
2283 |
|
2284 data = NewFHCD(func, file, tfile); |
|
2285 if (data == NULL) |
|
2286 return NULL; |
|
2287 |
|
2288 /* Ought to check for null Tcl_File object... */ |
|
2289 ENTER_TCL |
|
2290 Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data); |
|
2291 LEAVE_TCL |
|
2292 Py_INCREF(Py_None); |
|
2293 return Py_None; |
|
2294 } |
|
2295 |
|
2296 static PyObject * |
|
2297 Tkapp_DeleteFileHandler(PyObject *self, PyObject *args) |
|
2298 { |
|
2299 PyObject *file; |
|
2300 int tfile; |
|
2301 |
|
2302 if (!PyArg_ParseTuple(args, "O:deletefilehandler", &file)) |
|
2303 return NULL; |
|
2304 |
|
2305 #ifdef WITH_THREAD |
|
2306 if (!self && !tcl_lock) { |
|
2307 /* We don't have the Tcl lock since Tcl is threaded. */ |
|
2308 PyErr_SetString(PyExc_RuntimeError, |
|
2309 "_tkinter.deletefilehandler not supported " |
|
2310 "for threaded Tcl"); |
|
2311 return NULL; |
|
2312 } |
|
2313 #endif |
|
2314 |
|
2315 if (self) { |
|
2316 CHECK_TCL_APPARTMENT; |
|
2317 } |
|
2318 |
|
2319 tfile = PyObject_AsFileDescriptor(file); |
|
2320 if (tfile < 0) |
|
2321 return NULL; |
|
2322 |
|
2323 DeleteFHCD(tfile); |
|
2324 |
|
2325 /* Ought to check for null Tcl_File object... */ |
|
2326 ENTER_TCL |
|
2327 Tcl_DeleteFileHandler(tfile); |
|
2328 LEAVE_TCL |
|
2329 Py_INCREF(Py_None); |
|
2330 return Py_None; |
|
2331 } |
|
2332 #endif /* HAVE_CREATEFILEHANDLER */ |
|
2333 |
|
2334 |
|
2335 /**** Tktt Object (timer token) ****/ |
|
2336 |
|
2337 static PyTypeObject Tktt_Type; |
|
2338 |
|
2339 typedef struct { |
|
2340 PyObject_HEAD |
|
2341 Tcl_TimerToken token; |
|
2342 PyObject *func; |
|
2343 } TkttObject; |
|
2344 |
|
2345 static PyObject * |
|
2346 Tktt_DeleteTimerHandler(PyObject *self, PyObject *args) |
|
2347 { |
|
2348 TkttObject *v = (TkttObject *)self; |
|
2349 PyObject *func = v->func; |
|
2350 |
|
2351 if (!PyArg_ParseTuple(args, ":deletetimerhandler")) |
|
2352 return NULL; |
|
2353 if (v->token != NULL) { |
|
2354 Tcl_DeleteTimerHandler(v->token); |
|
2355 v->token = NULL; |
|
2356 } |
|
2357 if (func != NULL) { |
|
2358 v->func = NULL; |
|
2359 Py_DECREF(func); |
|
2360 Py_DECREF(v); /* See Tktt_New() */ |
|
2361 } |
|
2362 Py_INCREF(Py_None); |
|
2363 return Py_None; |
|
2364 } |
|
2365 |
|
2366 static PyMethodDef Tktt_methods[] = |
|
2367 { |
|
2368 {"deletetimerhandler", Tktt_DeleteTimerHandler, METH_VARARGS}, |
|
2369 {NULL, NULL} |
|
2370 }; |
|
2371 |
|
2372 static TkttObject * |
|
2373 Tktt_New(PyObject *func) |
|
2374 { |
|
2375 TkttObject *v; |
|
2376 |
|
2377 v = PyObject_New(TkttObject, &Tktt_Type); |
|
2378 if (v == NULL) |
|
2379 return NULL; |
|
2380 |
|
2381 Py_INCREF(func); |
|
2382 v->token = NULL; |
|
2383 v->func = func; |
|
2384 |
|
2385 /* Extra reference, deleted when called or when handler is deleted */ |
|
2386 Py_INCREF(v); |
|
2387 return v; |
|
2388 } |
|
2389 |
|
2390 static void |
|
2391 Tktt_Dealloc(PyObject *self) |
|
2392 { |
|
2393 TkttObject *v = (TkttObject *)self; |
|
2394 PyObject *func = v->func; |
|
2395 |
|
2396 Py_XDECREF(func); |
|
2397 |
|
2398 PyObject_Del(self); |
|
2399 } |
|
2400 |
|
2401 static PyObject * |
|
2402 Tktt_Repr(PyObject *self) |
|
2403 { |
|
2404 TkttObject *v = (TkttObject *)self; |
|
2405 char buf[100]; |
|
2406 |
|
2407 PyOS_snprintf(buf, sizeof(buf), "<tktimertoken at %p%s>", v, |
|
2408 v->func == NULL ? ", handler deleted" : ""); |
|
2409 return PyString_FromString(buf); |
|
2410 } |
|
2411 |
|
2412 static PyObject * |
|
2413 Tktt_GetAttr(PyObject *self, char *name) |
|
2414 { |
|
2415 return Py_FindMethod(Tktt_methods, self, name); |
|
2416 } |
|
2417 |
|
2418 static PyTypeObject Tktt_Type = |
|
2419 { |
|
2420 PyVarObject_HEAD_INIT(NULL, 0) |
|
2421 "tktimertoken", /*tp_name */ |
|
2422 sizeof(TkttObject), /*tp_basicsize */ |
|
2423 0, /*tp_itemsize */ |
|
2424 Tktt_Dealloc, /*tp_dealloc */ |
|
2425 0, /*tp_print */ |
|
2426 Tktt_GetAttr, /*tp_getattr */ |
|
2427 0, /*tp_setattr */ |
|
2428 0, /*tp_compare */ |
|
2429 Tktt_Repr, /*tp_repr */ |
|
2430 0, /*tp_as_number */ |
|
2431 0, /*tp_as_sequence */ |
|
2432 0, /*tp_as_mapping */ |
|
2433 0, /*tp_hash */ |
|
2434 }; |
|
2435 |
|
2436 |
|
2437 |
|
2438 /** Timer Handler **/ |
|
2439 |
|
2440 static void |
|
2441 TimerHandler(ClientData clientData) |
|
2442 { |
|
2443 TkttObject *v = (TkttObject *)clientData; |
|
2444 PyObject *func = v->func; |
|
2445 PyObject *res; |
|
2446 |
|
2447 if (func == NULL) |
|
2448 return; |
|
2449 |
|
2450 v->func = NULL; |
|
2451 |
|
2452 ENTER_PYTHON |
|
2453 |
|
2454 res = PyEval_CallObject(func, NULL); |
|
2455 Py_DECREF(func); |
|
2456 Py_DECREF(v); /* See Tktt_New() */ |
|
2457 |
|
2458 if (res == NULL) { |
|
2459 errorInCmd = 1; |
|
2460 PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); |
|
2461 } |
|
2462 else |
|
2463 Py_DECREF(res); |
|
2464 |
|
2465 LEAVE_PYTHON |
|
2466 } |
|
2467 |
|
2468 static PyObject * |
|
2469 Tkapp_CreateTimerHandler(PyObject *self, PyObject *args) |
|
2470 { |
|
2471 int milliseconds; |
|
2472 PyObject *func; |
|
2473 TkttObject *v; |
|
2474 |
|
2475 if (!PyArg_ParseTuple(args, "iO:createtimerhandler", |
|
2476 &milliseconds, &func)) |
|
2477 return NULL; |
|
2478 if (!PyCallable_Check(func)) { |
|
2479 PyErr_SetString(PyExc_TypeError, "bad argument list"); |
|
2480 return NULL; |
|
2481 } |
|
2482 |
|
2483 #ifdef WITH_THREAD |
|
2484 if (!self && !tcl_lock) { |
|
2485 /* We don't have the Tcl lock since Tcl is threaded. */ |
|
2486 PyErr_SetString(PyExc_RuntimeError, |
|
2487 "_tkinter.createtimerhandler not supported " |
|
2488 "for threaded Tcl"); |
|
2489 return NULL; |
|
2490 } |
|
2491 #endif |
|
2492 |
|
2493 if (self) { |
|
2494 CHECK_TCL_APPARTMENT; |
|
2495 } |
|
2496 |
|
2497 v = Tktt_New(func); |
|
2498 if (v) { |
|
2499 v->token = Tcl_CreateTimerHandler(milliseconds, TimerHandler, |
|
2500 (ClientData)v); |
|
2501 } |
|
2502 |
|
2503 return (PyObject *) v; |
|
2504 } |
|
2505 |
|
2506 |
|
2507 /** Event Loop **/ |
|
2508 |
|
2509 static PyObject * |
|
2510 Tkapp_MainLoop(PyObject *selfptr, PyObject *args) |
|
2511 { |
|
2512 int threshold = 0; |
|
2513 TkappObject *self = (TkappObject*)selfptr; |
|
2514 #ifdef WITH_THREAD |
|
2515 PyThreadState *tstate = PyThreadState_Get(); |
|
2516 #endif |
|
2517 |
|
2518 if (!PyArg_ParseTuple(args, "|i:mainloop", &threshold)) |
|
2519 return NULL; |
|
2520 |
|
2521 #ifdef WITH_THREAD |
|
2522 if (!self && !tcl_lock) { |
|
2523 /* We don't have the Tcl lock since Tcl is threaded. */ |
|
2524 PyErr_SetString(PyExc_RuntimeError, |
|
2525 "_tkinter.mainloop not supported " |
|
2526 "for threaded Tcl"); |
|
2527 return NULL; |
|
2528 } |
|
2529 #endif |
|
2530 |
|
2531 if (self) { |
|
2532 CHECK_TCL_APPARTMENT; |
|
2533 self->dispatching = 1; |
|
2534 } |
|
2535 |
|
2536 quitMainLoop = 0; |
|
2537 while (Tk_GetNumMainWindows() > threshold && |
|
2538 !quitMainLoop && |
|
2539 !errorInCmd) |
|
2540 { |
|
2541 int result; |
|
2542 |
|
2543 #ifdef WITH_THREAD |
|
2544 if (self && self->threaded) { |
|
2545 /* Allow other Python threads to run. */ |
|
2546 ENTER_TCL |
|
2547 result = Tcl_DoOneEvent(0); |
|
2548 LEAVE_TCL |
|
2549 } |
|
2550 else { |
|
2551 Py_BEGIN_ALLOW_THREADS |
|
2552 if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); |
|
2553 tcl_tstate = tstate; |
|
2554 result = Tcl_DoOneEvent(TCL_DONT_WAIT); |
|
2555 tcl_tstate = NULL; |
|
2556 if(tcl_lock)PyThread_release_lock(tcl_lock); |
|
2557 if (result == 0) |
|
2558 Sleep(Tkinter_busywaitinterval); |
|
2559 Py_END_ALLOW_THREADS |
|
2560 } |
|
2561 #else |
|
2562 result = Tcl_DoOneEvent(0); |
|
2563 #endif |
|
2564 |
|
2565 if (PyErr_CheckSignals() != 0) { |
|
2566 if (self) |
|
2567 self->dispatching = 0; |
|
2568 return NULL; |
|
2569 } |
|
2570 if (result < 0) |
|
2571 break; |
|
2572 } |
|
2573 if (self) |
|
2574 self->dispatching = 0; |
|
2575 quitMainLoop = 0; |
|
2576 |
|
2577 if (errorInCmd) { |
|
2578 errorInCmd = 0; |
|
2579 PyErr_Restore(excInCmd, valInCmd, trbInCmd); |
|
2580 excInCmd = valInCmd = trbInCmd = NULL; |
|
2581 return NULL; |
|
2582 } |
|
2583 Py_INCREF(Py_None); |
|
2584 return Py_None; |
|
2585 } |
|
2586 |
|
2587 static PyObject * |
|
2588 Tkapp_DoOneEvent(PyObject *self, PyObject *args) |
|
2589 { |
|
2590 int flags = 0; |
|
2591 int rv; |
|
2592 |
|
2593 if (!PyArg_ParseTuple(args, "|i:dooneevent", &flags)) |
|
2594 return NULL; |
|
2595 |
|
2596 ENTER_TCL |
|
2597 rv = Tcl_DoOneEvent(flags); |
|
2598 LEAVE_TCL |
|
2599 return Py_BuildValue("i", rv); |
|
2600 } |
|
2601 |
|
2602 static PyObject * |
|
2603 Tkapp_Quit(PyObject *self, PyObject *args) |
|
2604 { |
|
2605 |
|
2606 if (!PyArg_ParseTuple(args, ":quit")) |
|
2607 return NULL; |
|
2608 |
|
2609 quitMainLoop = 1; |
|
2610 Py_INCREF(Py_None); |
|
2611 return Py_None; |
|
2612 } |
|
2613 |
|
2614 static PyObject * |
|
2615 Tkapp_InterpAddr(PyObject *self, PyObject *args) |
|
2616 { |
|
2617 |
|
2618 if (!PyArg_ParseTuple(args, ":interpaddr")) |
|
2619 return NULL; |
|
2620 |
|
2621 return PyInt_FromLong((long)Tkapp_Interp(self)); |
|
2622 } |
|
2623 |
|
2624 static PyObject * |
|
2625 Tkapp_TkInit(PyObject *self, PyObject *args) |
|
2626 { |
|
2627 static int has_failed; |
|
2628 Tcl_Interp *interp = Tkapp_Interp(self); |
|
2629 Tk_Window main_window; |
|
2630 const char * _tk_exists = NULL; |
|
2631 int err; |
|
2632 main_window = Tk_MainWindow(interp); |
|
2633 |
|
2634 /* In all current versions of Tk (including 8.4.13), Tk_Init |
|
2635 deadlocks on the second call when the first call failed. |
|
2636 To avoid the deadlock, we just refuse the second call through |
|
2637 a static variable. */ |
|
2638 if (has_failed) { |
|
2639 PyErr_SetString(Tkinter_TclError, |
|
2640 "Calling Tk_Init again after a previous call failed might deadlock"); |
|
2641 return NULL; |
|
2642 } |
|
2643 |
|
2644 /* We want to guard against calling Tk_Init() multiple times */ |
|
2645 CHECK_TCL_APPARTMENT; |
|
2646 ENTER_TCL |
|
2647 err = Tcl_Eval(Tkapp_Interp(self), "info exists tk_version"); |
|
2648 ENTER_OVERLAP |
|
2649 if (err == TCL_ERROR) { |
|
2650 /* This sets an exception, but we cannot return right |
|
2651 away because we need to exit the overlap first. */ |
|
2652 Tkinter_Error(self); |
|
2653 } else { |
|
2654 _tk_exists = Tkapp_Result(self); |
|
2655 } |
|
2656 LEAVE_OVERLAP_TCL |
|
2657 if (err == TCL_ERROR) { |
|
2658 return NULL; |
|
2659 } |
|
2660 if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) { |
|
2661 if (Tk_Init(interp) == TCL_ERROR) { |
|
2662 PyErr_SetString(Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self))); |
|
2663 has_failed = 1; |
|
2664 return NULL; |
|
2665 } |
|
2666 } |
|
2667 Py_INCREF(Py_None); |
|
2668 return Py_None; |
|
2669 } |
|
2670 |
|
2671 static PyObject * |
|
2672 Tkapp_WantObjects(PyObject *self, PyObject *args) |
|
2673 { |
|
2674 |
|
2675 int wantobjects = -1; |
|
2676 if (!PyArg_ParseTuple(args, "|i:wantobjects", &wantobjects)) |
|
2677 return NULL; |
|
2678 if (wantobjects == -1) |
|
2679 return PyBool_FromLong(((TkappObject*)self)->wantobjects); |
|
2680 ((TkappObject*)self)->wantobjects = wantobjects; |
|
2681 |
|
2682 Py_INCREF(Py_None); |
|
2683 return Py_None; |
|
2684 } |
|
2685 |
|
2686 static PyObject * |
|
2687 Tkapp_WillDispatch(PyObject *self, PyObject *args) |
|
2688 { |
|
2689 |
|
2690 ((TkappObject*)self)->dispatching = 1; |
|
2691 |
|
2692 Py_INCREF(Py_None); |
|
2693 return Py_None; |
|
2694 } |
|
2695 |
|
2696 |
|
2697 /**** Tkapp Method List ****/ |
|
2698 |
|
2699 static PyMethodDef Tkapp_methods[] = |
|
2700 { |
|
2701 {"willdispatch", Tkapp_WillDispatch, METH_NOARGS}, |
|
2702 {"wantobjects", Tkapp_WantObjects, METH_VARARGS}, |
|
2703 {"call", Tkapp_Call, METH_VARARGS}, |
|
2704 {"globalcall", Tkapp_GlobalCall, METH_VARARGS}, |
|
2705 {"eval", Tkapp_Eval, METH_VARARGS}, |
|
2706 {"globaleval", Tkapp_GlobalEval, METH_VARARGS}, |
|
2707 {"evalfile", Tkapp_EvalFile, METH_VARARGS}, |
|
2708 {"record", Tkapp_Record, METH_VARARGS}, |
|
2709 {"adderrorinfo", Tkapp_AddErrorInfo, METH_VARARGS}, |
|
2710 {"setvar", Tkapp_SetVar, METH_VARARGS}, |
|
2711 {"globalsetvar", Tkapp_GlobalSetVar, METH_VARARGS}, |
|
2712 {"getvar", Tkapp_GetVar, METH_VARARGS}, |
|
2713 {"globalgetvar", Tkapp_GlobalGetVar, METH_VARARGS}, |
|
2714 {"unsetvar", Tkapp_UnsetVar, METH_VARARGS}, |
|
2715 {"globalunsetvar", Tkapp_GlobalUnsetVar, METH_VARARGS}, |
|
2716 {"getint", Tkapp_GetInt, METH_VARARGS}, |
|
2717 {"getdouble", Tkapp_GetDouble, METH_VARARGS}, |
|
2718 {"getboolean", Tkapp_GetBoolean, METH_VARARGS}, |
|
2719 {"exprstring", Tkapp_ExprString, METH_VARARGS}, |
|
2720 {"exprlong", Tkapp_ExprLong, METH_VARARGS}, |
|
2721 {"exprdouble", Tkapp_ExprDouble, METH_VARARGS}, |
|
2722 {"exprboolean", Tkapp_ExprBoolean, METH_VARARGS}, |
|
2723 {"splitlist", Tkapp_SplitList, METH_VARARGS}, |
|
2724 {"split", Tkapp_Split, METH_VARARGS}, |
|
2725 {"merge", Tkapp_Merge, METH_VARARGS}, |
|
2726 {"createcommand", Tkapp_CreateCommand, METH_VARARGS}, |
|
2727 {"deletecommand", Tkapp_DeleteCommand, METH_VARARGS}, |
|
2728 #ifdef HAVE_CREATEFILEHANDLER |
|
2729 {"createfilehandler", Tkapp_CreateFileHandler, METH_VARARGS}, |
|
2730 {"deletefilehandler", Tkapp_DeleteFileHandler, METH_VARARGS}, |
|
2731 #endif |
|
2732 {"createtimerhandler", Tkapp_CreateTimerHandler, METH_VARARGS}, |
|
2733 {"mainloop", Tkapp_MainLoop, METH_VARARGS}, |
|
2734 {"dooneevent", Tkapp_DoOneEvent, METH_VARARGS}, |
|
2735 {"quit", Tkapp_Quit, METH_VARARGS}, |
|
2736 {"interpaddr", Tkapp_InterpAddr, METH_VARARGS}, |
|
2737 {"loadtk", Tkapp_TkInit, METH_NOARGS}, |
|
2738 {NULL, NULL} |
|
2739 }; |
|
2740 |
|
2741 |
|
2742 |
|
2743 /**** Tkapp Type Methods ****/ |
|
2744 |
|
2745 static void |
|
2746 Tkapp_Dealloc(PyObject *self) |
|
2747 { |
|
2748 /*CHECK_TCL_APPARTMENT;*/ |
|
2749 ENTER_TCL |
|
2750 Tcl_DeleteInterp(Tkapp_Interp(self)); |
|
2751 LEAVE_TCL |
|
2752 PyObject_Del(self); |
|
2753 DisableEventHook(); |
|
2754 } |
|
2755 |
|
2756 static PyObject * |
|
2757 Tkapp_GetAttr(PyObject *self, char *name) |
|
2758 { |
|
2759 return Py_FindMethod(Tkapp_methods, self, name); |
|
2760 } |
|
2761 |
|
2762 static PyTypeObject Tkapp_Type = |
|
2763 { |
|
2764 PyVarObject_HEAD_INIT(NULL, 0) |
|
2765 "tkapp", /*tp_name */ |
|
2766 sizeof(TkappObject), /*tp_basicsize */ |
|
2767 0, /*tp_itemsize */ |
|
2768 Tkapp_Dealloc, /*tp_dealloc */ |
|
2769 0, /*tp_print */ |
|
2770 Tkapp_GetAttr, /*tp_getattr */ |
|
2771 0, /*tp_setattr */ |
|
2772 0, /*tp_compare */ |
|
2773 0, /*tp_repr */ |
|
2774 0, /*tp_as_number */ |
|
2775 0, /*tp_as_sequence */ |
|
2776 0, /*tp_as_mapping */ |
|
2777 0, /*tp_hash */ |
|
2778 }; |
|
2779 |
|
2780 |
|
2781 |
|
2782 /**** Tkinter Module ****/ |
|
2783 |
|
2784 typedef struct { |
|
2785 PyObject* tuple; |
|
2786 int size; /* current size */ |
|
2787 int maxsize; /* allocated size */ |
|
2788 } FlattenContext; |
|
2789 |
|
2790 static int |
|
2791 _bump(FlattenContext* context, int size) |
|
2792 { |
|
2793 /* expand tuple to hold (at least) size new items. |
|
2794 return true if successful, false if an exception was raised */ |
|
2795 |
|
2796 int maxsize = context->maxsize * 2; |
|
2797 |
|
2798 if (maxsize < context->size + size) |
|
2799 maxsize = context->size + size; |
|
2800 |
|
2801 context->maxsize = maxsize; |
|
2802 |
|
2803 return _PyTuple_Resize(&context->tuple, maxsize) >= 0; |
|
2804 } |
|
2805 |
|
2806 static int |
|
2807 _flatten1(FlattenContext* context, PyObject* item, int depth) |
|
2808 { |
|
2809 /* add tuple or list to argument tuple (recursively) */ |
|
2810 |
|
2811 int i, size; |
|
2812 |
|
2813 if (depth > 1000) { |
|
2814 PyErr_SetString(PyExc_ValueError, |
|
2815 "nesting too deep in _flatten"); |
|
2816 return 0; |
|
2817 } else if (PyList_Check(item)) { |
|
2818 size = PyList_GET_SIZE(item); |
|
2819 /* preallocate (assume no nesting) */ |
|
2820 if (context->size + size > context->maxsize && |
|
2821 !_bump(context, size)) |
|
2822 return 0; |
|
2823 /* copy items to output tuple */ |
|
2824 for (i = 0; i < size; i++) { |
|
2825 PyObject *o = PyList_GET_ITEM(item, i); |
|
2826 if (PyList_Check(o) || PyTuple_Check(o)) { |
|
2827 if (!_flatten1(context, o, depth + 1)) |
|
2828 return 0; |
|
2829 } else if (o != Py_None) { |
|
2830 if (context->size + 1 > context->maxsize && |
|
2831 !_bump(context, 1)) |
|
2832 return 0; |
|
2833 Py_INCREF(o); |
|
2834 PyTuple_SET_ITEM(context->tuple, |
|
2835 context->size++, o); |
|
2836 } |
|
2837 } |
|
2838 } else if (PyTuple_Check(item)) { |
|
2839 /* same, for tuples */ |
|
2840 size = PyTuple_GET_SIZE(item); |
|
2841 if (context->size + size > context->maxsize && |
|
2842 !_bump(context, size)) |
|
2843 return 0; |
|
2844 for (i = 0; i < size; i++) { |
|
2845 PyObject *o = PyTuple_GET_ITEM(item, i); |
|
2846 if (PyList_Check(o) || PyTuple_Check(o)) { |
|
2847 if (!_flatten1(context, o, depth + 1)) |
|
2848 return 0; |
|
2849 } else if (o != Py_None) { |
|
2850 if (context->size + 1 > context->maxsize && |
|
2851 !_bump(context, 1)) |
|
2852 return 0; |
|
2853 Py_INCREF(o); |
|
2854 PyTuple_SET_ITEM(context->tuple, |
|
2855 context->size++, o); |
|
2856 } |
|
2857 } |
|
2858 } else { |
|
2859 PyErr_SetString(PyExc_TypeError, "argument must be sequence"); |
|
2860 return 0; |
|
2861 } |
|
2862 return 1; |
|
2863 } |
|
2864 |
|
2865 static PyObject * |
|
2866 Tkinter_Flatten(PyObject* self, PyObject* args) |
|
2867 { |
|
2868 FlattenContext context; |
|
2869 PyObject* item; |
|
2870 |
|
2871 if (!PyArg_ParseTuple(args, "O:_flatten", &item)) |
|
2872 return NULL; |
|
2873 |
|
2874 context.maxsize = PySequence_Size(item); |
|
2875 if (context.maxsize <= 0) |
|
2876 return PyTuple_New(0); |
|
2877 |
|
2878 context.tuple = PyTuple_New(context.maxsize); |
|
2879 if (!context.tuple) |
|
2880 return NULL; |
|
2881 |
|
2882 context.size = 0; |
|
2883 |
|
2884 if (!_flatten1(&context, item,0)) |
|
2885 return NULL; |
|
2886 |
|
2887 if (_PyTuple_Resize(&context.tuple, context.size)) |
|
2888 return NULL; |
|
2889 |
|
2890 return context.tuple; |
|
2891 } |
|
2892 |
|
2893 static PyObject * |
|
2894 Tkinter_Create(PyObject *self, PyObject *args) |
|
2895 { |
|
2896 char *screenName = NULL; |
|
2897 char *baseName = NULL; |
|
2898 char *className = NULL; |
|
2899 int interactive = 0; |
|
2900 int wantobjects = 0; |
|
2901 int wantTk = 1; /* If false, then Tk_Init() doesn't get called */ |
|
2902 int sync = 0; /* pass -sync to wish */ |
|
2903 char *use = NULL; /* pass -use to wish */ |
|
2904 |
|
2905 baseName = strrchr(Py_GetProgramName(), '/'); |
|
2906 if (baseName != NULL) |
|
2907 baseName++; |
|
2908 else |
|
2909 baseName = Py_GetProgramName(); |
|
2910 className = "Tk"; |
|
2911 |
|
2912 if (!PyArg_ParseTuple(args, "|zssiiiiz:create", |
|
2913 &screenName, &baseName, &className, |
|
2914 &interactive, &wantobjects, &wantTk, |
|
2915 &sync, &use)) |
|
2916 return NULL; |
|
2917 |
|
2918 return (PyObject *) Tkapp_New(screenName, baseName, className, |
|
2919 interactive, wantobjects, wantTk, |
|
2920 sync, use); |
|
2921 } |
|
2922 |
|
2923 static PyObject * |
|
2924 Tkinter_setbusywaitinterval(PyObject *self, PyObject *args) |
|
2925 { |
|
2926 int new_val; |
|
2927 if (!PyArg_ParseTuple(args, "i:setbusywaitinterval", &new_val)) |
|
2928 return NULL; |
|
2929 if (new_val < 0) { |
|
2930 PyErr_SetString(PyExc_ValueError, |
|
2931 "busywaitinterval must be >= 0"); |
|
2932 return NULL; |
|
2933 } |
|
2934 Tkinter_busywaitinterval = new_val; |
|
2935 Py_INCREF(Py_None); |
|
2936 return Py_None; |
|
2937 } |
|
2938 |
|
2939 static char setbusywaitinterval_doc[] = |
|
2940 "setbusywaitinterval(n) -> None\n\ |
|
2941 \n\ |
|
2942 Set the busy-wait interval in milliseconds between successive\n\ |
|
2943 calls to Tcl_DoOneEvent in a threaded Python interpreter.\n\ |
|
2944 It should be set to a divisor of the maximum time between\n\ |
|
2945 frames in an animation."; |
|
2946 |
|
2947 static PyObject * |
|
2948 Tkinter_getbusywaitinterval(PyObject *self, PyObject *args) |
|
2949 { |
|
2950 return PyInt_FromLong(Tkinter_busywaitinterval); |
|
2951 } |
|
2952 |
|
2953 static char getbusywaitinterval_doc[] = |
|
2954 "getbusywaitinterval() -> int\n\ |
|
2955 \n\ |
|
2956 Return the current busy-wait interval between successive\n\ |
|
2957 calls to Tcl_DoOneEvent in a threaded Python interpreter."; |
|
2958 |
|
2959 static PyMethodDef moduleMethods[] = |
|
2960 { |
|
2961 {"_flatten", Tkinter_Flatten, METH_VARARGS}, |
|
2962 {"create", Tkinter_Create, METH_VARARGS}, |
|
2963 #ifdef HAVE_CREATEFILEHANDLER |
|
2964 {"createfilehandler", Tkapp_CreateFileHandler, METH_VARARGS}, |
|
2965 {"deletefilehandler", Tkapp_DeleteFileHandler, METH_VARARGS}, |
|
2966 #endif |
|
2967 {"createtimerhandler", Tkapp_CreateTimerHandler, METH_VARARGS}, |
|
2968 {"mainloop", Tkapp_MainLoop, METH_VARARGS}, |
|
2969 {"dooneevent", Tkapp_DoOneEvent, METH_VARARGS}, |
|
2970 {"quit", Tkapp_Quit, METH_VARARGS}, |
|
2971 {"setbusywaitinterval",Tkinter_setbusywaitinterval, METH_VARARGS, |
|
2972 setbusywaitinterval_doc}, |
|
2973 {"getbusywaitinterval",(PyCFunction)Tkinter_getbusywaitinterval, |
|
2974 METH_NOARGS, getbusywaitinterval_doc}, |
|
2975 {NULL, NULL} |
|
2976 }; |
|
2977 |
|
2978 #ifdef WAIT_FOR_STDIN |
|
2979 |
|
2980 static int stdin_ready = 0; |
|
2981 |
|
2982 #ifndef MS_WINDOWS |
|
2983 static void |
|
2984 MyFileProc(void *clientData, int mask) |
|
2985 { |
|
2986 stdin_ready = 1; |
|
2987 } |
|
2988 #endif |
|
2989 |
|
2990 #ifdef WITH_THREAD |
|
2991 static PyThreadState *event_tstate = NULL; |
|
2992 #endif |
|
2993 |
|
2994 static int |
|
2995 EventHook(void) |
|
2996 { |
|
2997 #ifndef MS_WINDOWS |
|
2998 int tfile; |
|
2999 #endif |
|
3000 #ifdef WITH_THREAD |
|
3001 PyEval_RestoreThread(event_tstate); |
|
3002 #endif |
|
3003 stdin_ready = 0; |
|
3004 errorInCmd = 0; |
|
3005 #ifndef MS_WINDOWS |
|
3006 tfile = fileno(stdin); |
|
3007 Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL); |
|
3008 #endif |
|
3009 while (!errorInCmd && !stdin_ready) { |
|
3010 int result; |
|
3011 #ifdef MS_WINDOWS |
|
3012 if (_kbhit()) { |
|
3013 stdin_ready = 1; |
|
3014 break; |
|
3015 } |
|
3016 #endif |
|
3017 #if defined(WITH_THREAD) || defined(MS_WINDOWS) |
|
3018 Py_BEGIN_ALLOW_THREADS |
|
3019 if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); |
|
3020 tcl_tstate = event_tstate; |
|
3021 |
|
3022 result = Tcl_DoOneEvent(TCL_DONT_WAIT); |
|
3023 |
|
3024 tcl_tstate = NULL; |
|
3025 if(tcl_lock)PyThread_release_lock(tcl_lock); |
|
3026 if (result == 0) |
|
3027 Sleep(Tkinter_busywaitinterval); |
|
3028 Py_END_ALLOW_THREADS |
|
3029 #else |
|
3030 result = Tcl_DoOneEvent(0); |
|
3031 #endif |
|
3032 |
|
3033 if (result < 0) |
|
3034 break; |
|
3035 } |
|
3036 #ifndef MS_WINDOWS |
|
3037 Tcl_DeleteFileHandler(tfile); |
|
3038 #endif |
|
3039 if (errorInCmd) { |
|
3040 errorInCmd = 0; |
|
3041 PyErr_Restore(excInCmd, valInCmd, trbInCmd); |
|
3042 excInCmd = valInCmd = trbInCmd = NULL; |
|
3043 PyErr_Print(); |
|
3044 } |
|
3045 #ifdef WITH_THREAD |
|
3046 PyEval_SaveThread(); |
|
3047 #endif |
|
3048 return 0; |
|
3049 } |
|
3050 |
|
3051 #endif |
|
3052 |
|
3053 static void |
|
3054 EnableEventHook(void) |
|
3055 { |
|
3056 #ifdef WAIT_FOR_STDIN |
|
3057 if (PyOS_InputHook == NULL) { |
|
3058 #ifdef WITH_THREAD |
|
3059 event_tstate = PyThreadState_Get(); |
|
3060 #endif |
|
3061 PyOS_InputHook = EventHook; |
|
3062 } |
|
3063 #endif |
|
3064 } |
|
3065 |
|
3066 static void |
|
3067 DisableEventHook(void) |
|
3068 { |
|
3069 #ifdef WAIT_FOR_STDIN |
|
3070 if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) { |
|
3071 PyOS_InputHook = NULL; |
|
3072 } |
|
3073 #endif |
|
3074 } |
|
3075 |
|
3076 |
|
3077 /* all errors will be checked in one fell swoop in init_tkinter() */ |
|
3078 static void |
|
3079 ins_long(PyObject *d, char *name, long val) |
|
3080 { |
|
3081 PyObject *v = PyInt_FromLong(val); |
|
3082 if (v) { |
|
3083 PyDict_SetItemString(d, name, v); |
|
3084 Py_DECREF(v); |
|
3085 } |
|
3086 } |
|
3087 static void |
|
3088 ins_string(PyObject *d, char *name, char *val) |
|
3089 { |
|
3090 PyObject *v = PyString_FromString(val); |
|
3091 if (v) { |
|
3092 PyDict_SetItemString(d, name, v); |
|
3093 Py_DECREF(v); |
|
3094 } |
|
3095 } |
|
3096 |
|
3097 |
|
3098 PyMODINIT_FUNC |
|
3099 init_tkinter(void) |
|
3100 { |
|
3101 PyObject *m, *d; |
|
3102 |
|
3103 Py_TYPE(&Tkapp_Type) = &PyType_Type; |
|
3104 |
|
3105 #ifdef WITH_THREAD |
|
3106 tcl_lock = PyThread_allocate_lock(); |
|
3107 #endif |
|
3108 |
|
3109 m = Py_InitModule("_tkinter", moduleMethods); |
|
3110 if (m == NULL) |
|
3111 return; |
|
3112 |
|
3113 d = PyModule_GetDict(m); |
|
3114 Tkinter_TclError = PyErr_NewException("_tkinter.TclError", NULL, NULL); |
|
3115 PyDict_SetItemString(d, "TclError", Tkinter_TclError); |
|
3116 |
|
3117 ins_long(d, "READABLE", TCL_READABLE); |
|
3118 ins_long(d, "WRITABLE", TCL_WRITABLE); |
|
3119 ins_long(d, "EXCEPTION", TCL_EXCEPTION); |
|
3120 ins_long(d, "WINDOW_EVENTS", TCL_WINDOW_EVENTS); |
|
3121 ins_long(d, "FILE_EVENTS", TCL_FILE_EVENTS); |
|
3122 ins_long(d, "TIMER_EVENTS", TCL_TIMER_EVENTS); |
|
3123 ins_long(d, "IDLE_EVENTS", TCL_IDLE_EVENTS); |
|
3124 ins_long(d, "ALL_EVENTS", TCL_ALL_EVENTS); |
|
3125 ins_long(d, "DONT_WAIT", TCL_DONT_WAIT); |
|
3126 ins_string(d, "TK_VERSION", TK_VERSION); |
|
3127 ins_string(d, "TCL_VERSION", TCL_VERSION); |
|
3128 |
|
3129 PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type); |
|
3130 |
|
3131 Py_TYPE(&Tktt_Type) = &PyType_Type; |
|
3132 PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type); |
|
3133 |
|
3134 Py_TYPE(&PyTclObject_Type) = &PyType_Type; |
|
3135 PyDict_SetItemString(d, "Tcl_Obj", (PyObject *)&PyTclObject_Type); |
|
3136 |
|
3137 #ifdef TK_AQUA |
|
3138 /* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems |
|
3139 * start waking up. Note that Tcl_FindExecutable will do this, this |
|
3140 * code must be above it! The original warning from |
|
3141 * tkMacOSXAppInit.c is copied below. |
|
3142 * |
|
3143 * NB - You have to swap in the Tk Notifier BEFORE you start up the |
|
3144 * Tcl interpreter for now. It probably should work to do this |
|
3145 * in the other order, but for now it doesn't seem to. |
|
3146 * |
|
3147 */ |
|
3148 Tk_MacOSXSetupTkNotifier(); |
|
3149 #endif |
|
3150 |
|
3151 |
|
3152 /* This helps the dynamic loader; in Unicode aware Tcl versions |
|
3153 it also helps Tcl find its encodings. */ |
|
3154 Tcl_FindExecutable(Py_GetProgramName()); |
|
3155 |
|
3156 if (PyErr_Occurred()) |
|
3157 return; |
|
3158 |
|
3159 #if 0 |
|
3160 /* This was not a good idea; through <Destroy> bindings, |
|
3161 Tcl_Finalize() may invoke Python code but at that point the |
|
3162 interpreter and thread state have already been destroyed! */ |
|
3163 Py_AtExit(Tcl_Finalize); |
|
3164 #endif |
|
3165 |
|
3166 } |