1 /***********************************************************
2 Copyright (C) 1994 Steen Lumholt.
6 ******************************************************************/
8 /* _tkinter.c -- Interface to libtk.a and libtcl.a. */
10 /* TCL/TK VERSION INFO:
12 Only Tcl/Tk 8.2 and later are supported. Older versions are not
13 supported. (Use Python 2.2 if you cannot upgrade your Tcl/Tk
17 /* XXX Further speed-up ideas, involving Tcl 8.0 features:
19 - Register a new Tcl type, "Python callable", which can be called more
20 efficiently and passed to Tcl_EvalObj() directly (if this is possible).
40 /* Starting with Tcl 8.4, many APIs offer const-correctness. Unfortunately,
41 making _tkinter correct for this API means to break earlier
42 versions. USE_COMPAT_CONST allows to make _tkinter work with both 8.4 and
43 earlier versions. Once Tcl releases before 8.4 don't need to be supported
44 anymore, this should go. */
45 #define USE_COMPAT_CONST
47 /* If Tcl is compiled for threads, we must also define TCL_THREAD. We define
48 it always; if Tcl is not threaded, the thread functions in
60 /* For Tcl 8.2 and 8.3, CONST* is not defined. */
61 #ifndef CONST84_RETURN
62 #define CONST84_RETURN
66 #define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION)
68 #if TKMAJORMINOR < 8002
69 #error "Tk older than 8.2 not supported"
72 /* Unicode conversion assumes that Tcl_UniChar is two bytes.
73 We cannot test this directly, so we test UTF-8 size instead,
74 expecting that TCL_UTF_MAX is changed if Tcl ever supports
75 either UTF-16 or UCS-4. */
77 #error "unsupported Tcl configuration"
80 #if defined(macintosh)
81 /* Sigh, we have to include this to get at the tcl qd pointer */
83 /* And this one we need to clear the menu bar */
87 #if !(defined(MS_WINDOWS) || defined(__CYGWIN__) || defined(macintosh))
88 /* Mac has it, but it doesn't really work:-( */
89 #define HAVE_CREATEFILEHANDLER
92 #ifdef HAVE_CREATEFILEHANDLER
94 /* Tcl_CreateFileHandler() changed several times; these macros deal with the
95 messiness. In Tcl 8.0 and later, it is not available on Windows (and on
96 Unix, only because Jack added it back); when available on Windows, it only
97 applies to sockets. */
100 #define FHANDLETYPE TCL_WIN_SOCKET
102 #define FHANDLETYPE TCL_UNIX_FD
105 /* If Tcl can wait for a Unix file descriptor, define the EventHook() routine
106 which uses this to handle Tcl events while the user is typing commands. */
108 #if FHANDLETYPE == TCL_UNIX_FD
109 #define WAIT_FOR_STDIN
112 #endif /* HAVE_CREATEFILEHANDLER */
116 #define WAIT_FOR_STDIN
121 /* The threading situation is complicated. Tcl is not thread-safe, except
122 when configured with --enable-threads.
123 So we need to use a lock around all uses of Tcl. Previously, the Python
124 interpreter lock was used for this. However, this causes problems when
125 other Python threads need to run while Tcl is blocked waiting for events.
127 To solve this problem, a separate lock for Tcl is introduced. Holding it
128 is incompatible with holding Python's interpreter lock. The following four
129 macros manipulate both locks together.
131 ENTER_TCL and LEAVE_TCL are brackets, just like Py_BEGIN_ALLOW_THREADS and
132 Py_END_ALLOW_THREADS. They should be used whenever a call into Tcl is made
133 that could call an event handler, or otherwise affect the state of a Tcl
134 interpreter. These assume that the surrounding code has the Python
135 interpreter lock; inside the brackets, the Python interpreter lock has been
136 released and the lock for Tcl has been acquired.
138 Sometimes, it is necessary to have both the Python lock and the Tcl lock.
139 (For example, when transferring data from the Tcl interpreter result to a
140 Python string object.) This can be done by using different macros to close
141 the ENTER_TCL block: ENTER_OVERLAP reacquires the Python lock (and restores
142 the thread state) but doesn't release the Tcl lock; LEAVE_OVERLAP_TCL
143 releases the Tcl lock.
145 By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event
146 handlers when the handler needs to use Python. Such event handlers are
147 entered while the lock for Tcl is held; the event handler presumably needs
148 to use Python. ENTER_PYTHON releases the lock for Tcl and acquires
149 the Python interpreter lock, restoring the appropriate thread state, and
150 LEAVE_PYTHON releases the Python interpreter lock and re-acquires the lock
151 for Tcl. It is okay for ENTER_TCL/LEAVE_TCL pairs to be contained inside
152 the code between ENTER_PYTHON and LEAVE_PYTHON.
154 These locks expand to several statements and brackets; they should not be
155 used in branches of if statements and the like.
157 If Tcl is threaded, this approach won't work anymore. The Tcl interpreter is
158 only valid in the thread that created it, and all Tk activity must happen in this
159 thread, also. That means that the mainloop must be invoked in the thread that
160 created the interpreter. Invoking commands from other threads is possible;
161 _tkinter will queue an event for the interpreter thread, which will then
162 execute the command and pass back the result. If the main thread is not in the
163 mainloop, and invoking commands causes an exception; if the main loop is running
164 but not processing events, the command invocation will block.
166 In addition, for a threaded Tcl, a single global tcl_tstate won't be sufficient
167 anymore, since multiple Tcl interpreters may simultaneously dispatch in different
168 threads. So we use the Tcl TLS API.
172 static PyThread_type_lock tcl_lock
= 0;
175 static Tcl_ThreadDataKey state_key
;
176 typedef PyThreadState
*ThreadSpecificData
;
177 #define tcl_tstate (*(PyThreadState**)Tcl_GetThreadData(&state_key, sizeof(PyThreadState*)))
179 static PyThreadState
*tcl_tstate
= NULL
;
183 { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \
184 if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
187 tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
189 #define ENTER_OVERLAP \
192 #define LEAVE_OVERLAP_TCL \
193 tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); }
195 #define ENTER_PYTHON \
196 { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
197 if(tcl_lock)PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
199 #define LEAVE_PYTHON \
200 { PyThreadState *tstate = PyEval_SaveThread(); \
201 if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }
203 #define CHECK_TCL_APPARTMENT \
204 if (((TkappObject *)self)->threaded && \
205 ((TkappObject *)self)->thread_id != Tcl_GetCurrentThread()) { \
206 PyErr_SetString(PyExc_RuntimeError, "Calling Tcl from different appartment"); \
214 #define ENTER_OVERLAP
215 #define LEAVE_OVERLAP_TCL
218 #define CHECK_TCL_APPARTMENT
225 ** Additional cruft needed by Tcl/Tk on the Mac.
226 ** This is for Tcl 7.5 and Tk 4.1 (patch release 1).
229 /* ckfree() expects a char* */
230 #define FREECAST (char *)
232 #include <Events.h> /* For EventRecord */
234 typedef int (*TclMacConvertEventPtr
) (EventRecord
*eventPtr
);
235 void Tcl_MacSetEventProc(TclMacConvertEventPtr procPtr
);
236 int TkMacConvertEvent(EventRecord
*eventPtr
);
238 static int PyMacConvertEvent(EventRecord
*eventPtr
);
241 extern int SIOUXIsAppWindow(WindowPtr
);
243 #endif /* macintosh */
246 #define FREECAST (char *)
249 /**** Tkapp Object Declaration ****/
251 static PyTypeObject Tkapp_Type
;
257 int threaded
; /* True if tcl_platform[threaded] */
258 Tcl_ThreadId thread_id
;
260 /* We cannot include tclInt.h, as this is internal.
261 So we cache interesting types here. */
262 Tcl_ObjType
*BooleanType
;
263 Tcl_ObjType
*ByteArrayType
;
264 Tcl_ObjType
*DoubleType
;
265 Tcl_ObjType
*IntType
;
266 Tcl_ObjType
*ListType
;
267 Tcl_ObjType
*ProcBodyType
;
268 Tcl_ObjType
*StringType
;
271 #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type)
272 #define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
273 #define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v))
275 #define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \
276 (void *) v, ((PyObject *) v)->ob_refcnt))
280 /**** Error Handling ****/
282 static PyObject
*Tkinter_TclError
;
283 static int quitMainLoop
= 0;
284 static int errorInCmd
= 0;
285 static PyObject
*excInCmd
;
286 static PyObject
*valInCmd
;
287 static PyObject
*trbInCmd
;
292 Tkinter_Error(PyObject
*v
)
294 PyErr_SetString(Tkinter_TclError
, Tkapp_Result(v
));
305 /* Millisecond sleep() for Unix platforms. */
310 /* XXX Too bad if you don't have select(). */
312 t
.tv_sec
= milli
/1000;
313 t
.tv_usec
= (milli
%1000) * 1000;
314 select(0, (fd_set
*)0, (fd_set
*)0, (fd_set
*)0, &t
);
316 #endif /* MS_WINDOWS */
317 #endif /* WITH_THREAD */
319 /* Wait up to 1s for the mainloop to come up. */
322 WaitForMainloop(TkappObject
* self
)
325 for (i
= 0; i
< 10; i
++) {
326 if (self
->dispatching
)
328 Py_BEGIN_ALLOW_THREADS
332 if (self
->dispatching
)
334 PyErr_SetString(PyExc_RuntimeError
, "main thread is not in main loop");
340 AsString(PyObject
*value
, PyObject
*tmp
)
342 if (PyString_Check(value
))
343 return PyString_AsString(value
);
344 #ifdef Py_USING_UNICODE
345 else if (PyUnicode_Check(value
)) {
346 PyObject
*v
= PyUnicode_AsUTF8String(value
);
349 if (PyList_Append(tmp
, v
) != 0) {
354 return PyString_AsString(v
);
358 PyObject
*v
= PyObject_Str(value
);
361 if (PyList_Append(tmp
, v
) != 0) {
366 return PyString_AsString(v
);
375 Merge(PyObject
*args
)
377 PyObject
*tmp
= NULL
;
378 char *argvStore
[ARGSZ
];
382 int argc
= 0, fvc
= 0, i
;
385 if (!(tmp
= PyList_New(0)))
394 else if (!PyTuple_Check(args
)) {
397 if (!(argv
[0] = AsString(args
, tmp
)))
401 argc
= PyTuple_Size(args
);
404 argv
= (char **)ckalloc(argc
* sizeof(char *));
405 fv
= (int *)ckalloc(argc
* sizeof(int));
406 if (argv
== NULL
|| fv
== NULL
) {
412 for (i
= 0; i
< argc
; i
++) {
413 PyObject
*v
= PyTuple_GetItem(args
, i
);
414 if (PyTuple_Check(v
)) {
416 if (!(argv
[i
] = Merge(v
)))
420 else if (v
== Py_None
) {
426 if (!(argv
[i
] = AsString(v
, tmp
)))
432 res
= Tcl_Merge(argc
, argv
);
434 PyErr_SetString(Tkinter_TclError
, "merge failed");
437 for (i
= 0; i
< fvc
; i
++)
441 if (argv
!= argvStore
)
442 ckfree(FREECAST argv
);
464 if (Tcl_SplitList((Tcl_Interp
*)NULL
, list
, &argc
, &argv
) != TCL_OK
) {
466 * Could be a quoted string containing funnies, e.g. {"}.
467 * Return the string itself.
469 return PyString_FromString(list
);
473 v
= PyString_FromString("");
475 v
= PyString_FromString(argv
[0]);
476 else if ((v
= PyTuple_New(argc
)) != NULL
) {
480 for (i
= 0; i
< argc
; i
++) {
481 if ((w
= Split(argv
[i
])) == NULL
) {
486 PyTuple_SetItem(v
, i
, w
);
489 Tcl_Free(FREECAST argv
);
493 /* In some cases, Tcl will still return strings that are supposed to be
494 lists. SplitObj walks through a nested tuple, finding string objects that
498 SplitObj(PyObject
*arg
)
500 if (PyTuple_Check(arg
)) {
502 PyObject
*elem
, *newelem
, *result
;
504 size
= PyTuple_Size(arg
);
506 /* Recursively invoke SplitObj for all tuple items.
507 If this does not return a new object, no action is
509 for(i
= 0; i
< size
; i
++) {
510 elem
= PyTuple_GetItem(arg
, i
);
511 newelem
= SplitObj(elem
);
518 if (newelem
== elem
) {
522 result
= PyTuple_New(size
);
525 for(k
= 0; k
< i
; k
++) {
526 elem
= PyTuple_GetItem(arg
, k
);
528 PyTuple_SetItem(result
, k
, elem
);
531 PyTuple_SetItem(result
, i
, newelem
);
535 /* Fall through, returning arg. */
537 else if (PyString_Check(arg
)) {
540 char *list
= PyString_AsString(arg
);
542 if (Tcl_SplitList((Tcl_Interp
*)NULL
, list
, &argc
, &argv
) != TCL_OK
) {
546 Tcl_Free(FREECAST argv
);
548 return Split(PyString_AsString(arg
));
549 /* Fall through, returning arg. */
556 /**** Tkapp Object ****/
560 Tcl_AppInit(Tcl_Interp
*interp
)
564 main
= Tk_MainWindow(interp
);
565 if (Tcl_Init(interp
) == TCL_ERROR
) {
566 PySys_WriteStderr("Tcl_Init error: %s\n", Tcl_GetStringResult(interp
));
569 if (Tk_Init(interp
) == TCL_ERROR
) {
570 PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp
));
575 #endif /* !WITH_APPINIT */
580 /* Initialize the Tk application; see the `main' function in
584 static void EnableEventHook(void); /* Forward */
585 static void DisableEventHook(void); /* Forward */
588 Tkapp_New(char *screenName
, char *baseName
, char *className
,
589 int interactive
, int wantobjects
)
594 v
= PyObject_New(TkappObject
, &Tkapp_Type
);
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();
607 PyErr_SetString(PyExc_RuntimeError
, "Tcl is threaded but _tkinter is not");
612 if (v
->threaded
&& tcl_lock
) {
613 /* If Tcl is threaded, we don't need the lock. */
614 PyThread_free_lock(tcl_lock
);
618 v
->BooleanType
= Tcl_GetObjType("boolean");
619 v
->ByteArrayType
= Tcl_GetObjType("bytearray");
620 v
->DoubleType
= Tcl_GetObjType("double");
621 v
->IntType
= Tcl_GetObjType("int");
622 v
->ListType
= Tcl_GetObjType("list");
623 v
->ProcBodyType
= Tcl_GetObjType("procbody");
624 v
->StringType
= Tcl_GetObjType("string");
626 #if defined(macintosh)
627 /* This seems to be needed */
629 TkMacInitMenus(v
->interp
);
632 /* Delete the 'exit' command, which can screw things up */
633 Tcl_DeleteCommand(v
->interp
, "exit");
635 if (screenName
!= NULL
)
636 Tcl_SetVar2(v
->interp
, "env", "DISPLAY",
637 screenName
, TCL_GLOBAL_ONLY
);
640 Tcl_SetVar(v
->interp
, "tcl_interactive", "1", TCL_GLOBAL_ONLY
);
642 Tcl_SetVar(v
->interp
, "tcl_interactive", "0", TCL_GLOBAL_ONLY
);
644 /* This is used to get the application class for Tk 4.1 and up */
645 argv0
= (char*)ckalloc(strlen(className
) + 1);
652 strcpy(argv0
, className
);
653 if (isupper((int)(argv0
[0])))
654 argv0
[0] = tolower(argv0
[0]);
655 Tcl_SetVar(v
->interp
, "argv0", argv0
, TCL_GLOBAL_ONLY
);
658 if (Tcl_AppInit(v
->interp
) != TCL_OK
)
659 return (TkappObject
*)Tkinter_Error((PyObject
*)v
);
668 Tkapp_ThreadSend(TkappObject
*self
, Tcl_Event
*ev
,
669 Tcl_Condition
*cond
, Tcl_Mutex
*mutex
)
671 Py_BEGIN_ALLOW_THREADS
;
672 Tcl_MutexLock(mutex
);
673 Tcl_ThreadQueueEvent(self
->thread_id
, ev
, TCL_QUEUE_TAIL
);
674 Tcl_ThreadAlert(self
->thread_id
);
675 Tcl_ConditionWait(cond
, mutex
, NULL
);
676 Tcl_MutexUnlock(mutex
);
688 staticforward PyTypeObject PyTclObject_Type
;
689 #define PyTclObject_Check(v) ((v)->ob_type == &PyTclObject_Type)
692 newPyTclObject(Tcl_Obj
*arg
)
695 self
= PyObject_New(PyTclObject
, &PyTclObject_Type
);
698 Tcl_IncrRefCount(arg
);
700 return (PyObject
*)self
;
704 PyTclObject_dealloc(PyTclObject
*self
)
706 Tcl_DecrRefCount(self
->value
);
711 PyTclObject_str(PyTclObject
*self
)
713 return PyString_FromString(Tcl_GetString(self
->value
));
717 PyTclObject_repr(PyTclObject
*self
)
720 PyOS_snprintf(buf
, 50, "<%s object at 0x%.8x>",
721 self
->value
->typePtr
->name
, (int)self
->value
);
722 return PyString_FromString(buf
);
726 get_typename(PyTclObject
* obj
, void* ignored
)
728 return PyString_FromString(obj
->value
->typePtr
->name
);
731 static PyGetSetDef PyTclObject_getsetlist
[] = {
732 {"typename", (getter
)get_typename
, NULL
, "name of the Tcl type"},
736 statichere PyTypeObject PyTclObject_Type
= {
737 PyObject_HEAD_INIT(NULL
)
739 "_tkinter.Tcl_Obj", /*tp_name*/
740 sizeof(PyTclObject
), /*tp_basicsize*/
743 (destructor
)PyTclObject_dealloc
, /*tp_dealloc*/
748 (reprfunc
)PyTclObject_repr
, /*tp_repr*/
750 0, /*tp_as_sequence*/
754 (reprfunc
)PyTclObject_str
, /*tp_str*/
755 PyObject_GenericGetAttr
,/*tp_getattro*/
758 Py_TPFLAGS_DEFAULT
, /*tp_flags*/
762 0, /*tp_richcompare*/
763 0, /*tp_weaklistoffset*/
768 PyTclObject_getsetlist
, /*tp_getset*/
782 AsObj(PyObject
*value
)
786 if (PyString_Check(value
))
787 return Tcl_NewStringObj(PyString_AS_STRING(value
),
788 PyString_GET_SIZE(value
));
789 else if (PyInt_Check(value
))
790 return Tcl_NewLongObj(PyInt_AS_LONG(value
));
791 else if (PyFloat_Check(value
))
792 return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value
));
793 else if (PyTuple_Check(value
)) {
794 Tcl_Obj
**argv
= (Tcl_Obj
**)
795 ckalloc(PyTuple_Size(value
)*sizeof(Tcl_Obj
*));
799 for(i
=0;i
<PyTuple_Size(value
);i
++)
800 argv
[i
] = AsObj(PyTuple_GetItem(value
,i
));
801 result
= Tcl_NewListObj(PyTuple_Size(value
), argv
);
802 ckfree(FREECAST argv
);
805 #ifdef Py_USING_UNICODE
806 else if (PyUnicode_Check(value
)) {
807 Py_UNICODE
*inbuf
= PyUnicode_AS_UNICODE(value
);
808 int size
= PyUnicode_GET_SIZE(value
);
809 /* This #ifdef assumes that Tcl uses UCS-2.
810 See TCL_UTF_MAX test above. */
811 #ifdef Py_UNICODE_WIDE
814 outbuf
= (Tcl_UniChar
*)ckalloc(size
* sizeof(Tcl_UniChar
));
819 for (i
= 0; i
< size
; i
++) {
820 if (inbuf
[i
] >= 0x10000) {
821 /* Tcl doesn't do UTF-16, yet. */
822 PyErr_SetString(PyExc_ValueError
,
823 "unsupported character");
824 ckfree(FREECAST outbuf
);
827 outbuf
[i
] = inbuf
[i
];
829 result
= Tcl_NewUnicodeObj(outbuf
, size
);
830 ckfree(FREECAST outbuf
);
833 return Tcl_NewUnicodeObj(inbuf
, size
);
838 else if(PyTclObject_Check(value
)) {
839 Tcl_Obj
*v
= ((PyTclObject
*)value
)->value
;
844 PyObject
*v
= PyObject_Str(value
);
854 FromObj(PyObject
* tkapp
, Tcl_Obj
*value
)
856 PyObject
*result
= NULL
;
857 TkappObject
*app
= (TkappObject
*)tkapp
;
859 if (value
->typePtr
== NULL
) {
860 /* If the result contains any bytes with the top bit set,
861 it's UTF-8 and we should decode it to Unicode */
862 #ifdef Py_USING_UNICODE
864 char *s
= value
->bytes
;
865 int len
= value
->length
;
866 for (i
= 0; i
< len
; i
++) {
867 if (value
->bytes
[i
] & 0x80)
871 if (i
== value
->length
)
872 result
= PyString_FromStringAndSize(s
, len
);
874 /* Convert UTF-8 to Unicode string */
875 result
= PyUnicode_DecodeUTF8(s
, len
, "strict");
876 if (result
== NULL
) {
878 result
= PyString_FromStringAndSize(s
, len
);
882 res
= PyString_FromStringAndSize(value
->bytes
, value
->length
);
887 if (value
->typePtr
== app
->BooleanType
) {
888 result
= value
->internalRep
.longValue
? Py_True
: Py_False
;
893 if (value
->typePtr
== app
->ByteArrayType
) {
895 char *data
= (char*)Tcl_GetByteArrayFromObj(value
, &size
);
896 return PyString_FromStringAndSize(data
, size
);
899 if (value
->typePtr
== app
->DoubleType
) {
900 return PyFloat_FromDouble(value
->internalRep
.doubleValue
);
903 if (value
->typePtr
== app
->IntType
) {
904 return PyInt_FromLong(value
->internalRep
.longValue
);
907 if (value
->typePtr
== app
->ListType
) {
913 status
= Tcl_ListObjLength(Tkapp_Interp(tkapp
), value
, &size
);
914 if (status
== TCL_ERROR
)
915 return Tkinter_Error(tkapp
);
916 result
= PyTuple_New(size
);
919 for (i
= 0; i
< size
; i
++) {
920 status
= Tcl_ListObjIndex(Tkapp_Interp(tkapp
),
921 value
, i
, &tcl_elem
);
922 if (status
== TCL_ERROR
) {
924 return Tkinter_Error(tkapp
);
926 elem
= FromObj(tkapp
, tcl_elem
);
931 PyTuple_SetItem(result
, i
, elem
);
936 if (value
->typePtr
== app
->ProcBodyType
) {
937 /* fall through: return tcl object. */
940 if (value
->typePtr
== app
->StringType
) {
941 #ifdef Py_USING_UNICODE
942 #ifdef Py_UNICODE_WIDE
948 size
= Tcl_GetCharLength(value
);
949 result
= PyUnicode_FromUnicode(NULL
, size
);
952 input
= Tcl_GetUnicode(value
);
953 output
= PyUnicode_AS_UNICODE(result
);
955 *output
++ = *input
++;
958 return PyUnicode_FromUnicode(Tcl_GetUnicode(value
),
959 Tcl_GetCharLength(value
));
964 c
= Tcl_GetStringFromObj(value
, &size
);
965 return PyString_FromStringAndSize(c
, size
);
969 return newPyTclObject(value
);
972 /* This mutex synchronizes inter-thread command calls. */
974 TCL_DECLARE_MUTEX(call_mutex
)
976 typedef struct Tkapp_CallEvent
{
977 Tcl_Event ev
; /* Must be first */
982 PyObject
**exc_type
, **exc_value
, **exc_tb
;
987 Tkapp_CallDeallocArgs(Tcl_Obj
** objv
, Tcl_Obj
** objStore
, int objc
)
990 for (i
= 0; i
< objc
; i
++)
991 Tcl_DecrRefCount(objv
[i
]);
992 if (objv
!= objStore
)
993 ckfree(FREECAST objv
);
996 /* Convert Python objects to Tcl objects. This must happen in the
997 interpreter thread, which may or may not be the calling thread. */
1000 Tkapp_CallArgs(PyObject
*args
, Tcl_Obj
** objStore
, int *pobjc
)
1002 Tcl_Obj
**objv
= objStore
;
1007 else if (!PyTuple_Check(args
)) {
1008 objv
[0] = AsObj(args
);
1012 Tcl_IncrRefCount(objv
[0]);
1015 objc
= PyTuple_Size(args
);
1018 objv
= (Tcl_Obj
**)ckalloc(objc
* sizeof(char *));
1026 for (i
= 0; i
< objc
; i
++) {
1027 PyObject
*v
= PyTuple_GetItem(args
, i
);
1034 /* Reset objc, so it attempts to clear
1035 objects only up to i. */
1039 Tcl_IncrRefCount(objv
[i
]);
1045 Tkapp_CallDeallocArgs(objv
, objStore
, objc
);
1049 /* Convert the results of a command call into a Python objects. */
1052 Tkapp_CallResult(TkappObject
*self
)
1054 PyObject
*res
= NULL
;
1055 if(self
->wantobjects
) {
1056 Tcl_Obj
*value
= Tcl_GetObjResult(self
->interp
);
1057 /* Not sure whether the IncrRef is necessary, but something
1058 may overwrite the interpreter result while we are
1060 Tcl_IncrRefCount(value
);
1061 res
= FromObj((PyObject
*)self
, value
);
1062 Tcl_DecrRefCount(value
);
1064 const char *s
= Tcl_GetStringResult(self
->interp
);
1067 /* If the result contains any bytes with the top bit set,
1068 it's UTF-8 and we should decode it to Unicode */
1069 #ifdef Py_USING_UNICODE
1070 while (*p
!= '\0') {
1077 res
= PyString_FromStringAndSize(s
, (int)(p
-s
));
1079 /* Convert UTF-8 to Unicode string */
1080 p
= strchr(p
, '\0');
1081 res
= PyUnicode_DecodeUTF8(s
, (int)(p
-s
), "strict");
1084 res
= PyString_FromStringAndSize(s
, (int)(p
-s
));
1088 p
= strchr(p
, '\0');
1089 res
= PyString_FromStringAndSize(s
, (int)(p
-s
));
1095 /* Tkapp_CallProc is the event procedure that is executed in the context of
1096 the Tcl interpreter thread. Initially, it holds the Tcl lock, and doesn't
1097 hold the Python lock. */
1100 Tkapp_CallProc(Tkapp_CallEvent
*e
, int flags
)
1102 Tcl_Obj
*objStore
[ARGSZ
];
1107 objv
= Tkapp_CallArgs(e
->args
, objStore
, &objc
);
1109 PyErr_Fetch(e
->exc_type
, e
->exc_value
, e
->exc_tb
);
1115 i
= Tcl_EvalObjv(e
->self
->interp
, objc
, objv
, e
->flags
);
1117 if (i
== TCL_ERROR
) {
1119 *(e
->exc_type
) = NULL
;
1120 *(e
->exc_tb
) = NULL
;
1121 *(e
->exc_value
) = PyObject_CallFunction(
1122 Tkinter_TclError
, "s",
1123 Tcl_GetStringResult(e
->self
->interp
));
1126 *(e
->res
) = Tkapp_CallResult(e
->self
);
1130 /* Wake up calling thread. */
1131 Tcl_MutexLock(&call_mutex
);
1132 Tcl_ConditionNotify(&e
->done
);
1133 Tcl_MutexUnlock(&call_mutex
);
1137 /* This is the main entry point for calling a Tcl command.
1138 It supports three cases, with regard to threading:
1139 1. Tcl is not threaded: Must have the Tcl lock, then can invoke command in
1140 the context of the calling thread.
1141 2. Tcl is threaded, caller of the command is in the interpreter thread:
1142 Execute the command in the calling thread. Since the Tcl lock will
1143 not be used, we can merge that with case 1.
1144 3. Tcl is threaded, caller is in a different thread: Must queue an event to
1145 the interpreter thread. Allocation of Tcl objects needs to occur in the
1146 interpreter thread, so we ship the PyObject* args to the target thread,
1147 and perform processing there. */
1150 Tkapp_Call(PyObject
*_self
, PyObject
*args
)
1152 Tcl_Obj
*objStore
[ARGSZ
];
1153 Tcl_Obj
**objv
= NULL
;
1155 PyObject
*res
= NULL
;
1156 TkappObject
*self
= (TkappObject
*)_self
;
1157 /* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */
1158 int flags
= TCL_EVAL_DIRECT
;
1160 if (self
->threaded
&& self
->thread_id
!= Tcl_GetCurrentThread()) {
1161 /* We cannot call the command directly. Instead, we must
1162 marshal the parameters to the interpreter thread. */
1163 Tkapp_CallEvent
*ev
;
1164 PyObject
*exc_type
, *exc_value
, *exc_tb
;
1165 if (!WaitForMainloop(self
))
1167 ev
= (Tkapp_CallEvent
*)ckalloc(sizeof(Tkapp_CallEvent
));
1168 ev
->ev
.proc
= (Tcl_EventProc
*)Tkapp_CallProc
;
1172 ev
->exc_type
= &exc_type
;
1173 ev
->exc_value
= &exc_value
;
1174 ev
->exc_tb
= &exc_tb
;
1175 ev
->done
= (Tcl_Condition
)0;
1177 Tkapp_ThreadSend(self
, (Tcl_Event
*)ev
, &ev
->done
, &call_mutex
);
1181 PyErr_Restore(exc_type
, exc_value
, exc_tb
);
1183 PyErr_SetObject(Tkinter_TclError
, exc_value
);
1188 objv
= Tkapp_CallArgs(args
, objStore
, &objc
);
1194 i
= Tcl_EvalObjv(self
->interp
, objc
, objv
, flags
);
1199 Tkinter_Error(_self
);
1201 res
= Tkapp_CallResult(self
);
1205 Tkapp_CallDeallocArgs(objv
, objStore
, objc
);
1212 Tkapp_GlobalCall(PyObject
*self
, PyObject
*args
)
1214 /* Could do the same here as for Tkapp_Call(), but this is not used
1215 much, so I can't be bothered. Unfortunately Tcl doesn't export a
1216 way for the user to do what all its Global* variants do (save and
1217 reset the scope pointer, call the local version, restore the saved
1221 PyObject
*res
= NULL
;
1223 CHECK_TCL_APPARTMENT
;
1229 err
= Tcl_GlobalEval(Tkapp_Interp(self
), cmd
);
1231 if (err
== TCL_ERROR
)
1232 res
= Tkinter_Error(self
);
1234 res
= PyString_FromString(Tkapp_Result(self
));
1243 Tkapp_Eval(PyObject
*self
, PyObject
*args
)
1246 PyObject
*res
= NULL
;
1249 if (!PyArg_ParseTuple(args
, "s:eval", &script
))
1252 CHECK_TCL_APPARTMENT
;
1255 err
= Tcl_Eval(Tkapp_Interp(self
), script
);
1257 if (err
== TCL_ERROR
)
1258 res
= Tkinter_Error(self
);
1260 res
= PyString_FromString(Tkapp_Result(self
));
1266 Tkapp_GlobalEval(PyObject
*self
, PyObject
*args
)
1269 PyObject
*res
= NULL
;
1272 if (!PyArg_ParseTuple(args
, "s:globaleval", &script
))
1275 CHECK_TCL_APPARTMENT
;
1278 err
= Tcl_GlobalEval(Tkapp_Interp(self
), script
);
1280 if (err
== TCL_ERROR
)
1281 res
= Tkinter_Error(self
);
1283 res
= PyString_FromString(Tkapp_Result(self
));
1289 Tkapp_EvalFile(PyObject
*self
, PyObject
*args
)
1292 PyObject
*res
= NULL
;
1295 if (!PyArg_ParseTuple(args
, "s:evalfile", &fileName
))
1298 CHECK_TCL_APPARTMENT
;
1301 err
= Tcl_EvalFile(Tkapp_Interp(self
), fileName
);
1303 if (err
== TCL_ERROR
)
1304 res
= Tkinter_Error(self
);
1307 res
= PyString_FromString(Tkapp_Result(self
));
1313 Tkapp_Record(PyObject
*self
, PyObject
*args
)
1316 PyObject
*res
= NULL
;
1319 if (!PyArg_ParseTuple(args
, "s", &script
))
1322 CHECK_TCL_APPARTMENT
;
1325 err
= Tcl_RecordAndEval(Tkapp_Interp(self
), script
, TCL_NO_EVAL
);
1327 if (err
== TCL_ERROR
)
1328 res
= Tkinter_Error(self
);
1330 res
= PyString_FromString(Tkapp_Result(self
));
1336 Tkapp_AddErrorInfo(PyObject
*self
, PyObject
*args
)
1340 if (!PyArg_ParseTuple(args
, "s:adderrorinfo", &msg
))
1342 CHECK_TCL_APPARTMENT
;
1345 Tcl_AddErrorInfo(Tkapp_Interp(self
), msg
);
1354 /** Tcl Variable **/
1356 TCL_DECLARE_MUTEX(var_mutex
)
1358 typedef CONST84_RETURN
char* (*EventFunc1
)(Tcl_Interp
*, CONST
char*, int);
1359 typedef CONST84_RETURN
char* (*EventFunc2
)(Tcl_Interp
*, CONST
char*, CONST
char*, int);
1360 typedef CONST84_RETURN
char* (*EventFunc3
)(Tcl_Interp
*, CONST
char*, CONST
char*, CONST
char*, int);
1361 typedef struct VarEvent
{
1362 Tcl_Event ev
; /* must be first */
1378 var_perform(VarEvent
*ev
)
1380 if (!ev
->arg2
&& !ev
->arg2
)
1381 return ev
->func1(ev
->self
->interp
, ev
->arg1
, ev
->flags
);
1383 return ev
->func2(ev
->self
->interp
, ev
->arg1
,
1384 ev
->arg2
, ev
->flags
);
1385 return ev
->func3(ev
->self
->interp
, ev
->arg1
, ev
->arg2
,
1386 ev
->arg3
, ev
->flags
);
1390 var_fill_result(VarEvent
*ev
, const char* res
)
1392 if (ev
->coderesult
) {
1393 if ((int)res
!= TCL_ERROR
) {
1395 *(ev
->res
) = Py_None
;
1400 *(ev
->res
) = PyString_FromString(res
);
1405 *(ev
->exc
) = PyObject_CallFunction(
1406 Tkinter_TclError
, "s",
1407 Tcl_GetStringResult(ev
->self
->interp
));
1412 var_proc(VarEvent
* ev
, int flags
)
1414 const char *result
= var_perform(ev
);
1416 var_fill_result(ev
, result
);
1417 Tcl_MutexLock(&var_mutex
);
1418 Tcl_ConditionNotify(&ev
->cond
);
1419 Tcl_MutexUnlock(&var_mutex
);
1425 var_invoke(PyObject
*_self
, char* arg1
, char* arg2
, char* arg3
, int flags
,
1426 EventFunc1 func1
, EventFunc2 func2
, EventFunc3 func3
,
1430 TkappObject
*self
= (TkappObject
*)_self
;
1431 VarEvent
*ev
= self
->threaded
?
1432 (VarEvent
*)ckalloc(sizeof(VarEvent
)) : &_ev
;
1433 PyObject
*res
, *exc
;
1443 ev
->coderesult
= coderesult
;
1446 if (self
->threaded
&& self
->thread_id
!= Tcl_GetCurrentThread()) {
1447 /* The current thread is not the interpreter thread. Marshal
1448 the call to the interpreter thread, then wait for
1451 if (!WaitForMainloop(self
))
1454 ev
->ev
.proc
= (Tcl_EventProc
*)var_proc
;
1455 Tkapp_ThreadSend(self
, (Tcl_Event
*)ev
, &ev
->cond
, &var_mutex
);
1458 /* Tcl is not threaded, or this is the interpreter thread. To
1459 perform the call, we must hold the TCL lock. To receive the
1460 results, we must also hold the Python lock. */
1463 result
= var_perform(ev
);
1465 var_fill_result(ev
, result
);
1469 PyErr_SetObject(Tkinter_TclError
, exc
);
1476 var_invoke2(PyObject
*_self
, char* arg1
, char* arg2
, char* arg3
, int flags
,
1477 int (*func1
)(Tcl_Interp
*, CONST
char*, int),
1478 int (*func2
)(Tcl_Interp
*, CONST
char*, CONST
char*, int),
1479 int (*func3
)(Tcl_Interp
*, CONST
char*, CONST
char*, CONST
char*, int))
1481 return var_invoke(_self
, arg1
, arg2
, arg3
, flags
,
1482 (EventFunc1
)func1
, (EventFunc2
)func2
,
1483 (EventFunc3
)func3
, 1);
1487 SetVar(PyObject
*self
, PyObject
*args
, int flags
)
1489 char *name1
, *name2
, *s
;
1494 tmp
= PyList_New(0);
1498 if (PyArg_ParseTuple(args
, "sO:setvar", &name1
, &newValue
)) {
1500 s
= AsString(newValue
, tmp
);
1503 res
= var_invoke(self
, name1
, s
, NULL
, flags
,
1504 NULL
, Tcl_SetVar
, NULL
, 0);
1508 if (PyArg_ParseTuple(args
, "ssO:setvar",
1509 &name1
, &name2
, &newValue
)) {
1510 s
= AsString(newValue
, tmp
);
1513 res
= var_invoke(self
, name1
, name2
, s
, flags
,
1514 NULL
, NULL
, Tcl_SetVar2
, 0);
1532 Tkapp_SetVar(PyObject
*self
, PyObject
*args
)
1534 return SetVar(self
, args
, TCL_LEAVE_ERR_MSG
);
1538 Tkapp_GlobalSetVar(PyObject
*self
, PyObject
*args
)
1540 return SetVar(self
, args
, TCL_LEAVE_ERR_MSG
| TCL_GLOBAL_ONLY
);
1546 GetVar(PyObject
*self
, PyObject
*args
, int flags
)
1548 char *name1
, *name2
=NULL
;
1549 PyObject
*res
= NULL
;
1551 if (!PyArg_ParseTuple(args
, "s|s:getvar", &name1
, &name2
))
1554 res
= var_invoke(self
, name1
, name2
, NULL
, flags
,
1555 Tcl_GetVar
, Tcl_GetVar2
, NULL
, 0);
1560 Tkapp_GetVar(PyObject
*self
, PyObject
*args
)
1562 return GetVar(self
, args
, TCL_LEAVE_ERR_MSG
);
1566 Tkapp_GlobalGetVar(PyObject
*self
, PyObject
*args
)
1568 return GetVar(self
, args
, TCL_LEAVE_ERR_MSG
| TCL_GLOBAL_ONLY
);
1574 UnsetVar(PyObject
*self
, PyObject
*args
, int flags
)
1576 char *name1
, *name2
=NULL
;
1577 PyObject
*res
= NULL
;
1579 if (!PyArg_ParseTuple(args
, "s|s:unsetvar", &name1
, &name2
))
1582 res
= var_invoke2(self
, name1
, name2
, NULL
, flags
,
1583 Tcl_UnsetVar
, Tcl_UnsetVar2
, NULL
);
1588 Tkapp_UnsetVar(PyObject
*self
, PyObject
*args
)
1590 return UnsetVar(self
, args
, TCL_LEAVE_ERR_MSG
);
1594 Tkapp_GlobalUnsetVar(PyObject
*self
, PyObject
*args
)
1596 return UnsetVar(self
, args
, TCL_LEAVE_ERR_MSG
| TCL_GLOBAL_ONLY
);
1601 /** Tcl to Python **/
1604 Tkapp_GetInt(PyObject
*self
, PyObject
*args
)
1609 if (PyTuple_Size(args
) == 1) {
1610 PyObject
* o
= PyTuple_GetItem(args
, 0);
1611 if (PyInt_Check(o
)) {
1616 if (!PyArg_ParseTuple(args
, "s:getint", &s
))
1618 if (Tcl_GetInt(Tkapp_Interp(self
), s
, &v
) == TCL_ERROR
)
1619 return Tkinter_Error(self
);
1620 return Py_BuildValue("i", v
);
1624 Tkapp_GetDouble(PyObject
*self
, PyObject
*args
)
1629 if (PyTuple_Size(args
) == 1) {
1630 PyObject
*o
= PyTuple_GetItem(args
, 0);
1631 if (PyFloat_Check(o
)) {
1636 if (!PyArg_ParseTuple(args
, "s:getdouble", &s
))
1638 if (Tcl_GetDouble(Tkapp_Interp(self
), s
, &v
) == TCL_ERROR
)
1639 return Tkinter_Error(self
);
1640 return Py_BuildValue("d", v
);
1644 Tkapp_GetBoolean(PyObject
*self
, PyObject
*args
)
1649 if (PyTuple_Size(args
) == 1) {
1650 PyObject
*o
= PyTuple_GetItem(args
, 0);
1651 if (PyInt_Check(o
)) {
1656 if (!PyArg_ParseTuple(args
, "s:getboolean", &s
))
1658 if (Tcl_GetBoolean(Tkapp_Interp(self
), s
, &v
) == TCL_ERROR
)
1659 return Tkinter_Error(self
);
1660 return Py_BuildValue("i", v
);
1664 Tkapp_ExprString(PyObject
*self
, PyObject
*args
)
1667 PyObject
*res
= NULL
;
1670 if (!PyArg_ParseTuple(args
, "s:exprstring", &s
))
1673 CHECK_TCL_APPARTMENT
;
1676 retval
= Tcl_ExprString(Tkapp_Interp(self
), s
);
1678 if (retval
== TCL_ERROR
)
1679 res
= Tkinter_Error(self
);
1681 res
= Py_BuildValue("s", Tkapp_Result(self
));
1687 Tkapp_ExprLong(PyObject
*self
, PyObject
*args
)
1690 PyObject
*res
= NULL
;
1694 if (!PyArg_ParseTuple(args
, "s:exprlong", &s
))
1697 CHECK_TCL_APPARTMENT
;
1700 retval
= Tcl_ExprLong(Tkapp_Interp(self
), s
, &v
);
1702 if (retval
== TCL_ERROR
)
1703 res
= Tkinter_Error(self
);
1705 res
= Py_BuildValue("l", v
);
1711 Tkapp_ExprDouble(PyObject
*self
, PyObject
*args
)
1714 PyObject
*res
= NULL
;
1718 if (!PyArg_ParseTuple(args
, "s:exprdouble", &s
))
1720 CHECK_TCL_APPARTMENT
;
1721 PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
1723 retval
= Tcl_ExprDouble(Tkapp_Interp(self
), s
, &v
);
1725 PyFPE_END_PROTECT(retval
)
1726 if (retval
== TCL_ERROR
)
1727 res
= Tkinter_Error(self
);
1729 res
= Py_BuildValue("d", v
);
1735 Tkapp_ExprBoolean(PyObject
*self
, PyObject
*args
)
1738 PyObject
*res
= NULL
;
1742 if (!PyArg_ParseTuple(args
, "s:exprboolean", &s
))
1744 CHECK_TCL_APPARTMENT
;
1746 retval
= Tcl_ExprBoolean(Tkapp_Interp(self
), s
, &v
);
1748 if (retval
== TCL_ERROR
)
1749 res
= Tkinter_Error(self
);
1751 res
= Py_BuildValue("i", v
);
1759 Tkapp_SplitList(PyObject
*self
, PyObject
*args
)
1767 if (PyTuple_Size(args
) == 1) {
1768 v
= PyTuple_GetItem(args
, 0);
1769 if (PyTuple_Check(v
)) {
1774 if (!PyArg_ParseTuple(args
, "et:splitlist", "utf-8", &list
))
1777 if (Tcl_SplitList(Tkapp_Interp(self
), list
, &argc
, &argv
) == TCL_ERROR
)
1778 return Tkinter_Error(self
);
1780 if (!(v
= PyTuple_New(argc
)))
1783 for (i
= 0; i
< argc
; i
++) {
1784 PyObject
*s
= PyString_FromString(argv
[i
]);
1785 if (!s
|| PyTuple_SetItem(v
, i
, s
)) {
1793 ckfree(FREECAST argv
);
1798 Tkapp_Split(PyObject
*self
, PyObject
*args
)
1802 if (PyTuple_Size(args
) == 1) {
1803 PyObject
* o
= PyTuple_GetItem(args
, 0);
1804 if (PyTuple_Check(o
)) {
1809 if (!PyArg_ParseTuple(args
, "et:split", "utf-8", &list
))
1815 Tkapp_Merge(PyObject
*self
, PyObject
*args
)
1817 char *s
= Merge(args
);
1818 PyObject
*res
= NULL
;
1821 res
= PyString_FromString(s
);
1832 /* Client data struct */
1836 } PythonCmd_ClientData
;
1839 PythonCmd_Error(Tcl_Interp
*interp
)
1842 PyErr_Fetch(&excInCmd
, &valInCmd
, &trbInCmd
);
1847 /* This is the Tcl command that acts as a wrapper for Python
1848 * function or method.
1851 PythonCmd(ClientData clientData
, Tcl_Interp
*interp
, int argc
, char *argv
[])
1853 PythonCmd_ClientData
*data
= (PythonCmd_ClientData
*)clientData
;
1854 PyObject
*self
, *func
, *arg
, *res
, *tmp
;
1860 /* TBD: no error checking here since we know, via the
1861 * Tkapp_CreateCommand() that the client data is a two-tuple
1866 /* Create argument list (argv1, ..., argvN) */
1867 if (!(arg
= PyTuple_New(argc
- 1)))
1868 return PythonCmd_Error(interp
);
1870 for (i
= 0; i
< (argc
- 1); i
++) {
1871 PyObject
*s
= PyString_FromString(argv
[i
+ 1]);
1872 if (!s
|| PyTuple_SetItem(arg
, i
, s
)) {
1874 return PythonCmd_Error(interp
);
1877 res
= PyEval_CallObject(func
, arg
);
1881 return PythonCmd_Error(interp
);
1883 if (!(tmp
= PyList_New(0))) {
1885 return PythonCmd_Error(interp
);
1888 s
= AsString(res
, tmp
);
1890 rv
= PythonCmd_Error(interp
);
1893 Tcl_SetResult(Tkapp_Interp(self
), s
, TCL_VOLATILE
);
1906 PythonCmdDelete(ClientData clientData
)
1908 PythonCmd_ClientData
*data
= (PythonCmd_ClientData
*)clientData
;
1911 Py_XDECREF(data
->self
);
1912 Py_XDECREF(data
->func
);
1920 TCL_DECLARE_MUTEX(command_mutex
)
1922 typedef struct CommandEvent
{
1933 Tkapp_CommandProc(CommandEvent
*ev
, int flags
)
1936 *ev
->status
= Tcl_CreateCommand(
1937 ev
->interp
, ev
->name
, PythonCmd
,
1938 ev
->data
, PythonCmdDelete
) == NULL
;
1940 *ev
->status
= Tcl_DeleteCommand(ev
->interp
, ev
->name
);
1941 Tcl_MutexLock(&command_mutex
);
1942 Tcl_ConditionNotify(&ev
->done
);
1943 Tcl_MutexUnlock(&command_mutex
);
1948 Tkapp_CreateCommand(PyObject
*_self
, PyObject
*args
)
1950 TkappObject
*self
= (TkappObject
*)_self
;
1951 PythonCmd_ClientData
*data
;
1956 if (!PyArg_ParseTuple(args
, "sO:createcommand", &cmdName
, &func
))
1958 if (!PyCallable_Check(func
)) {
1959 PyErr_SetString(PyExc_TypeError
, "command not callable");
1963 if (self
->threaded
&& self
->thread_id
!= Tcl_GetCurrentThread() &&
1964 !WaitForMainloop(self
))
1967 data
= PyMem_NEW(PythonCmd_ClientData
, 1);
1975 if (self
->threaded
&& self
->thread_id
!= Tcl_GetCurrentThread()) {
1976 CommandEvent
*ev
= (CommandEvent
*)ckalloc(sizeof(CommandEvent
));
1977 ev
->ev
.proc
= (Tcl_EventProc
*)Tkapp_CommandProc
;
1978 ev
->interp
= self
->interp
;
1981 ev
->data
= (ClientData
)data
;
1984 Tkapp_ThreadSend(self
, (Tcl_Event
*)ev
, &ev
->done
, &command_mutex
);
1988 err
= Tcl_CreateCommand(
1989 Tkapp_Interp(self
), cmdName
, PythonCmd
,
1990 (ClientData
)data
, PythonCmdDelete
) == NULL
;
1994 PyErr_SetString(Tkinter_TclError
, "can't create Tcl command");
2006 Tkapp_DeleteCommand(PyObject
*_self
, PyObject
*args
)
2008 TkappObject
*self
= (TkappObject
*)_self
;
2012 if (!PyArg_ParseTuple(args
, "s:deletecommand", &cmdName
))
2014 if (self
->threaded
&& self
->thread_id
!= Tcl_GetCurrentThread()) {
2016 ev
= (CommandEvent
*)ckalloc(sizeof(CommandEvent
));
2017 ev
->ev
.proc
= (Tcl_EventProc
*)Tkapp_CommandProc
;
2018 ev
->interp
= self
->interp
;
2023 Tkapp_ThreadSend(self
, (Tcl_Event
*)ev
, &ev
->done
,
2028 err
= Tcl_DeleteCommand(self
->interp
, cmdName
);
2032 PyErr_SetString(Tkinter_TclError
, "can't delete Tcl command");
2041 #ifdef HAVE_CREATEFILEHANDLER
2042 /** File Handler **/
2044 typedef struct _fhcdata
{
2048 struct _fhcdata
*next
;
2049 } FileHandler_ClientData
;
2051 static FileHandler_ClientData
*HeadFHCD
;
2053 static FileHandler_ClientData
*
2054 NewFHCD(PyObject
*func
, PyObject
*file
, int id
)
2056 FileHandler_ClientData
*p
;
2057 p
= PyMem_NEW(FileHandler_ClientData
, 1);
2073 FileHandler_ClientData
*p
, **pp
;
2076 while ((p
= *pp
) != NULL
) {
2079 Py_XDECREF(p
->func
);
2080 Py_XDECREF(p
->file
);
2089 FileHandler(ClientData clientData
, int mask
)
2091 FileHandler_ClientData
*data
= (FileHandler_ClientData
*)clientData
;
2092 PyObject
*func
, *file
, *arg
, *res
;
2098 arg
= Py_BuildValue("(Oi)", file
, (long) mask
);
2099 res
= PyEval_CallObject(func
, arg
);
2104 PyErr_Fetch(&excInCmd
, &valInCmd
, &trbInCmd
);
2111 Tkapp_CreateFileHandler(PyObject
*self
, PyObject
*args
)
2112 /* args is (file, mask, func) */
2114 FileHandler_ClientData
*data
;
2115 PyObject
*file
, *func
;
2118 if (!PyArg_ParseTuple(args
, "OiO:createfilehandler",
2119 &file
, &mask
, &func
))
2121 CHECK_TCL_APPARTMENT
;
2122 tfile
= PyObject_AsFileDescriptor(file
);
2125 if (!PyCallable_Check(func
)) {
2126 PyErr_SetString(PyExc_TypeError
, "bad argument list");
2130 data
= NewFHCD(func
, file
, tfile
);
2134 /* Ought to check for null Tcl_File object... */
2136 Tcl_CreateFileHandler(tfile
, mask
, FileHandler
, (ClientData
) data
);
2143 Tkapp_DeleteFileHandler(PyObject
*self
, PyObject
*args
)
2148 if (!PyArg_ParseTuple(args
, "O:deletefilehandler", &file
))
2150 CHECK_TCL_APPARTMENT
;
2151 tfile
= PyObject_AsFileDescriptor(file
);
2157 /* Ought to check for null Tcl_File object... */
2159 Tcl_DeleteFileHandler(tfile
);
2164 #endif /* HAVE_CREATEFILEHANDLER */
2167 /**** Tktt Object (timer token) ****/
2169 static PyTypeObject Tktt_Type
;
2173 Tcl_TimerToken token
;
2178 Tktt_DeleteTimerHandler(PyObject
*self
, PyObject
*args
)
2180 TkttObject
*v
= (TkttObject
*)self
;
2181 PyObject
*func
= v
->func
;
2183 if (!PyArg_ParseTuple(args
, ":deletetimerhandler"))
2185 if (v
->token
!= NULL
) {
2186 Tcl_DeleteTimerHandler(v
->token
);
2192 Py_DECREF(v
); /* See Tktt_New() */
2198 static PyMethodDef Tktt_methods
[] =
2200 {"deletetimerhandler", Tktt_DeleteTimerHandler
, METH_VARARGS
},
2205 Tktt_New(PyObject
*func
)
2209 v
= PyObject_New(TkttObject
, &Tktt_Type
);
2217 /* Extra reference, deleted when called or when handler is deleted */
2223 Tktt_Dealloc(PyObject
*self
)
2225 TkttObject
*v
= (TkttObject
*)self
;
2226 PyObject
*func
= v
->func
;
2234 Tktt_Repr(PyObject
*self
)
2236 TkttObject
*v
= (TkttObject
*)self
;
2239 PyOS_snprintf(buf
, sizeof(buf
), "<tktimertoken at %p%s>", v
,
2240 v
->func
== NULL
? ", handler deleted" : "");
2241 return PyString_FromString(buf
);
2245 Tktt_GetAttr(PyObject
*self
, char *name
)
2247 return Py_FindMethod(Tktt_methods
, self
, name
);
2250 static PyTypeObject Tktt_Type
=
2252 PyObject_HEAD_INIT(NULL
)
2254 "tktimertoken", /*tp_name */
2255 sizeof(TkttObject
), /*tp_basicsize */
2257 Tktt_Dealloc
, /*tp_dealloc */
2259 Tktt_GetAttr
, /*tp_getattr */
2262 Tktt_Repr
, /*tp_repr */
2263 0, /*tp_as_number */
2264 0, /*tp_as_sequence */
2265 0, /*tp_as_mapping */
2271 /** Timer Handler **/
2274 TimerHandler(ClientData clientData
)
2276 TkttObject
*v
= (TkttObject
*)clientData
;
2277 PyObject
*func
= v
->func
;
2287 res
= PyEval_CallObject(func
, NULL
);
2289 Py_DECREF(v
); /* See Tktt_New() */
2293 PyErr_Fetch(&excInCmd
, &valInCmd
, &trbInCmd
);
2302 Tkapp_CreateTimerHandler(PyObject
*self
, PyObject
*args
)
2308 if (!PyArg_ParseTuple(args
, "iO:createtimerhandler",
2309 &milliseconds
, &func
))
2311 if (!PyCallable_Check(func
)) {
2312 PyErr_SetString(PyExc_TypeError
, "bad argument list");
2316 v
->token
= Tcl_CreateTimerHandler(milliseconds
, TimerHandler
,
2319 return (PyObject
*) v
;
2326 Tkapp_MainLoop(PyObject
*_self
, PyObject
*args
)
2329 TkappObject
*self
= (TkappObject
*)_self
;
2331 PyThreadState
*tstate
= PyThreadState_Get();
2334 if (!PyArg_ParseTuple(args
, "|i:mainloop", &threshold
))
2337 CHECK_TCL_APPARTMENT
;
2340 self
->dispatching
= 1;
2341 while (Tk_GetNumMainWindows() > threshold
&&
2348 if (self
->threaded
) {
2349 /* Allow other Python threads to run. */
2351 result
= Tcl_DoOneEvent(0);
2355 Py_BEGIN_ALLOW_THREADS
2356 if(tcl_lock
)PyThread_acquire_lock(tcl_lock
, 1);
2357 tcl_tstate
= tstate
;
2358 result
= Tcl_DoOneEvent(TCL_DONT_WAIT
);
2360 if(tcl_lock
)PyThread_release_lock(tcl_lock
);
2363 Py_END_ALLOW_THREADS
2366 result
= Tcl_DoOneEvent(0);
2369 if (PyErr_CheckSignals() != 0) {
2370 self
->dispatching
= 0;
2376 self
->dispatching
= 0;
2381 PyErr_Restore(excInCmd
, valInCmd
, trbInCmd
);
2382 excInCmd
= valInCmd
= trbInCmd
= NULL
;
2390 Tkapp_DoOneEvent(PyObject
*self
, PyObject
*args
)
2395 if (!PyArg_ParseTuple(args
, "|i:dooneevent", &flags
))
2397 CHECK_TCL_APPARTMENT
;
2400 rv
= Tcl_DoOneEvent(flags
);
2402 return Py_BuildValue("i", rv
);
2406 Tkapp_Quit(PyObject
*self
, PyObject
*args
)
2409 if (!PyArg_ParseTuple(args
, ":quit"))
2418 Tkapp_InterpAddr(PyObject
*self
, PyObject
*args
)
2421 if (!PyArg_ParseTuple(args
, ":interpaddr"))
2424 return PyInt_FromLong((long)Tkapp_Interp(self
));
2429 Tkapp_WantObjects(PyObject
*self
, PyObject
*args
)
2433 if (!PyArg_ParseTuple(args
, "i:wantobjects", &wantobjects
))
2435 ((TkappObject
*)self
)->wantobjects
= wantobjects
;
2442 Tkapp_WillDispatch(PyObject
*self
, PyObject
*args
)
2445 ((TkappObject
*)self
)->dispatching
= 1;
2452 /**** Tkapp Method List ****/
2454 static PyMethodDef Tkapp_methods
[] =
2456 {"willdispatch", Tkapp_WillDispatch
, METH_NOARGS
},
2457 {"wantobjects", Tkapp_WantObjects
, METH_VARARGS
},
2458 {"call", Tkapp_Call
, METH_OLDARGS
},
2459 {"globalcall", Tkapp_GlobalCall
, METH_OLDARGS
},
2460 {"eval", Tkapp_Eval
, METH_VARARGS
},
2461 {"globaleval", Tkapp_GlobalEval
, METH_VARARGS
},
2462 {"evalfile", Tkapp_EvalFile
, METH_VARARGS
},
2463 {"record", Tkapp_Record
, METH_VARARGS
},
2464 {"adderrorinfo", Tkapp_AddErrorInfo
, METH_VARARGS
},
2465 {"setvar", Tkapp_SetVar
, METH_VARARGS
},
2466 {"globalsetvar", Tkapp_GlobalSetVar
, METH_VARARGS
},
2467 {"getvar", Tkapp_GetVar
, METH_VARARGS
},
2468 {"globalgetvar", Tkapp_GlobalGetVar
, METH_VARARGS
},
2469 {"unsetvar", Tkapp_UnsetVar
, METH_VARARGS
},
2470 {"globalunsetvar", Tkapp_GlobalUnsetVar
, METH_VARARGS
},
2471 {"getint", Tkapp_GetInt
, METH_VARARGS
},
2472 {"getdouble", Tkapp_GetDouble
, METH_VARARGS
},
2473 {"getboolean", Tkapp_GetBoolean
, METH_VARARGS
},
2474 {"exprstring", Tkapp_ExprString
, METH_VARARGS
},
2475 {"exprlong", Tkapp_ExprLong
, METH_VARARGS
},
2476 {"exprdouble", Tkapp_ExprDouble
, METH_VARARGS
},
2477 {"exprboolean", Tkapp_ExprBoolean
, METH_VARARGS
},
2478 {"splitlist", Tkapp_SplitList
, METH_VARARGS
},
2479 {"split", Tkapp_Split
, METH_VARARGS
},
2480 {"merge", Tkapp_Merge
, METH_OLDARGS
},
2481 {"createcommand", Tkapp_CreateCommand
, METH_VARARGS
},
2482 {"deletecommand", Tkapp_DeleteCommand
, METH_VARARGS
},
2483 #ifdef HAVE_CREATEFILEHANDLER
2484 {"createfilehandler", Tkapp_CreateFileHandler
, METH_VARARGS
},
2485 {"deletefilehandler", Tkapp_DeleteFileHandler
, METH_VARARGS
},
2487 {"createtimerhandler", Tkapp_CreateTimerHandler
, METH_VARARGS
},
2488 {"mainloop", Tkapp_MainLoop
, METH_VARARGS
},
2489 {"dooneevent", Tkapp_DoOneEvent
, METH_VARARGS
},
2490 {"quit", Tkapp_Quit
, METH_VARARGS
},
2491 {"interpaddr", Tkapp_InterpAddr
, METH_VARARGS
},
2497 /**** Tkapp Type Methods ****/
2500 Tkapp_Dealloc(PyObject
*self
)
2502 /*CHECK_TCL_APPARTMENT;*/
2504 Tcl_DeleteInterp(Tkapp_Interp(self
));
2511 Tkapp_GetAttr(PyObject
*self
, char *name
)
2513 return Py_FindMethod(Tkapp_methods
, self
, name
);
2516 static PyTypeObject Tkapp_Type
=
2518 PyObject_HEAD_INIT(NULL
)
2520 "tkapp", /*tp_name */
2521 sizeof(TkappObject
), /*tp_basicsize */
2523 Tkapp_Dealloc
, /*tp_dealloc */
2525 Tkapp_GetAttr
, /*tp_getattr */
2529 0, /*tp_as_number */
2530 0, /*tp_as_sequence */
2531 0, /*tp_as_mapping */
2537 /**** Tkinter Module ****/
2541 int size
; /* current size */
2542 int maxsize
; /* allocated size */
2546 _bump(FlattenContext
* context
, int size
)
2548 /* expand tuple to hold (at least) size new items.
2549 return true if successful, false if an exception was raised */
2551 int maxsize
= context
->maxsize
* 2;
2553 if (maxsize
< context
->size
+ size
)
2554 maxsize
= context
->size
+ size
;
2556 context
->maxsize
= maxsize
;
2558 return _PyTuple_Resize(&context
->tuple
, maxsize
) >= 0;
2562 _flatten1(FlattenContext
* context
, PyObject
* item
, int depth
)
2564 /* add tuple or list to argument tuple (recursively) */
2569 PyErr_SetString(PyExc_ValueError
,
2570 "nesting too deep in _flatten");
2572 } else if (PyList_Check(item
)) {
2573 size
= PyList_GET_SIZE(item
);
2574 /* preallocate (assume no nesting) */
2575 if (context
->size
+ size
> context
->maxsize
&&
2576 !_bump(context
, size
))
2578 /* copy items to output tuple */
2579 for (i
= 0; i
< size
; i
++) {
2580 PyObject
*o
= PyList_GET_ITEM(item
, i
);
2581 if (PyList_Check(o
) || PyTuple_Check(o
)) {
2582 if (!_flatten1(context
, o
, depth
+ 1))
2584 } else if (o
!= Py_None
) {
2585 if (context
->size
+ 1 > context
->maxsize
&&
2589 PyTuple_SET_ITEM(context
->tuple
,
2590 context
->size
++, o
);
2593 } else if (PyTuple_Check(item
)) {
2594 /* same, for tuples */
2595 size
= PyTuple_GET_SIZE(item
);
2596 if (context
->size
+ size
> context
->maxsize
&&
2597 !_bump(context
, size
))
2599 for (i
= 0; i
< size
; i
++) {
2600 PyObject
*o
= PyTuple_GET_ITEM(item
, i
);
2601 if (PyList_Check(o
) || PyTuple_Check(o
)) {
2602 if (!_flatten1(context
, o
, depth
+ 1))
2604 } else if (o
!= Py_None
) {
2605 if (context
->size
+ 1 > context
->maxsize
&&
2609 PyTuple_SET_ITEM(context
->tuple
,
2610 context
->size
++, o
);
2614 PyErr_SetString(PyExc_TypeError
, "argument must be sequence");
2621 Tkinter_Flatten(PyObject
* self
, PyObject
* args
)
2623 FlattenContext context
;
2626 if (!PyArg_ParseTuple(args
, "O:_flatten", &item
))
2629 context
.maxsize
= PySequence_Size(item
);
2630 if (context
.maxsize
<= 0)
2631 return PyTuple_New(0);
2633 context
.tuple
= PyTuple_New(context
.maxsize
);
2639 if (!_flatten1(&context
, item
,0))
2642 if (_PyTuple_Resize(&context
.tuple
, context
.size
))
2645 return context
.tuple
;
2649 Tkinter_Create(PyObject
*self
, PyObject
*args
)
2651 char *screenName
= NULL
;
2652 char *baseName
= NULL
;
2653 char *className
= NULL
;
2654 int interactive
= 0;
2655 int wantobjects
= 0;
2657 baseName
= strrchr(Py_GetProgramName(), '/');
2658 if (baseName
!= NULL
)
2661 baseName
= Py_GetProgramName();
2664 if (!PyArg_ParseTuple(args
, "|zssii:create",
2665 &screenName
, &baseName
, &className
,
2666 &interactive
, &wantobjects
))
2669 return (PyObject
*) Tkapp_New(screenName
, baseName
, className
,
2670 interactive
, wantobjects
);
2673 static PyMethodDef moduleMethods
[] =
2675 {"_flatten", Tkinter_Flatten
, METH_VARARGS
},
2676 {"create", Tkinter_Create
, METH_VARARGS
},
2677 #ifdef HAVE_CREATEFILEHANDLER
2678 {"createfilehandler", Tkapp_CreateFileHandler
, METH_VARARGS
},
2679 {"deletefilehandler", Tkapp_DeleteFileHandler
, METH_VARARGS
},
2681 {"createtimerhandler", Tkapp_CreateTimerHandler
, METH_VARARGS
},
2682 {"mainloop", Tkapp_MainLoop
, METH_VARARGS
},
2683 {"dooneevent", Tkapp_DoOneEvent
, METH_VARARGS
},
2684 {"quit", Tkapp_Quit
, METH_VARARGS
},
2688 #ifdef WAIT_FOR_STDIN
2690 static int stdin_ready
= 0;
2694 MyFileProc(void *clientData
, int mask
)
2700 static PyThreadState
*event_tstate
= NULL
;
2709 PyEval_RestoreThread(event_tstate
);
2714 tfile
= fileno(stdin
);
2715 Tcl_CreateFileHandler(tfile
, TCL_READABLE
, MyFileProc
, NULL
);
2717 while (!errorInCmd
&& !stdin_ready
) {
2725 #if defined(WITH_THREAD) || defined(MS_WINDOWS)
2726 Py_BEGIN_ALLOW_THREADS
2727 if(tcl_lock
)PyThread_acquire_lock(tcl_lock
, 1);
2728 tcl_tstate
= event_tstate
;
2730 result
= Tcl_DoOneEvent(TCL_DONT_WAIT
);
2733 if(tcl_lock
)PyThread_release_lock(tcl_lock
);
2736 Py_END_ALLOW_THREADS
2738 result
= Tcl_DoOneEvent(0);
2745 Tcl_DeleteFileHandler(tfile
);
2749 PyErr_Restore(excInCmd
, valInCmd
, trbInCmd
);
2750 excInCmd
= valInCmd
= trbInCmd
= NULL
;
2754 PyEval_SaveThread();
2762 EnableEventHook(void)
2764 #ifdef WAIT_FOR_STDIN
2765 if (PyOS_InputHook
== NULL
) {
2767 event_tstate
= PyThreadState_Get();
2769 PyOS_InputHook
= EventHook
;
2775 DisableEventHook(void)
2777 #ifdef WAIT_FOR_STDIN
2778 if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook
== EventHook
) {
2779 PyOS_InputHook
= NULL
;
2785 /* all errors will be checked in one fell swoop in init_tkinter() */
2787 ins_long(PyObject
*d
, char *name
, long val
)
2789 PyObject
*v
= PyInt_FromLong(val
);
2791 PyDict_SetItemString(d
, name
, v
);
2796 ins_string(PyObject
*d
, char *name
, char *val
)
2798 PyObject
*v
= PyString_FromString(val
);
2800 PyDict_SetItemString(d
, name
, v
);
2811 Tkapp_Type
.ob_type
= &PyType_Type
;
2814 tcl_lock
= PyThread_allocate_lock();
2817 m
= Py_InitModule("_tkinter", moduleMethods
);
2819 d
= PyModule_GetDict(m
);
2820 Tkinter_TclError
= PyErr_NewException("_tkinter.TclError", NULL
, NULL
);
2821 PyDict_SetItemString(d
, "TclError", Tkinter_TclError
);
2823 ins_long(d
, "READABLE", TCL_READABLE
);
2824 ins_long(d
, "WRITABLE", TCL_WRITABLE
);
2825 ins_long(d
, "EXCEPTION", TCL_EXCEPTION
);
2826 ins_long(d
, "WINDOW_EVENTS", TCL_WINDOW_EVENTS
);
2827 ins_long(d
, "FILE_EVENTS", TCL_FILE_EVENTS
);
2828 ins_long(d
, "TIMER_EVENTS", TCL_TIMER_EVENTS
);
2829 ins_long(d
, "IDLE_EVENTS", TCL_IDLE_EVENTS
);
2830 ins_long(d
, "ALL_EVENTS", TCL_ALL_EVENTS
);
2831 ins_long(d
, "DONT_WAIT", TCL_DONT_WAIT
);
2832 ins_string(d
, "TK_VERSION", TK_VERSION
);
2833 ins_string(d
, "TCL_VERSION", TCL_VERSION
);
2835 PyDict_SetItemString(d
, "TkappType", (PyObject
*)&Tkapp_Type
);
2837 Tktt_Type
.ob_type
= &PyType_Type
;
2838 PyDict_SetItemString(d
, "TkttType", (PyObject
*)&Tktt_Type
);
2840 PyTclObject_Type
.ob_type
= &PyType_Type
;
2841 PyDict_SetItemString(d
, "Tcl_Obj", (PyObject
*)&PyTclObject_Type
);
2844 /* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems
2845 * start waking up. Note that Tcl_FindExecutable will do this, this
2846 * code must be above it! The original warning from
2847 * tkMacOSXAppInit.c is copied below.
2849 * NB - You have to swap in the Tk Notifier BEFORE you start up the
2850 * Tcl interpreter for now. It probably should work to do this
2851 * in the other order, but for now it doesn't seem to.
2854 Tk_MacOSXSetupTkNotifier();
2858 /* This helps the dynamic loader; in Unicode aware Tcl versions
2859 it also helps Tcl find its encodings. */
2860 Tcl_FindExecutable(Py_GetProgramName());
2862 if (PyErr_Occurred())
2866 /* This was not a good idea; through <Destroy> bindings,
2867 Tcl_Finalize() may invoke Python code but at that point the
2868 interpreter and thread state have already been destroyed! */
2869 Py_AtExit(Tcl_Finalize
);
2874 ** Part of this code is stolen from MacintoshInit in tkMacAppInit.
2875 ** Most of the initializations in that routine (toolbox init calls and
2876 ** such) have already been done for us, so we only need these.
2880 Tcl_MacSetEventProc(PyMacConvertEvent
);
2882 mac_addlibresources();
2883 #endif /* GENERATINGCFM */
2884 #endif /* macintosh */
2892 ** Anyone who embeds Tcl/Tk on the Mac must define panic().
2896 panic(char * format
, ...)
2900 va_start(varg
, format
);
2902 vfprintf(stderr
, format
, varg
);
2903 (void) fflush(stderr
);
2907 Py_FatalError("Tcl/Tk panic");
2911 ** Pass events to SIOUX before passing them to Tk.
2915 PyMacConvertEvent(EventRecord
*eventPtr
)
2919 ** Sioux eats too many events, so we don't pass it everything. We
2920 ** always pass update events to Sioux, and we only pass other events if
2921 ** the Sioux window is frontmost. This means that Tk menus don't work
2922 ** in that case, but at least we can scroll the sioux window.
2923 ** Note that the SIOUXIsAppWindow() routine we use here is not really
2924 ** part of the external interface of Sioux...
2926 frontwin
= FrontWindow();
2927 if ( eventPtr
->what
== updateEvt
|| SIOUXIsAppWindow(frontwin
) ) {
2928 if (SIOUXHandleOneEvent(eventPtr
))
2929 return 0; /* Nothing happened to the Tcl event queue */
2931 return TkMacConvertEvent(eventPtr
);
2937 ** Additional Mac specific code for dealing with shared libraries.
2940 #include <Resources.h>
2941 #include <CodeFragments.h>
2943 static int loaded_from_shlib
= 0;
2944 static FSSpec library_fss
;
2947 ** If this module is dynamically loaded the following routine should
2948 ** be the init routine. It takes care of adding the shared library to
2949 ** the resource-file chain, so that the tk routines can find their
2953 init_tkinter_shlib(CFragInitBlockPtr data
)
2956 if ( data
== nil
) return noErr
;
2957 if ( data
->fragLocator
.where
== kDataForkCFragLocator
) {
2958 library_fss
= *data
->fragLocator
.u
.onDisk
.fileSpec
;
2959 loaded_from_shlib
= 1;
2960 } else if ( data
->fragLocator
.where
== kResourceCFragLocator
) {
2961 library_fss
= *data
->fragLocator
.u
.inSegs
.fileSpec
;
2962 loaded_from_shlib
= 1;
2968 ** Insert the library resources into the search path. Put them after
2969 ** the resources from the application. Again, we ignore errors.
2972 mac_addlibresources(void)
2974 if ( !loaded_from_shlib
)
2976 (void)FSpOpenResFile(&library_fss
, fsRdPerm
);
2979 #endif /* GENERATINGCFM */
2980 #endif /* macintosh */