blob: 5153454d5fb8d97d37bfa205637a274f2437bdc4 [file] [log] [blame]
Guido van Rossum18468821994-06-20 07:49:28 +00001/* tkintermodule.c -- Interface to libtk.a and libtcl.a.
2 Copyright (C) 1994 Steen Lumholt */
3
Guido van Rossum602099a1994-09-14 13:32:22 +00004#include <Python.h>
Guido van Rossum18468821994-06-20 07:49:28 +00005
Guido van Rossum18468821994-06-20 07:49:28 +00006#define PyInit_tkinter inittkinter
7
Guido van Rossum18468821994-06-20 07:49:28 +00008#include <tcl.h>
9#include <tk.h>
10
11extern char *getprogramname ();
Guido van Rossumd308e2b1994-07-07 09:25:12 +000012
13/* Internal declarations from tkInt.h. */
Guido van Rossum18468821994-06-20 07:49:28 +000014extern int tk_NumMainWindows;
Guido van Rossumd308e2b1994-07-07 09:25:12 +000015extern struct { Tk_Window win; } *tkMainWindowList;
Guido van Rossum18468821994-06-20 07:49:28 +000016
17/**** Tkapp Object Declaration ****/
18
19staticforward PyTypeObject Tkapp_Type;
20
21typedef struct
22 {
23 PyObject_HEAD
24 Tcl_Interp *interp;
25 Tk_Window tkwin;
26 }
27TkappObject;
28
29#define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type)
30#define Tkapp_Tkwin(v) (((TkappObject *) (v))->tkwin)
31#define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
32#define Tkapp_Result(v) (((TkappObject *) (v))->interp->result)
33
34#define DEBUG_REFCNT(v) (printf ("DEBUG: id=%p, refcnt=%i\n", \
35 (void *) v, ((PyObject *) v)->ob_refcnt))
36
37/**** Error Handling ****/
38
39static PyObject *Tkinter_TclError;
Guido van Rossumd308e2b1994-07-07 09:25:12 +000040static int quitMainLoop = 0;
Guido van Rossum18468821994-06-20 07:49:28 +000041static int errorInCmd = 0;
42static PyObject *excInCmd;
43static PyObject *valInCmd;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +000044static PyObject *trbInCmd;
Guido van Rossum18468821994-06-20 07:49:28 +000045
46static PyObject *
47Tkinter_Error (v)
48 PyObject *v;
49{
Guido van Rossum18468821994-06-20 07:49:28 +000050 PyErr_SetString (Tkinter_TclError, Tkapp_Result (v));
51 return NULL;
52}
53
54int
55PythonCmd_Error (interp)
56 Tcl_Interp *interp;
57{
58 errorInCmd = 1;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +000059 PyErr_Fetch (&excInCmd, &valInCmd, &trbInCmd);
Guido van Rossum18468821994-06-20 07:49:28 +000060 return TCL_ERROR;
61}
62
63/**** Utils ****/
64
65static char *
66AsString (value, tmp)
67 PyObject *value;
68 PyObject *tmp;
69{
70 if (PyString_Check (value))
71 return PyString_AsString (value);
72 else
73 {
74 PyObject *v;
75
Guido van Rossumcd938fc1995-01-17 16:13:48 +000076 v = PyObject_Str (value);
Guido van Rossum18468821994-06-20 07:49:28 +000077 PyList_Append (tmp, v);
78 Py_DECREF (v);
79 return PyString_AsString (v);
80 }
81}
82
83#define ARGSZ 64
84
85static char *
86Merge (args)
87 PyObject *args;
88{
89 PyObject *tmp;
90 char *argvStore[ARGSZ];
91 char **argv;
92 int fvStore[ARGSZ];
93 int *fv;
94 int argc;
95 char *res;
96 int i;
97
98 tmp = PyList_New (0);
99 argv = argvStore;
100 fv = fvStore;
101
102 if (!PyTuple_Check (args))
103 {
104 argc = 1;
105 fv[0] = 0;
106 argv[0] = AsString (args, tmp);
107 }
108 else
109 {
110 PyObject *v;
111
112 if (PyTuple_Size (args) > ARGSZ)
113 {
Guido van Rossumb6fe7041995-03-09 12:13:43 +0000114 argv = (char **) malloc (PyTuple_Size (args) * sizeof (char *));
115 fv = (int *) malloc (PyTuple_Size (args) * sizeof (int));
Guido van Rossum18468821994-06-20 07:49:28 +0000116 if (argv == NULL || fv == NULL)
117 PyErr_NoMemory ();
118 }
119
120 argc = PyTuple_Size (args);
121 for (i = 0; i < argc; i++)
122 {
123 v = PyTuple_GetItem (args, i);
124 if (PyTuple_Check (v))
125 {
126 fv[i] = 1;
127 argv[i] = Merge (v);
128 }
129 else if (v == Py_None)
130 {
131 argc = i;
132 break;
133 }
134 else
135 {
136 fv[i] = 0;
137 argv[i] = AsString (v, tmp);
138 }
139 }
140 }
141
142 res = Tcl_Merge (argc, argv);
143
144 Py_DECREF (tmp);
145 for (i = 0; i < argc; i++)
146 if (fv[i]) free (argv[i]);
147 if (argv != argvStore)
148 free (argv);
149 if (fv != fvStore)
150 free (fv);
151
152 return res;
153}
154
155static PyObject *
156Split (self, list)
157 PyObject *self;
158 char *list;
159{
160 int argc;
161 char **argv;
162 PyObject *v;
163
164 if (list == NULL)
165 {
166 Py_INCREF (Py_None);
167 return Py_None;
168 }
169
170 if (Tcl_SplitList (Tkapp_Interp (self), list, &argc, &argv) == TCL_ERROR)
171 return Tkinter_Error (self);
172
173 if (argc == 0)
174 v = PyString_FromString ("");
175 else if (argc == 1)
176 v = PyString_FromString (argv[0]);
177 else
178 {
179 int i;
180
181 v = PyTuple_New (argc);
182 for (i = 0; i < argc; i++)
183 PyTuple_SetItem (v, i, Split (self, argv[i]));
184 }
185
186 free (argv);
187 return v;
188}
189
190/**** Tkapp Object ****/
191
192#ifndef WITH_APPINIT
193int
194Tcl_AppInit (interp)
195 Tcl_Interp *interp;
196{
Guido van Rossuma3c3f2c1995-02-07 15:41:02 +0000197 Tk_Window main;
198 main = Tk_MainWindow(interp);
199 if (Tcl_Init (interp) == TCL_ERROR) {
200 fprintf(stderr, "Tcl_Init error: %s\n", interp->result);
Guido van Rossum18468821994-06-20 07:49:28 +0000201 return TCL_ERROR;
Guido van Rossuma3c3f2c1995-02-07 15:41:02 +0000202 }
203 if (Tk_Init (interp) == TCL_ERROR) {
204 fprintf(stderr, "Tk_Init error: %s\n", interp->result);
Guido van Rossum18468821994-06-20 07:49:28 +0000205 return TCL_ERROR;
Guido van Rossuma3c3f2c1995-02-07 15:41:02 +0000206 }
Guido van Rossum18468821994-06-20 07:49:28 +0000207 return TCL_OK;
208}
209#endif /* !WITH_APPINIT */
210
211/* Initialize the Tk application; see the `main' function in
212 `tkMain.c'. */
213static TkappObject *
214Tkapp_New (screenName, baseName, className, interactive)
215 char *screenName;
216 char *baseName;
217 char *className;
218 int interactive;
219{
220 TkappObject *v;
221
222 v = PyObject_NEW (TkappObject, &Tkapp_Type);
223 if (v == NULL)
224 return NULL;
225
226 v->interp = Tcl_CreateInterp ();
227 v->tkwin = Tk_CreateMainWindow (v->interp, screenName,
228 baseName, className);
229 if (v->tkwin == NULL)
230 return (TkappObject *) Tkinter_Error ((PyObject *) v);
231
232 Tk_GeometryRequest (v->tkwin, 200, 200);
233
234 if (screenName != NULL)
235 Tcl_SetVar2 (v->interp, "env", "DISPLAY", screenName, TCL_GLOBAL_ONLY);
236
237 if (interactive)
238 Tcl_SetVar (v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
239 else
240 Tcl_SetVar (v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
241
Guido van Rossum18468821994-06-20 07:49:28 +0000242 if (Tcl_AppInit (v->interp) != TCL_OK)
243 {
244 PyErr_SetString (Tkinter_TclError, "Tcl_AppInit failed"); /* XXX */
245 return NULL;
246 }
Guido van Rossum18468821994-06-20 07:49:28 +0000247
248 return v;
249}
250
251/** Tcl Eval **/
252
253static PyObject *
254Tkapp_Call (self, args)
255 PyObject *self;
256 PyObject *args;
257{
258 char *cmd;
259
260 cmd = Merge (args);
261 if (Tcl_Eval (Tkapp_Interp (self), cmd) == TCL_ERROR)
262 {
263 free (cmd);
264 return Tkinter_Error (self);
265 }
266
267 free (cmd);
268 return PyString_FromString (Tkapp_Result (self));
269}
270
271static PyObject *
272Tkapp_GlobalCall (self, args)
273 PyObject *self;
274 PyObject *args;
275{
276 char *cmd;
277
278 cmd = Merge (args);
279 if (Tcl_GlobalEval (Tkapp_Interp (self), cmd) == TCL_ERROR)
280 {
281 free (cmd);
282 return Tkinter_Error (self);
283 }
284
285 free (cmd);
286 return PyString_FromString (Tkapp_Result (self));
287}
288
289static PyObject *
290Tkapp_Eval (self, args)
291 PyObject *self;
292 PyObject *args;
293{
294 char *script;
295
296 if (!PyArg_Parse (args, "s", &script))
297 return NULL;
298
299 if (Tcl_Eval (Tkapp_Interp (self), script) == TCL_ERROR)
300 return Tkinter_Error (self);
301
302 return PyString_FromString (Tkapp_Result (self));
303}
304
305static PyObject *
306Tkapp_GlobalEval (self, args)
307 PyObject *self;
308 PyObject *args;
309{
310 char *script;
311
312 if (!PyArg_Parse (args, "s", &script))
313 return NULL;
314
315 if (Tcl_GlobalEval (Tkapp_Interp (self), script) == TCL_ERROR)
316 return Tkinter_Error (self);
317
318 return PyString_FromString (Tkapp_Result (self));
319}
320
321static PyObject *
322Tkapp_EvalFile (self, args)
323 PyObject *self;
324 PyObject *args;
325{
326 char *fileName;
327
328 if (!PyArg_Parse (args, "s", &fileName))
329 return NULL;
330
331 if (Tcl_EvalFile (Tkapp_Interp (self), fileName) == TCL_ERROR)
332 return Tkinter_Error (self);
333
334 return PyString_FromString (Tkapp_Result (self));
335}
336
337static PyObject *
338Tkapp_Record (self, args)
339 PyObject *self;
340 PyObject *args;
341{
342 char *script;
343
344 if (!PyArg_Parse (args, "s", &script))
345 return NULL;
346
347 if (Tcl_RecordAndEval (Tkapp_Interp (self),
348 script, TCL_NO_EVAL) == TCL_ERROR)
349 return Tkinter_Error (self);
350
351 return PyString_FromString (Tkapp_Result (self));
352}
353
354static PyObject *
355Tkapp_AddErrorInfo (self, args)
356 PyObject *self;
357 PyObject *args;
358{
359 char *msg;
360
361 if (!PyArg_Parse (args, "s", &msg))
362 return NULL;
363 Tcl_AddErrorInfo (Tkapp_Interp (self), msg);
364
365 Py_INCREF(Py_None);
366 return Py_None;
367}
368
369/** Tcl Variable **/
370
371static PyObject *
372SetVar (self, args, flags)
373 PyObject *self;
374 PyObject *args;
375 int flags;
376{
377 char *name1, *name2, *ok;
378 PyObject *newValue;
379 PyObject *tmp;
380
381 tmp = PyList_New (0);
382
383 if (PyArg_Parse (args, "(sO)", &name1, &newValue))
384 ok = Tcl_SetVar (Tkapp_Interp (self), name1,
385 AsString (newValue, tmp), flags); /* XXX Merge? */
386 else if (PyArg_Parse (args, "(ssO)", &name1, &name2, &newValue))
387 ok = Tcl_SetVar2 (Tkapp_Interp (self), name1, name2,
388 AsString (newValue, tmp), flags);
389 else
390 {
391 Py_DECREF (tmp);
392 return NULL;
393 }
394 Py_DECREF (tmp);
395
396 if (!ok)
397 return Tkinter_Error (self);
398
399 Py_INCREF (Py_None);
400 return Py_None;
401}
402
403static PyObject *
404Tkapp_SetVar (self, args)
405 PyObject *self;
406 PyObject *args;
407{
408 return SetVar (self, args, TCL_LEAVE_ERR_MSG);
409}
410
411static PyObject *
412Tkapp_GlobalSetVar (self, args)
413 PyObject *self;
414 PyObject *args;
415{
416 return SetVar (self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
417}
418
419static PyObject *
420GetVar (self, args, flags)
421 PyObject *self;
422 PyObject *args;
423 int flags;
424{
425 char *name1, *name2, *s;
426
427 if (PyArg_Parse (args, "s", &name1))
428 s = Tcl_GetVar (Tkapp_Interp (self), name1, flags);
429 else if (PyArg_Parse (args, "(ss)", &name1, &name2))
430 s = Tcl_GetVar2 (Tkapp_Interp (self), name1, name2, flags);
431 else
432 return NULL;
433
434 if (s == NULL)
435 return Tkinter_Error (self);
436
437 return PyString_FromString (s);
438}
439
440static PyObject *
441Tkapp_GetVar (self, args)
442 PyObject *self;
443 PyObject *args;
444{
445 return GetVar (self, args, TCL_LEAVE_ERR_MSG);
446}
447
448static PyObject *
449Tkapp_GlobalGetVar (self, args)
450 PyObject *self;
451 PyObject *args;
452{
453 return GetVar (self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
454}
455
456static PyObject *
457UnsetVar (self, args, flags)
458 PyObject *self;
459 PyObject *args;
460 int flags;
461{
462 char *name1, *name2;
463 int code;
464
465 if (PyArg_Parse (args, "s", &name1))
466 code = Tcl_UnsetVar (Tkapp_Interp (self), name1, flags);
467 else if (PyArg_Parse (args, "(ss)", &name1, &name2))
468 code = Tcl_UnsetVar2 (Tkapp_Interp (self), name1, name2, flags);
469 else
470 return NULL;
471
472 if (code == TCL_ERROR)
473 return Tkinter_Error (self);
474
475 Py_INCREF (Py_None);
476 return Py_None;
477}
478
479static PyObject *
480Tkapp_UnsetVar (self, args)
481 PyObject *self;
482 PyObject *args;
483{
484 return UnsetVar (self, args, TCL_LEAVE_ERR_MSG);
485}
486
487static PyObject *
488Tkapp_GlobalUnsetVar (self, args)
489 PyObject *self;
490 PyObject *args;
491{
492 return UnsetVar (self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
493}
494
495/** Tcl to Python **/
496
497static PyObject *
498Tkapp_GetInt (self, args)
499 PyObject *self;
500 PyObject *args;
501{
502 char *s;
503 int v;
504
505 if (!PyArg_Parse (args, "s", &s))
506 return NULL;
507 if (Tcl_GetInt (Tkapp_Interp (self), s, &v) == TCL_ERROR)
508 return Tkinter_Error (self);
509 return Py_BuildValue ("i", v);
510}
511
512static PyObject *
513Tkapp_GetDouble (self, args)
514 PyObject *self;
515 PyObject *args;
516{
517 char *s;
518 double v;
519
520 if (!PyArg_Parse (args, "s", &s))
521 return NULL;
522 if (Tcl_GetDouble (Tkapp_Interp (self), s, &v) == TCL_ERROR)
523 return Tkinter_Error (self);
524 return Py_BuildValue ("d", v);
525}
526
527static PyObject *
528Tkapp_GetBoolean (self, args)
529 PyObject *self;
530 PyObject *args;
531{
532 char *s;
533 int v;
534
535 if (!PyArg_Parse (args, "s", &s))
536 return NULL;
537 if (Tcl_GetBoolean (Tkapp_Interp (self), s, &v) == TCL_ERROR)
538 return Tkinter_Error (self);
539 return Py_BuildValue ("i", v);
540}
541
542static PyObject *
543Tkapp_ExprString (self, args)
544 PyObject *self;
545 PyObject *args;
546{
547 char *s;
548
549 if (!PyArg_Parse (args, "s", &s))
550 return NULL;
551 if (Tcl_ExprString (Tkapp_Interp (self), s) == TCL_ERROR)
552 return Tkinter_Error (self);
553 return Py_BuildValue ("s", Tkapp_Result (self));
554}
555
556static PyObject *
557Tkapp_ExprLong (self, args)
558 PyObject *self;
559 PyObject *args;
560{
561 char *s;
562 long v;
563
564 if (!PyArg_Parse (args, "s", &s))
565 return NULL;
566 if (Tcl_ExprLong (Tkapp_Interp (self), s, &v) == TCL_ERROR)
567 return Tkinter_Error (self);
568 return Py_BuildValue ("l", v);
569}
570
571static PyObject *
572Tkapp_ExprDouble (self, args)
573 PyObject *self;
574 PyObject *args;
575{
576 char *s;
577 double v;
578
579 if (!PyArg_Parse (args, "s", &s))
580 return NULL;
581 if (Tcl_ExprDouble (Tkapp_Interp (self), s, &v) == TCL_ERROR)
582 return Tkinter_Error (self);
583 return Py_BuildValue ("d", v);
584}
585
586static PyObject *
587Tkapp_ExprBoolean (self, args)
588 PyObject *self;
589 PyObject *args;
590{
591 char *s;
592 int v;
593
594 if (!PyArg_Parse (args, "s", &s))
595 return NULL;
596 if (Tcl_ExprBoolean (Tkapp_Interp (self), s, &v) == TCL_ERROR)
597 return Tkinter_Error (self);
598 return Py_BuildValue ("i", v);
599}
600
601static PyObject *
602Tkapp_SplitList (self, args)
603 PyObject *self;
604 PyObject *args;
605{
606 char *list;
607 int argc;
608 char **argv;
609 PyObject *v;
610 int i;
611
612 if (!PyArg_Parse (args, "s", &list))
613 return NULL;
614
615 if (Tcl_SplitList (Tkapp_Interp (self), list, &argc, &argv) == TCL_ERROR)
616 return Tkinter_Error (self);
617
618 v = PyTuple_New (argc);
619 for (i = 0; i < argc; i++)
620 PyTuple_SetItem (v, i, PyString_FromString (argv[i]));
621
622 free (argv);
623 return v;
624}
625
626static PyObject *
627Tkapp_Split (self, args)
628 PyObject *self;
629 PyObject *args;
630{
631 char *list;
632
633 if (!PyArg_Parse (args, "s", &list))
634 return NULL;
635 return Split (self, list);
636}
637
638static PyObject *
639Tkapp_Merge (self, args)
640 PyObject *self;
641 PyObject *args;
642{
643 char *s;
644 PyObject *v;
645
646 s = Merge (args);
647 v = PyString_FromString (s);
648 free (s);
649 return v;
650}
651
652/** Tcl Command **/
653
654/* This is the Tcl command that acts as a wrapper for Python
655 function or method. */
656static int
657PythonCmd (clientData, interp, argc, argv)
658 ClientData clientData; /* Is (self, func) */
659 Tcl_Interp *interp;
660 int argc;
661 char *argv[];
662{
663 PyObject *self, *func, *arg, *res, *tmp;
664 int i;
665
666 self = PyTuple_GetItem ((PyObject *) clientData, 0);
667 func = PyTuple_GetItem ((PyObject *) clientData, 1);
668
669 /* Create argument list (argv1, ..., argvN) */
670 arg = PyTuple_New (argc - 1);
671 for (i = 0; i < (argc - 1); i++)
672 PyTuple_SetItem (arg, i, PyString_FromString (argv[i + 1]));
673
674 res = PyEval_CallObject (func, arg);
675 Py_DECREF (arg);
Guido van Rossumd308e2b1994-07-07 09:25:12 +0000676
Guido van Rossum18468821994-06-20 07:49:28 +0000677 if (res == NULL)
678 return PythonCmd_Error (interp);
679
680 tmp = PyList_New (0);
681 Tcl_SetResult (Tkapp_Interp (self), AsString (res, tmp), TCL_VOLATILE);
682 Py_DECREF (res);
683 Py_DECREF (tmp);
684
685 return TCL_OK;
686}
687
688static void
689PythonCmdDelete (clientData)
690 ClientData clientData; /* Is (self, func) */
691{
692 Py_DECREF ((PyObject *) clientData);
693}
694
695static PyObject *
696Tkapp_CreateCommand (self, args)
697 PyObject *self;
698 PyObject *args;
699{
700 char *cmdName;
701 PyObject *data;
702 PyObject *func;
703
704 /* Args is: (cmdName, func) */
705 if (!PyTuple_Check (args)
706 || !(PyTuple_Size (args) == 2)
707 || !PyString_Check (PyTuple_GetItem (args, 0))
Guido van Rossuma3c3f2c1995-02-07 15:41:02 +0000708 || !PyCallable_Check (PyTuple_GetItem (args, 1)))
Guido van Rossum18468821994-06-20 07:49:28 +0000709 {
710 PyErr_SetString (PyExc_TypeError, "bad argument list");
711 return NULL;
712 }
713
714 cmdName = PyString_AsString (PyTuple_GetItem (args, 0));
715 func = PyTuple_GetItem (args, 1);
716
717 data = PyTuple_New (2); /* ClientData is: (self, func) */
718
719 Py_INCREF (self);
720 PyTuple_SetItem (data, 0, self);
721
722 Py_INCREF (func);
723 PyTuple_SetItem (data, 1, func);
724
725 Tcl_CreateCommand (Tkapp_Interp (self), cmdName, PythonCmd,
726 (ClientData) data, PythonCmdDelete);
727
728 Py_INCREF (Py_None);
729 return Py_None;
730}
731
732static PyObject *
733Tkapp_DeleteCommand (self, args)
734 PyObject *self;
735 PyObject *args;
736{
737 char *cmdName;
738
739 if (!PyArg_Parse (args, "s", &cmdName))
740 return NULL;
741 if (Tcl_DeleteCommand (Tkapp_Interp (self), cmdName) == -1)
742 {
743 PyErr_SetString (Tkinter_TclError, "can't delete Tcl command");
744 return NULL;
745 }
746 Py_INCREF (Py_None);
747 return Py_None;
748}
749
750/** File Handler **/
751
Guido van Rossuma597dde1995-01-10 20:56:29 +0000752static void
Guido van Rossum18468821994-06-20 07:49:28 +0000753FileHandler (clientData, mask)
Guido van Rossum76875221994-06-27 07:59:42 +0000754 ClientData clientData; /* Is: (func, file) */
Guido van Rossum18468821994-06-20 07:49:28 +0000755 int mask;
756{
Guido van Rossum76875221994-06-27 07:59:42 +0000757 PyObject *func, *file, *arg, *res;
Guido van Rossum18468821994-06-20 07:49:28 +0000758
Guido van Rossum76875221994-06-27 07:59:42 +0000759 func = PyTuple_GetItem ((PyObject *) clientData, 0);
760 file = PyTuple_GetItem ((PyObject *) clientData, 1);
Guido van Rossum18468821994-06-20 07:49:28 +0000761
Guido van Rossum76875221994-06-27 07:59:42 +0000762 arg = Py_BuildValue ("(Oi)", file, (long) mask);
Guido van Rossum18468821994-06-20 07:49:28 +0000763 res = PyEval_CallObject (func, arg);
764 Py_DECREF (arg);
765 if (res == NULL)
766 {
767 errorInCmd = 1;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000768 PyErr_Fetch (&excInCmd, &valInCmd, &trbInCmd);
Guido van Rossum18468821994-06-20 07:49:28 +0000769 }
Guido van Rossum9bb4fd61994-08-09 14:15:19 +0000770 Py_XDECREF (res);
771}
772
773static int
774GetFileNo (file)
775 PyObject *file; /* Either an int >= 0 or an object with a
776 .fileno() method that returns an int >= 0 */
777{
Guido van Rossuma597dde1995-01-10 20:56:29 +0000778 PyObject *meth, *args, *res;
Guido van Rossum9bb4fd61994-08-09 14:15:19 +0000779 int id;
780 if (PyInt_Check(file)) {
781 id = PyInt_AsLong(file);
782 if (id < 0)
783 PyErr_SetString(PyExc_ValueError, "invalid file id");
784 return id;
785 }
786 meth = PyObject_GetAttrString(file, "fileno");
787 if (meth == NULL)
788 return -1;
789 args = PyTuple_New(0);
790 if (args == NULL)
791 return -1;
792 res = PyEval_CallObject(meth, args);
793 Py_DECREF(args);
794 Py_DECREF(meth);
795 if (res == NULL)
796 return -1;
797 if (PyInt_Check(res))
798 id = PyInt_AsLong(res);
799 else
800 id = -1;
801 if (id < 0)
802 PyErr_SetString(PyExc_ValueError,
803 "invalid fileno() return value");
804 Py_DECREF(res);
805 return id;
Guido van Rossum18468821994-06-20 07:49:28 +0000806}
807
808static PyObject *
809Tkapp_CreateFileHandler (self, args)
810 PyObject *self;
811 PyObject *args; /* Is (file, mask, func) */
812{
Guido van Rossum76875221994-06-27 07:59:42 +0000813 PyObject *file, *func, *data;
814 int mask, id;
Guido van Rossum18468821994-06-20 07:49:28 +0000815
816 if (!PyArg_Parse (args, "(OiO)", &file, &mask, &func))
817 return NULL;
Guido van Rossum9bb4fd61994-08-09 14:15:19 +0000818 id = GetFileNo (file);
819 if (id < 0)
820 return NULL;
Guido van Rossuma3c3f2c1995-02-07 15:41:02 +0000821 if (!PyCallable_Check(func))
Guido van Rossum18468821994-06-20 07:49:28 +0000822 {
823 PyErr_SetString (PyExc_TypeError, "bad argument list");
824 return NULL;
825 }
826
Guido van Rossum76875221994-06-27 07:59:42 +0000827 /* ClientData is: (func, file) */
828 data = Py_BuildValue ("(OO)", func, file);
829
Guido van Rossum76875221994-06-27 07:59:42 +0000830 Tk_CreateFileHandler (id, mask, FileHandler, (ClientData) data);
Guido van Rossum18468821994-06-20 07:49:28 +0000831 /* XXX fileHandlerDict */
Guido van Rossum76875221994-06-27 07:59:42 +0000832
Guido van Rossum18468821994-06-20 07:49:28 +0000833 Py_INCREF (Py_None);
834 return Py_None;
835}
836
837static PyObject *
838Tkapp_DeleteFileHandler (self, args)
839 PyObject *self;
840 PyObject *args; /* Args: file */
841{
Guido van Rossum9bb4fd61994-08-09 14:15:19 +0000842 PyObject *file;
Guido van Rossum18468821994-06-20 07:49:28 +0000843 int id;
844
Guido van Rossum9bb4fd61994-08-09 14:15:19 +0000845 if (!PyArg_Parse (args, "O", &file))
846 return NULL;
847 id = GetFileNo (file);
848 if (id < 0)
849 return NULL;
Guido van Rossum18468821994-06-20 07:49:28 +0000850
Guido van Rossum18468821994-06-20 07:49:28 +0000851 Tk_DeleteFileHandler (id);
852 /* XXX fileHandlerDict */
853 Py_INCREF (Py_None);
854 return Py_None;
855}
856
Guido van Rossumf34cadd1994-11-10 22:50:21 +0000857/**** Tktt Object (timer token) ****/
858
859staticforward PyTypeObject Tktt_Type;
860
861typedef struct
862 {
863 PyObject_HEAD
864 Tk_TimerToken token;
865 PyObject *func;
866 }
867TkttObject;
868
869static PyObject *
870Tktt_DeleteTimerHandler (self, args)
871 PyObject *self;
872 PyObject *args;
873{
874 TkttObject *v = (TkttObject *) self;
875
876 if (!PyArg_Parse (args, ""))
877 return NULL;
878 if (v->func != NULL)
879 {
880 Tk_DeleteTimerHandler (v->token);
881 PyMem_DEL (v->func);
882 v->func = NULL;
883 }
884 Py_INCREF (Py_None);
885 return Py_None;
886}
887
888static PyMethodDef Tktt_methods[] =
889{
890 {"deletetimerhandler", Tktt_DeleteTimerHandler},
891 {NULL, NULL}
892};
893
894static TkttObject *
895Tktt_New (token, func)
896 Tk_TimerToken token;
897 PyObject *func;
898{
899 TkttObject *v;
900
901 v = PyObject_NEW (TkttObject, &Tktt_Type);
902 if (v == NULL)
903 return NULL;
904
905 v->token = token;
906 v->func = func;
907 Py_INCREF (v->func);
908 return v;
909}
910
911static void
912Tktt_Dealloc (self)
913 PyObject *self;
914{
915 PyMem_DEL (self);
916}
917
918static int
919Tktt_Print (self, fp, flags)
920 PyObject *self;
921 FILE *fp;
922 int flags;
923{
924 TkttObject *v = (TkttObject *) self;
925
926 fprintf(fp, "<tktimertoken at 0x%x%s>", v,
927 v->func == NULL ? ", handler deleted" : "");
928 return 0;
929}
930
931static PyObject *
932Tktt_GetAttr (self, name)
933 PyObject *self;
934 char *name;
935{
936 return Py_FindMethod (Tktt_methods, self, name);
937}
938
939static PyTypeObject Tktt_Type =
940{
Guido van Rossuma597dde1995-01-10 20:56:29 +0000941 PyObject_HEAD_INIT (&PyType_Type)
Guido van Rossumf34cadd1994-11-10 22:50:21 +0000942 0, /*ob_size */
943 "tktimertoken", /*tp_name */
944 sizeof (TkttObject), /*tp_basicsize */
945 0, /*tp_itemsize */
946 Tktt_Dealloc, /*tp_dealloc */
947 Tktt_Print, /*tp_print */
948 Tktt_GetAttr, /*tp_getattr */
949 0, /*tp_setattr */
950 0, /*tp_compare */
951 0, /*tp_repr */
952 0, /*tp_as_number */
953 0, /*tp_as_sequence */
954 0, /*tp_as_mapping */
955 0, /*tp_hash */
956};
957
958/** Timer Handler **/
959
960static void
961TimerHandler (clientData)
962 ClientData clientData;
963{
964 PyObject *func = (PyObject *) clientData;
965 PyObject *arg, *res;
966
967 arg = PyTuple_New (0);
968 res = PyEval_CallObject (func, arg);
969 Py_DECREF (arg);
970 if (res == NULL)
971 {
972 errorInCmd = 1;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000973 PyErr_Fetch (&excInCmd, &valInCmd, &trbInCmd);
Guido van Rossumf34cadd1994-11-10 22:50:21 +0000974 }
Guido van Rossum3bbc62e1995-01-02 19:30:30 +0000975 else
976 Py_DECREF (res);
Guido van Rossumf34cadd1994-11-10 22:50:21 +0000977}
978
979static PyObject *
980Tkapp_CreateTimerHandler (self, args)
981 PyObject *self;
982 PyObject *args; /* Is (milliseconds, func) */
983{
984 int milliseconds;
985 PyObject *func;
986 Tk_TimerToken token;
987
988 if (!PyArg_Parse (args, "(iO)", &milliseconds, &func))
989 return NULL;
Guido van Rossuma3c3f2c1995-02-07 15:41:02 +0000990 if (!PyCallable_Check(func))
Guido van Rossumf34cadd1994-11-10 22:50:21 +0000991 {
992 PyErr_SetString (PyExc_TypeError, "bad argument list");
993 return NULL;
994 }
995 token = Tk_CreateTimerHandler(milliseconds, TimerHandler, (ClientData) func);
996 return (PyObject *) Tktt_New (token, func);
997}
998
Guido van Rossum18468821994-06-20 07:49:28 +0000999/** Event Loop **/
1000
Guido van Rossum18468821994-06-20 07:49:28 +00001001static PyObject *
1002Tkapp_MainLoop (self, args)
1003 PyObject *self;
1004 PyObject *args;
1005{
Guido van Rossumf34cadd1994-11-10 22:50:21 +00001006 int threshold = 0;
1007
Guido van Rossum18468821994-06-20 07:49:28 +00001008 if (!PyArg_Parse (args, ""))
Guido van Rossumf34cadd1994-11-10 22:50:21 +00001009 {
1010 PyErr_Clear();
1011 if (!PyArg_Parse (args, "i", &threshold))
1012 return NULL;
1013 }
Guido van Rossum18468821994-06-20 07:49:28 +00001014
1015 quitMainLoop = 0;
Guido van Rossumf34cadd1994-11-10 22:50:21 +00001016 while (tk_NumMainWindows > threshold && !quitMainLoop && !errorInCmd)
Guido van Rossum18468821994-06-20 07:49:28 +00001017 {
1018 if (PyOS_InterruptOccurred ())
1019 {
1020 PyErr_SetNone (PyExc_KeyboardInterrupt);
1021 return NULL;
1022 }
1023 Tk_DoOneEvent (0);
1024 }
1025
1026 if (errorInCmd)
1027 {
1028 errorInCmd = 0;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +00001029 PyErr_Restore (excInCmd, valInCmd, trbInCmd);
1030 excInCmd = valInCmd = trbInCmd = NULL;
Guido van Rossum18468821994-06-20 07:49:28 +00001031 return NULL;
1032 }
1033 Py_INCREF (Py_None);
1034 return Py_None;
1035}
1036
1037static PyObject *
Guido van Rossum062cfb01995-01-10 17:42:51 +00001038Tkapp_DoOneEvent (self, args)
1039 PyObject *self;
1040 PyObject *args;
1041{
1042 int flags;
1043 int rv;
1044
1045 if (PyArg_Parse (args, ""))
1046 flags = TK_ALL_EVENTS;
1047 else
1048 {
1049 PyErr_Clear();
1050 if (!PyArg_Parse (args, "i", &flags))
1051 return NULL;
1052 }
1053 rv = Tk_DoOneEvent(flags);
1054 return Py_BuildValue ("i", rv);
1055}
1056
1057static PyObject *
Guido van Rossum18468821994-06-20 07:49:28 +00001058Tkapp_Quit (self, args)
1059 PyObject *self;
1060 PyObject *args;
1061{
1062
1063 if (!PyArg_Parse (args, ""))
1064 return NULL;
1065 quitMainLoop = 1;
1066 Py_INCREF (Py_None);
1067 return Py_None;
1068}
1069
1070/**** Tkapp Method List ****/
1071
1072static PyMethodDef Tkapp_methods[] =
1073{
1074 {"call", Tkapp_Call},
1075 {"globalcall", Tkapp_GlobalCall},
1076 {"eval", Tkapp_Eval},
1077 {"globaleval", Tkapp_GlobalEval},
1078 {"evalfile", Tkapp_EvalFile},
1079 {"record", Tkapp_Record},
1080 {"adderrorinfo", Tkapp_AddErrorInfo},
1081 {"setvar", Tkapp_SetVar},
1082 {"globalsetvar", Tkapp_GlobalSetVar},
1083 {"getvar", Tkapp_GetVar},
1084 {"globalgetvar", Tkapp_GlobalGetVar},
1085 {"unsetvar", Tkapp_UnsetVar},
1086 {"globalunsetvar", Tkapp_GlobalUnsetVar},
1087 {"getint", Tkapp_GetInt},
1088 {"getdouble", Tkapp_GetDouble},
1089 {"getboolean", Tkapp_GetBoolean},
1090 {"exprstring", Tkapp_ExprString},
1091 {"exprlong", Tkapp_ExprLong},
1092 {"exprdouble", Tkapp_ExprDouble},
1093 {"exprboolean", Tkapp_ExprBoolean},
1094 {"splitlist", Tkapp_SplitList},
1095 {"split", Tkapp_Split},
1096 {"merge", Tkapp_Merge},
1097 {"createcommand", Tkapp_CreateCommand},
1098 {"deletecommand", Tkapp_DeleteCommand},
1099 {"createfilehandler", Tkapp_CreateFileHandler},
1100 {"deletefilehandler", Tkapp_DeleteFileHandler},
Guido van Rossumf34cadd1994-11-10 22:50:21 +00001101 {"createtimerhandler", Tkapp_CreateTimerHandler},
Guido van Rossum18468821994-06-20 07:49:28 +00001102 {"mainloop", Tkapp_MainLoop},
Guido van Rossum062cfb01995-01-10 17:42:51 +00001103 {"dooneevent", Tkapp_DoOneEvent},
Guido van Rossum18468821994-06-20 07:49:28 +00001104 {"quit", Tkapp_Quit},
1105 {NULL, NULL}
1106};
1107
1108/**** Tkapp Type Methods ****/
1109
1110static void
1111Tkapp_Dealloc (self)
1112 PyObject *self;
1113{
1114 Tk_DestroyWindow (Tkapp_Tkwin (self));
1115 Tcl_DeleteInterp (Tkapp_Interp (self));
1116 PyMem_DEL (self);
1117}
1118
1119static PyObject *
1120Tkapp_GetAttr (self, name)
1121 PyObject *self;
1122 char *name;
1123{
1124 return Py_FindMethod (Tkapp_methods, self, name);
1125}
1126
1127static PyTypeObject Tkapp_Type =
1128{
Guido van Rossuma597dde1995-01-10 20:56:29 +00001129 PyObject_HEAD_INIT (&PyType_Type)
Guido van Rossum18468821994-06-20 07:49:28 +00001130 0, /*ob_size */
1131 "tkapp", /*tp_name */
1132 sizeof (TkappObject), /*tp_basicsize */
1133 0, /*tp_itemsize */
1134 Tkapp_Dealloc, /*tp_dealloc */
1135 0, /*tp_print */
1136 Tkapp_GetAttr, /*tp_getattr */
1137 0, /*tp_setattr */
1138 0, /*tp_compare */
1139 0, /*tp_repr */
1140 0, /*tp_as_number */
1141 0, /*tp_as_sequence */
1142 0, /*tp_as_mapping */
1143 0, /*tp_hash */
1144};
1145
1146/**** Tkinter Module ****/
1147
1148static PyObject *
1149Tkinter_Create (self, args)
1150 PyObject *self;
1151 PyObject *args;
1152{
1153 char *screenName = NULL;
1154 char *baseName;
1155 char *className;
1156 int interactive = 0;
1157
1158 baseName = strrchr (getprogramname (), '/');
1159 if (baseName != NULL)
1160 baseName++;
1161 else
1162 baseName = getprogramname ();
1163 className = "Tk";
1164
1165 if (PyArg_Parse (args, ""))
1166 /* VOID */ ;
1167 else if (PyArg_Parse (args, "z",
1168 &screenName))
1169 /* VOID */ ;
1170 else if (PyArg_Parse (args, "(zs)",
1171 &screenName, &baseName))
1172 /* VOID */ ;
1173 else if (PyArg_Parse (args, "(zss)",
1174 &screenName, &baseName, &className))
1175 /* VOID */ ;
1176 else if (PyArg_Parse (args, "(zssi)",
1177 &screenName, &baseName, &className, &interactive))
1178 /* VOID */ ;
1179 else
1180 return NULL;
1181
1182 return (PyObject *) Tkapp_New (screenName, baseName, className,
1183 interactive);
1184}
1185
1186static PyMethodDef moduleMethods[] =
1187{
1188 {"create", Tkinter_Create},
Guido van Rossumf34cadd1994-11-10 22:50:21 +00001189 {"createfilehandler", Tkapp_CreateFileHandler},
1190 {"deletefilehandler", Tkapp_DeleteFileHandler},
1191 {"createtimerhandler", Tkapp_CreateTimerHandler},
1192 {"mainloop", Tkapp_MainLoop},
Guido van Rossum062cfb01995-01-10 17:42:51 +00001193 {"dooneevent", Tkapp_DoOneEvent},
Guido van Rossumf34cadd1994-11-10 22:50:21 +00001194 {"quit", Tkapp_Quit},
Guido van Rossum18468821994-06-20 07:49:28 +00001195 {NULL, NULL}
1196};
1197
Guido van Rossuma3c3f2c1995-02-07 15:41:02 +00001198#undef WITH_READLINE /* XXX */
Guido van Rossum18468821994-06-20 07:49:28 +00001199#ifdef WITH_READLINE
1200static int
1201EventHook ()
1202{
1203 if (errorInCmd) /* XXX Reset tty */
1204 {
1205 errorInCmd = 0;
Guido van Rossum3bbc62e1995-01-02 19:30:30 +00001206 PyErr_Restore (excInCmd, valInCmd, trbInCmd);
1207 excInCmd = valInCmd = trbInCmd = NULL;
Guido van Rossum18468821994-06-20 07:49:28 +00001208 PyErr_Print ();
1209 }
1210 if (tk_NumMainWindows > 0)
Guido van Rossume2ca9bd1994-08-03 08:01:43 +00001211 Tk_DoOneEvent (TK_DONT_WAIT);
Guido van Rossum18468821994-06-20 07:49:28 +00001212 return 0;
1213}
1214#endif /* WITH_READLINE */
1215
1216static void
Guido van Rossumd308e2b1994-07-07 09:25:12 +00001217Tkinter_Cleanup ()
1218{
Guido van Rossuma3c3f2c1995-02-07 15:41:02 +00001219/* This segfault with Tk 4.0 beta and seems unnecessary there as well */
1220#if TK_MAJOR_VERSION < 4
Guido van Rossumd308e2b1994-07-07 09:25:12 +00001221 /* XXX rl_deprep_terminal is static, damned! */
1222 while (tkMainWindowList != 0)
1223 Tk_DestroyWindow (tkMainWindowList->win);
Guido van Rossuma3c3f2c1995-02-07 15:41:02 +00001224#endif
Guido van Rossumd308e2b1994-07-07 09:25:12 +00001225}
1226
Guido van Rossum18468821994-06-20 07:49:28 +00001227void
1228PyInit_tkinter ()
1229{
Guido van Rossumd308e2b1994-07-07 09:25:12 +00001230 static inited = 0;
1231
Guido van Rossum18468821994-06-20 07:49:28 +00001232#ifdef WITH_READLINE
1233 extern int (*rl_event_hook) ();
1234#endif /* WITH_READLINE */
1235 PyObject *m, *d, *v;
1236
1237 m = Py_InitModule ("tkinter", moduleMethods);
1238
1239 d = PyModule_GetDict (m);
1240 Tkinter_TclError = Py_BuildValue ("s", "TclError");
1241 PyDict_SetItemString (d, "TclError", Tkinter_TclError);
1242
1243 v = Py_BuildValue ("i", TK_READABLE);
1244 PyDict_SetItemString (d, "READABLE", v);
1245 v = Py_BuildValue ("i", TK_WRITABLE);
1246 PyDict_SetItemString (d, "WRITABLE", v);
1247 v = Py_BuildValue ("i", TK_EXCEPTION);
1248 PyDict_SetItemString (d, "EXCEPTION", v);
Guido van Rossum062cfb01995-01-10 17:42:51 +00001249 v = Py_BuildValue ("i", TK_X_EVENTS);
1250 PyDict_SetItemString (d, "X_EVENTS", v);
1251 v = Py_BuildValue ("i", TK_FILE_EVENTS);
1252 PyDict_SetItemString (d, "FILE_EVENTS", v);
1253 v = Py_BuildValue ("i", TK_TIMER_EVENTS);
1254 PyDict_SetItemString (d, "TIMER_EVENTS", v);
1255 v = Py_BuildValue ("i", TK_IDLE_EVENTS);
1256 PyDict_SetItemString (d, "IDLE_EVENTS", v);
1257 v = Py_BuildValue ("i", TK_ALL_EVENTS);
1258 PyDict_SetItemString (d, "ALL_EVENTS", v);
1259 v = Py_BuildValue ("i", TK_DONT_WAIT);
1260 PyDict_SetItemString (d, "DONT_WAIT", v);
Guido van Rossuma3c3f2c1995-02-07 15:41:02 +00001261 v = Py_BuildValue ("s", TK_VERSION);
1262 PyDict_SetItemString (d, "TK_VERSION", v);
1263 v = Py_BuildValue ("s", TCL_VERSION);
1264 PyDict_SetItemString (d, "TCL_VERSION", v);
Guido van Rossum18468821994-06-20 07:49:28 +00001265
Guido van Rossum18468821994-06-20 07:49:28 +00001266#ifdef WITH_READLINE
1267 rl_event_hook = EventHook;
1268#endif /* WITH_READLINE */
1269
Guido van Rossumd308e2b1994-07-07 09:25:12 +00001270 if (!inited)
1271 {
1272 inited = 1;
Guido van Rossume4485b01994-09-07 14:32:49 +00001273 if (Py_AtExit (Tkinter_Cleanup) != 0)
1274 fprintf(stderr,
1275 "Tkinter: warning: cleanup procedure not registered\n");
Guido van Rossumd308e2b1994-07-07 09:25:12 +00001276 }
1277
Guido van Rossum18468821994-06-20 07:49:28 +00001278 if (PyErr_Occurred ())
1279 Py_FatalError ("can't initialize module tkinter");
1280}