Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
b5bfb9f3
Kaydet (Commit)
b5bfb9f3
authored
Ara 12, 2002
tarafından
Martin v. Löwis
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Support threads-enabled Tcl installations.
üst
d9a6ad3b
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
498 additions
and
91 deletions
+498
-91
_tkinter.c
Modules/_tkinter.c
+498
-91
No files found.
Modules/_tkinter.c
Dosyayı görüntüle @
b5bfb9f3
...
@@ -9,17 +9,13 @@ Copyright (C) 1994 Steen Lumholt.
...
@@ -9,17 +9,13 @@ Copyright (C) 1994 Steen Lumholt.
/* TCL/TK VERSION INFO:
/* TCL/TK VERSION INFO:
Only Tcl/Tk 8.
0
and later are supported. Older versions are not
Only Tcl/Tk 8.
2
and later are supported. Older versions are not
supported. (Use Python
1.5
.2 if you cannot upgrade your Tcl/Tk
supported. (Use Python
2
.2 if you cannot upgrade your Tcl/Tk
libraries.)
libraries.)
*/
*/
/* XXX Further speed-up ideas, involving Tcl 8.0 features:
/* XXX Further speed-up ideas, involving Tcl 8.0 features:
- In Tcl_Call(), create Tcl objects from the arguments, possibly using
intelligent mappings between Python objects and Tcl objects (e.g. ints,
floats and Tcl window pointers could be handled specially).
- Register a new Tcl type, "Python callable", which can be called more
- Register a new Tcl type, "Python callable", which can be called more
efficiently and passed to Tcl_EvalObj() directly (if this is possible).
efficiently and passed to Tcl_EvalObj() directly (if this is possible).
...
@@ -48,6 +44,11 @@ Copyright (C) 1994 Steen Lumholt.
...
@@ -48,6 +44,11 @@ Copyright (C) 1994 Steen Lumholt.
anymore, this should go. */
anymore, this should go. */
#define USE_COMPAT_CONST
#define USE_COMPAT_CONST
/* If Tcl is compiled for threads, we must also define TCL_THREAD. We define
it always; if Tcl is not threaded, the thread functions in
Tcl are empty. */
#define TCL_THREADS
#ifdef TK_FRAMEWORK
#ifdef TK_FRAMEWORK
#include <Tcl/tcl.h>
#include <Tcl/tcl.h>
#include <Tk/tk.h>
#include <Tk/tk.h>
...
@@ -111,9 +112,8 @@ Copyright (C) 1994 Steen Lumholt.
...
@@ -111,9 +112,8 @@ Copyright (C) 1994 Steen Lumholt.
#ifdef WITH_THREAD
#ifdef WITH_THREAD
/* The threading situation is complicated. Tcl is not thread-safe, except for
/* The threading situation is complicated. Tcl is not thread-safe, except
Tcl 8.1, which will probably remain in alpha status for another 6 months
when configured with --enable-threads.
(and the README says that Tk will probably remain thread-unsafe forever).
So we need to use a lock around all uses of Tcl. Previously, the Python
So we need to use a lock around all uses of Tcl. Previously, the Python
interpreter lock was used for this. However, this causes problems when
interpreter lock was used for this. However, this causes problems when
other Python threads need to run while Tcl is blocked waiting for events.
other Python threads need to run while Tcl is blocked waiting for events.
...
@@ -148,31 +148,58 @@ Copyright (C) 1994 Steen Lumholt.
...
@@ -148,31 +148,58 @@ Copyright (C) 1994 Steen Lumholt.
These locks expand to several statements and brackets; they should not be
These locks expand to several statements and brackets; they should not be
used in branches of if statements and the like.
used in branches of if statements and the like.
If Tcl is threaded, this approach won't work anymore. The Tcl interpreter is
only valid in the thread that created it, and all Tk activity must happen in this
thread, also. That means that the mainloop must be invoked in the thread that
created the interpreter. Invoking commands from other threads is possible;
_tkinter will queue an event for the interpreter thread, which will then
execute the command and pass back the result. If the main thread is not in the
mainloop, and invoking commands causes an exception; if the main loop is running
but not processing events, the command invocation will block.
In addition, for a threaded Tcl, a single global tcl_tstate won't be sufficient
anymore, since multiple Tcl interpreters may simultaneously dispatch in different
threads. So we use the Tcl TLS API.
*/
*/
static
PyThread_type_lock
tcl_lock
=
0
;
static
PyThread_type_lock
tcl_lock
=
0
;
#ifdef TCL_THREADS
static
Tcl_ThreadDataKey
state_key
;
typedef
PyThreadState
*
ThreadSpecificData
;
#define tcl_tstate (*(PyThreadState**)Tcl_GetThreadData(&state_key, sizeof(PyThreadState*)))
#else
static
PyThreadState
*
tcl_tstate
=
NULL
;
static
PyThreadState
*
tcl_tstate
=
NULL
;
#endif
#define ENTER_TCL \
#define ENTER_TCL \
{ PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \
{ PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \
PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
if(tcl_lock)
PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
#define LEAVE_TCL \
#define LEAVE_TCL \
tcl_tstate = NULL; PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
tcl_tstate = NULL;
if(tcl_lock)
PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
#define ENTER_OVERLAP \
#define ENTER_OVERLAP \
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS
#define LEAVE_OVERLAP_TCL \
#define LEAVE_OVERLAP_TCL \
tcl_tstate = NULL; PyThread_release_lock(tcl_lock); }
tcl_tstate = NULL;
if(tcl_lock)
PyThread_release_lock(tcl_lock); }
#define ENTER_PYTHON \
#define ENTER_PYTHON \
{ PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
{ PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
if(tcl_lock)
PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
#define LEAVE_PYTHON \
#define LEAVE_PYTHON \
{ PyThreadState *tstate = PyEval_SaveThread(); \
{ PyThreadState *tstate = PyEval_SaveThread(); \
PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }
if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }
#define CHECK_TCL_APPARTMENT \
if (((TkappObject *)self)->threaded && \
((TkappObject *)self)->thread_id != Tcl_GetCurrentThread()) { \
PyErr_SetString(PyExc_RuntimeError, "Calling Tcl from different appartment"); \
return 0; \
}
#else
#else
...
@@ -182,6 +209,7 @@ static PyThreadState *tcl_tstate = NULL;
...
@@ -182,6 +209,7 @@ static PyThreadState *tcl_tstate = NULL;
#define LEAVE_OVERLAP_TCL
#define LEAVE_OVERLAP_TCL
#define ENTER_PYTHON
#define ENTER_PYTHON
#define LEAVE_PYTHON
#define LEAVE_PYTHON
#define CHECK_TCL_APPARTMENT
#endif
#endif
...
@@ -220,6 +248,9 @@ typedef struct {
...
@@ -220,6 +248,9 @@ typedef struct {
PyObject_HEAD
PyObject_HEAD
Tcl_Interp
*
interp
;
Tcl_Interp
*
interp
;
int
wantobjects
;
int
wantobjects
;
int
threaded
;
/* True if tcl_platform[threaded] */
Tcl_ThreadId
thread_id
;
int
dispatching
;
/* We cannot include tclInt.h, as this is internal.
/* We cannot include tclInt.h, as this is internal.
So we cache interesting types here. */
So we cache interesting types here. */
Tcl_ObjType
*
BooleanType
;
Tcl_ObjType
*
BooleanType
;
...
@@ -280,6 +311,7 @@ Sleep(int milli)
...
@@ -280,6 +311,7 @@ Sleep(int milli)
#endif
/* WITH_THREAD */
#endif
/* WITH_THREAD */
static
char
*
static
char
*
AsString
(
PyObject
*
value
,
PyObject
*
tmp
)
AsString
(
PyObject
*
value
,
PyObject
*
tmp
)
{
{
...
@@ -541,6 +573,23 @@ Tkapp_New(char *screenName, char *baseName, char *className,
...
@@ -541,6 +573,23 @@ Tkapp_New(char *screenName, char *baseName, char *className,
v
->
interp
=
Tcl_CreateInterp
();
v
->
interp
=
Tcl_CreateInterp
();
v
->
wantobjects
=
wantobjects
;
v
->
wantobjects
=
wantobjects
;
v
->
threaded
=
Tcl_GetVar2Ex
(
v
->
interp
,
"tcl_platform"
,
"threaded"
,
TCL_GLOBAL_ONLY
)
!=
NULL
;
v
->
thread_id
=
Tcl_GetCurrentThread
();
v
->
dispatching
=
0
;
#ifndef TCL_THREADS
if
(
v
->
threaded
)
{
PyErr_SetString
(
PyExc_RuntimeError
,
"Tcl is threaded but _tkinter is not"
);
Py_DECREF
(
v
);
return
0
;
}
#endif
if
(
v
->
threaded
&&
tcl_lock
)
{
/* If Tcl is threaded, we don't need the lock. */
PyThread_free_lock
(
tcl_lock
);
tcl_lock
=
NULL
;
}
v
->
BooleanType
=
Tcl_GetObjType
(
"boolean"
);
v
->
BooleanType
=
Tcl_GetObjType
(
"boolean"
);
v
->
ByteArrayType
=
Tcl_GetObjType
(
"bytearray"
);
v
->
ByteArrayType
=
Tcl_GetObjType
(
"bytearray"
);
...
@@ -591,6 +640,19 @@ Tkapp_New(char *screenName, char *baseName, char *className,
...
@@ -591,6 +640,19 @@ Tkapp_New(char *screenName, char *baseName, char *className,
}
}
static
void
Tkapp_ThreadSend
(
TkappObject
*
self
,
Tcl_Event
*
ev
,
Tcl_Condition
*
cond
,
Tcl_Mutex
*
mutex
)
{
Py_BEGIN_ALLOW_THREADS
;
Tcl_MutexLock
(
mutex
);
Tcl_ThreadQueueEvent
(
self
->
thread_id
,
ev
,
TCL_QUEUE_TAIL
);
Tcl_ThreadAlert
(
self
->
thread_id
);
Tcl_ConditionWait
(
cond
,
mutex
,
NULL
);
Tcl_MutexUnlock
(
mutex
);
Py_END_ALLOW_THREADS
}
/** Tcl Eval **/
/** Tcl Eval **/
...
@@ -883,19 +945,38 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
...
@@ -883,19 +945,38 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
return
newPyTclObject
(
value
);
return
newPyTclObject
(
value
);
}
}
static
PyObject
*
/* This mutex synchronizes inter-thread command calls. */
Tkapp_Call
(
PyObject
*
self
,
PyObject
*
args
)
TCL_DECLARE_MUTEX
(
call_mutex
)
typedef
struct
Tkapp_CallEvent
{
Tcl_Event
ev
;
/* Must be first */
TkappObject
*
self
;
PyObject
*
args
;
int
flags
;
PyObject
**
res
;
PyObject
**
exc_type
,
**
exc_value
,
**
exc_tb
;
Tcl_Condition
done
;
}
Tkapp_CallEvent
;
void
Tkapp_CallDeallocArgs
(
Tcl_Obj
**
objv
,
Tcl_Obj
**
objStore
,
int
objc
)
{
{
Tcl_Obj
*
objStore
[
ARGSZ
];
int
i
;
Tcl_Obj
**
objv
=
NULL
;
for
(
i
=
0
;
i
<
objc
;
i
++
)
int
objc
=
0
,
i
;
Tcl_DecrRefCount
(
objv
[
i
]);
PyObject
*
res
=
NULL
;
if
(
objv
!=
objStore
)
Tcl_Interp
*
interp
=
Tkapp_Interp
(
self
);
ckfree
(
FREECAST
objv
);
/* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */
}
int
flags
=
TCL_EVAL_DIRECT
;
objv
=
objStore
;
/* Convert Python objects to Tcl objects. This must happen in the
interpreter thread, which may or may not be the calling thread. */
static
Tcl_Obj
**
Tkapp_CallArgs
(
PyObject
*
args
,
Tcl_Obj
**
objStore
,
int
*
pobjc
)
{
Tcl_Obj
**
objv
=
objStore
;
int
objc
,
i
;
if
(
args
==
NULL
)
if
(
args
==
NULL
)
/* do nothing */
;
/* do nothing */
;
...
@@ -934,24 +1015,29 @@ Tkapp_Call(PyObject *self, PyObject *args)
...
@@ -934,24 +1015,29 @@ Tkapp_Call(PyObject *self, PyObject *args)
Tcl_IncrRefCount
(
objv
[
i
]);
Tcl_IncrRefCount
(
objv
[
i
]);
}
}
}
}
*
pobjc
=
objc
;
return
objv
;
finally:
Tkapp_CallDeallocArgs
(
objv
,
objStore
,
objc
);
return
NULL
;
}
ENTER_TCL
/* Convert the results of a command call into a Python objects. */
i
=
Tcl_EvalObjv
(
interp
,
objc
,
objv
,
flags
);
ENTER_OVERLAP
static
PyObject
*
if
(
i
==
TCL_ERROR
)
Tkapp_CallResult
(
TkappObject
*
self
)
Tkinter_Error
(
self
);
{
else
if
(((
TkappObject
*
)
self
)
->
wantobjects
)
{
PyObject
*
res
=
NULL
;
Tcl_Obj
*
value
=
Tcl_GetObjResult
(
interp
);
if
(
self
->
wantobjects
)
{
Tcl_Obj
*
value
=
Tcl_GetObjResult
(
self
->
interp
);
/* Not sure whether the IncrRef is necessary, but something
/* Not sure whether the IncrRef is necessary, but something
may overwrite the interpreter result while we are
may overwrite the interpreter result while we are
converting it. */
converting it. */
Tcl_IncrRefCount
(
value
);
Tcl_IncrRefCount
(
value
);
res
=
FromObj
(
self
,
value
);
res
=
FromObj
(
(
PyObject
*
)
self
,
value
);
Tcl_DecrRefCount
(
value
);
Tcl_DecrRefCount
(
value
);
}
else
{
}
else
{
const
char
*
s
=
Tcl_GetStringResult
(
interp
);
const
char
*
s
=
Tcl_GetStringResult
(
self
->
interp
);
const
char
*
p
=
s
;
const
char
*
p
=
s
;
/* If the result contains any bytes with the top bit set,
/* If the result contains any bytes with the top bit set,
...
@@ -979,14 +1065,124 @@ Tkapp_Call(PyObject *self, PyObject *args)
...
@@ -979,14 +1065,124 @@ Tkapp_Call(PyObject *self, PyObject *args)
res
=
PyString_FromStringAndSize
(
s
,
(
int
)(
p
-
s
));
res
=
PyString_FromStringAndSize
(
s
,
(
int
)(
p
-
s
));
#endif
#endif
}
}
return
res
;
}
/* Tkapp_CallProc is the event procedure that is executed in the context of
the Tcl interpreter thread. Initially, it holds the Tcl lock, and doesn't
hold the Python lock. */
static
int
Tkapp_CallProc
(
Tkapp_CallEvent
*
e
,
int
flags
)
{
Tcl_Obj
*
objStore
[
ARGSZ
];
Tcl_Obj
**
objv
;
int
objc
;
int
i
;
ENTER_PYTHON
objv
=
Tkapp_CallArgs
(
e
->
args
,
objStore
,
&
objc
);
if
(
!
objv
)
{
PyErr_Fetch
(
e
->
exc_type
,
e
->
exc_value
,
e
->
exc_tb
);
*
(
e
->
res
)
=
NULL
;
}
LEAVE_PYTHON
if
(
!
objv
)
goto
done
;
i
=
Tcl_EvalObjv
(
e
->
self
->
interp
,
objc
,
objv
,
e
->
flags
);
ENTER_PYTHON
if
(
i
==
TCL_ERROR
)
{
*
(
e
->
res
)
=
NULL
;
*
(
e
->
exc_type
)
=
NULL
;
*
(
e
->
exc_tb
)
=
NULL
;
*
(
e
->
exc_value
)
=
PyObject_CallFunction
(
Tkinter_TclError
,
"s"
,
Tcl_GetStringResult
(
e
->
self
->
interp
));
}
else
{
*
(
e
->
res
)
=
Tkapp_CallResult
(
e
->
self
);
}
LEAVE_PYTHON
done:
/* Wake up calling thread. */
Tcl_MutexLock
(
&
call_mutex
);
Tcl_ConditionNotify
(
&
e
->
done
);
Tcl_MutexUnlock
(
&
call_mutex
);
return
1
;
}
/* This is the main entry point for calling a Tcl command.
It supports three cases, with regard to threading:
1. Tcl is not threaded: Must have the Tcl lock, then can invoke command in
the context of the calling thread.
2. Tcl is threaded, caller of the command is in the interpreter thread:
Execute the command in the calling thread. Since the Tcl lock will
not be used, we can merge that with case 1.
3. Tcl is threaded, caller is in a different thread: Must queue an event to
the interpreter thread. Allocation of Tcl objects needs to occur in the
interpreter thread, so we ship the PyObject* args to the target thread,
and perform processing there. */
static
PyObject
*
Tkapp_Call
(
PyObject
*
_self
,
PyObject
*
args
)
{
Tcl_Obj
*
objStore
[
ARGSZ
];
Tcl_Obj
**
objv
=
NULL
;
int
objc
,
i
;
PyObject
*
res
=
NULL
;
TkappObject
*
self
=
(
TkappObject
*
)
_self
;
/* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */
int
flags
=
TCL_EVAL_DIRECT
;
if
(
self
->
threaded
&&
self
->
thread_id
!=
Tcl_GetCurrentThread
())
{
/* We cannot call the command directly. Instead, we must
marshal the parameters to the interpreter thread. */
Tkapp_CallEvent
*
ev
;
PyObject
*
exc_type
,
*
exc_value
,
*
exc_tb
;
if
(
!
self
->
dispatching
)
{
PyErr_SetString
(
PyExc_RuntimeError
,
"main thread is not in main loop"
);
return
NULL
;
}
ev
=
(
Tkapp_CallEvent
*
)
ckalloc
(
sizeof
(
Tkapp_CallEvent
));
ev
->
ev
.
proc
=
(
Tcl_EventProc
*
)
Tkapp_CallProc
;
ev
->
self
=
self
;
ev
->
args
=
args
;
ev
->
res
=
&
res
;
ev
->
exc_type
=
&
exc_type
;
ev
->
exc_value
=
&
exc_value
;
ev
->
exc_tb
=
&
exc_tb
;
ev
->
done
=
(
Tcl_Condition
)
0
;
Tkapp_ThreadSend
(
self
,
(
Tcl_Event
*
)
ev
,
&
ev
->
done
,
&
call_mutex
);
if
(
res
==
NULL
)
{
if
(
exc_type
)
PyErr_Restore
(
exc_type
,
exc_value
,
exc_tb
);
else
PyErr_SetObject
(
Tkinter_TclError
,
exc_value
);
}
}
else
{
objv
=
Tkapp_CallArgs
(
args
,
objStore
,
&
objc
);
if
(
!
objv
)
return
NULL
;
ENTER_TCL
i
=
Tcl_EvalObjv
(
self
->
interp
,
objc
,
objv
,
flags
);
ENTER_OVERLAP
if
(
i
==
TCL_ERROR
)
Tkinter_Error
(
_self
);
else
res
=
Tkapp_CallResult
(
self
);
LEAVE_OVERLAP_TCL
LEAVE_OVERLAP_TCL
finally:
Tkapp_CallDeallocArgs
(
objv
,
objStore
,
objc
);
for
(
i
=
0
;
i
<
objc
;
i
++
)
}
Tcl_DecrRefCount
(
objv
[
i
]);
if
(
objv
!=
objStore
)
ckfree
(
FREECAST
objv
);
return
res
;
return
res
;
}
}
...
@@ -1003,6 +1199,8 @@ Tkapp_GlobalCall(PyObject *self, PyObject *args)
...
@@ -1003,6 +1199,8 @@ Tkapp_GlobalCall(PyObject *self, PyObject *args)
char
*
cmd
;
char
*
cmd
;
PyObject
*
res
=
NULL
;
PyObject
*
res
=
NULL
;
CHECK_TCL_APPARTMENT
;
cmd
=
Merge
(
args
);
cmd
=
Merge
(
args
);
if
(
cmd
)
{
if
(
cmd
)
{
int
err
;
int
err
;
...
@@ -1030,6 +1228,8 @@ Tkapp_Eval(PyObject *self, PyObject *args)
...
@@ -1030,6 +1228,8 @@ Tkapp_Eval(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"s:eval"
,
&
script
))
if
(
!
PyArg_ParseTuple
(
args
,
"s:eval"
,
&
script
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
ENTER_TCL
ENTER_TCL
err
=
Tcl_Eval
(
Tkapp_Interp
(
self
),
script
);
err
=
Tcl_Eval
(
Tkapp_Interp
(
self
),
script
);
ENTER_OVERLAP
ENTER_OVERLAP
...
@@ -1051,6 +1251,8 @@ Tkapp_GlobalEval(PyObject *self, PyObject *args)
...
@@ -1051,6 +1251,8 @@ Tkapp_GlobalEval(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"s:globaleval"
,
&
script
))
if
(
!
PyArg_ParseTuple
(
args
,
"s:globaleval"
,
&
script
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
ENTER_TCL
ENTER_TCL
err
=
Tcl_GlobalEval
(
Tkapp_Interp
(
self
),
script
);
err
=
Tcl_GlobalEval
(
Tkapp_Interp
(
self
),
script
);
ENTER_OVERLAP
ENTER_OVERLAP
...
@@ -1072,6 +1274,8 @@ Tkapp_EvalFile(PyObject *self, PyObject *args)
...
@@ -1072,6 +1274,8 @@ Tkapp_EvalFile(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"s:evalfile"
,
&
fileName
))
if
(
!
PyArg_ParseTuple
(
args
,
"s:evalfile"
,
&
fileName
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
ENTER_TCL
ENTER_TCL
err
=
Tcl_EvalFile
(
Tkapp_Interp
(
self
),
fileName
);
err
=
Tcl_EvalFile
(
Tkapp_Interp
(
self
),
fileName
);
ENTER_OVERLAP
ENTER_OVERLAP
...
@@ -1094,6 +1298,8 @@ Tkapp_Record(PyObject *self, PyObject *args)
...
@@ -1094,6 +1298,8 @@ Tkapp_Record(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"s"
,
&
script
))
if
(
!
PyArg_ParseTuple
(
args
,
"s"
,
&
script
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
ENTER_TCL
ENTER_TCL
err
=
Tcl_RecordAndEval
(
Tkapp_Interp
(
self
),
script
,
TCL_NO_EVAL
);
err
=
Tcl_RecordAndEval
(
Tkapp_Interp
(
self
),
script
,
TCL_NO_EVAL
);
ENTER_OVERLAP
ENTER_OVERLAP
...
@@ -1112,6 +1318,8 @@ Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
...
@@ -1112,6 +1318,8 @@ Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"s:adderrorinfo"
,
&
msg
))
if
(
!
PyArg_ParseTuple
(
args
,
"s:adderrorinfo"
,
&
msg
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
ENTER_TCL
ENTER_TCL
Tcl_AddErrorInfo
(
Tkapp_Interp
(
self
),
msg
);
Tcl_AddErrorInfo
(
Tkapp_Interp
(
self
),
msg
);
LEAVE_TCL
LEAVE_TCL
...
@@ -1124,11 +1332,144 @@ Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
...
@@ -1124,11 +1332,144 @@ Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
/** Tcl Variable **/
/** Tcl Variable **/
TCL_DECLARE_MUTEX
(
var_mutex
)
typedef
const
char
*
(
*
EventFunc1
)(
Tcl_Interp
*
,
const
char
*
,
int
);
typedef
const
char
*
(
*
EventFunc2
)(
Tcl_Interp
*
,
const
char
*
,
const
char
*
,
int
);
typedef
const
char
*
(
*
EventFunc3
)(
Tcl_Interp
*
,
const
char
*
,
const
char
*
,
const
char
*
,
int
);
typedef
struct
VarEvent
{
Tcl_Event
ev
;
/* must be first */
TkappObject
*
self
;
char
*
arg1
;
char
*
arg2
;
char
*
arg3
;
int
flags
;
EventFunc1
func1
;
EventFunc2
func2
;
EventFunc3
func3
;
PyObject
**
res
;
PyObject
**
exc
;
Tcl_Condition
cond
;
int
coderesult
;
}
VarEvent
;
static
const
char
*
var_perform
(
VarEvent
*
ev
)
{
if
(
!
ev
->
arg2
&&
!
ev
->
arg2
)
return
ev
->
func1
(
ev
->
self
->
interp
,
ev
->
arg1
,
ev
->
flags
);
if
(
!
ev
->
arg3
)
return
ev
->
func2
(
ev
->
self
->
interp
,
ev
->
arg1
,
ev
->
arg2
,
ev
->
flags
);
return
ev
->
func3
(
ev
->
self
->
interp
,
ev
->
arg1
,
ev
->
arg2
,
ev
->
arg3
,
ev
->
flags
);
}
static
void
var_fill_result
(
VarEvent
*
ev
,
const
char
*
res
)
{
if
(
ev
->
coderesult
)
{
if
((
int
)
res
!=
TCL_ERROR
)
{
Py_INCREF
(
Py_None
);
*
(
ev
->
res
)
=
Py_None
;
return
;
}
}
else
if
(
res
)
{
*
(
ev
->
res
)
=
PyString_FromString
(
res
);
return
;
}
*
(
ev
->
res
)
=
NULL
;
*
(
ev
->
exc
)
=
PyObject_CallFunction
(
Tkinter_TclError
,
"s"
,
Tcl_GetStringResult
(
ev
->
self
->
interp
));
}
static
int
var_proc
(
VarEvent
*
ev
,
int
flags
)
{
const
char
*
result
=
var_perform
(
ev
);
ENTER_PYTHON
var_fill_result
(
ev
,
result
);
Tcl_MutexLock
(
&
var_mutex
);
Tcl_ConditionNotify
(
&
ev
->
cond
);
Tcl_MutexUnlock
(
&
var_mutex
);
LEAVE_PYTHON
return
1
;
}
static
PyObject
*
var_invoke
(
PyObject
*
_self
,
char
*
arg1
,
char
*
arg2
,
char
*
arg3
,
int
flags
,
EventFunc1
func1
,
EventFunc2
func2
,
EventFunc3
func3
,
int
coderesult
)
{
VarEvent
_ev
;
TkappObject
*
self
=
(
TkappObject
*
)
_self
;
VarEvent
*
ev
=
self
->
threaded
?
(
VarEvent
*
)
ckalloc
(
sizeof
(
VarEvent
))
:
&
_ev
;
PyObject
*
res
,
*
exc
;
ev
->
self
=
self
;
ev
->
arg1
=
arg1
;
ev
->
arg2
=
arg2
;
ev
->
arg3
=
arg3
;
ev
->
flags
=
flags
;
ev
->
func1
=
func1
;
ev
->
func2
=
func2
;
ev
->
func3
=
func3
;
ev
->
coderesult
=
coderesult
;
ev
->
res
=
&
res
;
ev
->
exc
=
&
exc
;
if
(
self
->
threaded
&&
self
->
thread_id
!=
Tcl_GetCurrentThread
())
{
/* The current thread is not the interpreter thread. Marshal
the call to the interpreter thread, then wait for
completion. */
if
(
!
self
->
dispatching
)
{
PyErr_SetString
(
PyExc_RuntimeError
,
"main thread is not in main loop"
);
return
NULL
;
}
ev
->
cond
=
NULL
;
ev
->
ev
.
proc
=
(
Tcl_EventProc
*
)
var_proc
;
Tkapp_ThreadSend
(
self
,
(
Tcl_Event
*
)
ev
,
&
ev
->
cond
,
&
var_mutex
);
}
else
{
/* Tcl is not threaded, or this is the interpreter thread. To
perform the call, we must hold the TCL lock. To receive the
results, we must also hold the Python lock. */
const
char
*
result
;
ENTER_TCL
result
=
var_perform
(
ev
);
ENTER_OVERLAP
var_fill_result
(
ev
,
result
);
LEAVE_OVERLAP_TCL
}
if
(
!
res
)
{
PyErr_SetObject
(
Tkinter_TclError
,
exc
);
return
NULL
;
}
return
res
;
}
static
PyObject
*
var_invoke2
(
PyObject
*
_self
,
char
*
arg1
,
char
*
arg2
,
char
*
arg3
,
int
flags
,
int
(
*
func1
)(
Tcl_Interp
*
,
const
char
*
,
int
),
int
(
*
func2
)(
Tcl_Interp
*
,
const
char
*
,
const
char
*
,
int
),
int
(
*
func3
)(
Tcl_Interp
*
,
const
char
*
,
const
char
*
,
const
char
*
,
int
))
{
return
var_invoke
(
_self
,
arg1
,
arg2
,
arg3
,
flags
,
(
EventFunc1
)
func1
,
(
EventFunc2
)
func2
,
(
EventFunc3
)
func3
,
1
);
}
static
PyObject
*
static
PyObject
*
SetVar
(
PyObject
*
self
,
PyObject
*
args
,
int
flags
)
SetVar
(
PyObject
*
self
,
PyObject
*
args
,
int
flags
)
{
{
char
*
name1
,
*
name2
,
*
s
;
char
*
name1
,
*
name2
,
*
s
;
const
char
*
ok
;
PyObject
*
res
;
PyObject
*
newValue
;
PyObject
*
newValue
;
PyObject
*
tmp
;
PyObject
*
tmp
;
...
@@ -1141,9 +1482,8 @@ SetVar(PyObject *self, PyObject *args, int flags)
...
@@ -1141,9 +1482,8 @@ SetVar(PyObject *self, PyObject *args, int flags)
s
=
AsString
(
newValue
,
tmp
);
s
=
AsString
(
newValue
,
tmp
);
if
(
s
==
NULL
)
if
(
s
==
NULL
)
return
NULL
;
return
NULL
;
ENTER_TCL
res
=
var_invoke
(
self
,
name1
,
s
,
NULL
,
flags
,
ok
=
Tcl_SetVar
(
Tkapp_Interp
(
self
),
name1
,
s
,
flags
);
NULL
,
Tcl_SetVar
,
NULL
,
0
);
LEAVE_TCL
}
}
else
{
else
{
PyErr_Clear
();
PyErr_Clear
();
...
@@ -1152,10 +1492,8 @@ SetVar(PyObject *self, PyObject *args, int flags)
...
@@ -1152,10 +1492,8 @@ SetVar(PyObject *self, PyObject *args, int flags)
s
=
AsString
(
newValue
,
tmp
);
s
=
AsString
(
newValue
,
tmp
);
if
(
s
==
NULL
)
if
(
s
==
NULL
)
return
NULL
;
return
NULL
;
ENTER_TCL
res
=
var_invoke
(
self
,
name1
,
name2
,
s
,
flags
,
ok
=
Tcl_SetVar2
(
Tkapp_Interp
(
self
),
name1
,
name2
,
NULL
,
NULL
,
Tcl_SetVar2
,
0
);
s
,
flags
);
LEAVE_TCL
}
}
else
{
else
{
Py_DECREF
(
tmp
);
Py_DECREF
(
tmp
);
...
@@ -1164,9 +1502,10 @@ SetVar(PyObject *self, PyObject *args, int flags)
...
@@ -1164,9 +1502,10 @@ SetVar(PyObject *self, PyObject *args, int flags)
}
}
Py_DECREF
(
tmp
);
Py_DECREF
(
tmp
);
if
(
!
ok
)
if
(
!
res
)
return
Tkinter_Error
(
self
)
;
return
NULL
;
Py_DECREF
(
res
);
Py_INCREF
(
Py_None
);
Py_INCREF
(
Py_None
);
return
Py_None
;
return
Py_None
;
}
}
...
@@ -1189,24 +1528,13 @@ static PyObject *
...
@@ -1189,24 +1528,13 @@ static PyObject *
GetVar
(
PyObject
*
self
,
PyObject
*
args
,
int
flags
)
GetVar
(
PyObject
*
self
,
PyObject
*
args
,
int
flags
)
{
{
char
*
name1
,
*
name2
=
NULL
;
char
*
name1
,
*
name2
=
NULL
;
const
char
*
s
;
PyObject
*
res
=
NULL
;
PyObject
*
res
=
NULL
;
if
(
!
PyArg_ParseTuple
(
args
,
"s|s:getvar"
,
&
name1
,
&
name2
))
if
(
!
PyArg_ParseTuple
(
args
,
"s|s:getvar"
,
&
name1
,
&
name2
))
return
NULL
;
return
NULL
;
ENTER_TCL
if
(
name2
==
NULL
)
s
=
Tcl_GetVar
(
Tkapp_Interp
(
self
),
name1
,
flags
);
else
s
=
Tcl_GetVar2
(
Tkapp_Interp
(
self
),
name1
,
name2
,
flags
);
ENTER_OVERLAP
if
(
s
==
NULL
)
res
=
var_invoke
(
self
,
name1
,
name2
,
NULL
,
flags
,
res
=
Tkinter_Error
(
self
);
Tcl_GetVar
,
Tcl_GetVar2
,
NULL
,
0
);
else
res
=
PyString_FromString
(
s
);
LEAVE_OVERLAP_TCL
return
res
;
return
res
;
}
}
...
@@ -1229,25 +1557,12 @@ UnsetVar(PyObject *self, PyObject *args, int flags)
...
@@ -1229,25 +1557,12 @@ UnsetVar(PyObject *self, PyObject *args, int flags)
{
{
char
*
name1
,
*
name2
=
NULL
;
char
*
name1
,
*
name2
=
NULL
;
PyObject
*
res
=
NULL
;
PyObject
*
res
=
NULL
;
int
code
;
if
(
!
PyArg_ParseTuple
(
args
,
"s|s:unsetvar"
,
&
name1
,
&
name2
))
if
(
!
PyArg_ParseTuple
(
args
,
"s|s:unsetvar"
,
&
name1
,
&
name2
))
return
NULL
;
return
NULL
;
ENTER_TCL
if
(
name2
==
NULL
)
code
=
Tcl_UnsetVar
(
Tkapp_Interp
(
self
),
name1
,
flags
);
else
code
=
Tcl_UnsetVar2
(
Tkapp_Interp
(
self
),
name1
,
name2
,
flags
);
ENTER_OVERLAP
if
(
code
==
TCL_ERROR
)
res
=
var_invoke2
(
self
,
name1
,
name2
,
NULL
,
flags
,
res
=
Tkinter_Error
(
self
);
Tcl_UnsetVar
,
Tcl_UnsetVar2
,
NULL
);
else
{
Py_INCREF
(
Py_None
);
res
=
Py_None
;
}
LEAVE_OVERLAP_TCL
return
res
;
return
res
;
}
}
...
@@ -1336,6 +1651,9 @@ Tkapp_ExprString(PyObject *self, PyObject *args)
...
@@ -1336,6 +1651,9 @@ Tkapp_ExprString(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"s:exprstring"
,
&
s
))
if
(
!
PyArg_ParseTuple
(
args
,
"s:exprstring"
,
&
s
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
ENTER_TCL
ENTER_TCL
retval
=
Tcl_ExprString
(
Tkapp_Interp
(
self
),
s
);
retval
=
Tcl_ExprString
(
Tkapp_Interp
(
self
),
s
);
ENTER_OVERLAP
ENTER_OVERLAP
...
@@ -1357,6 +1675,9 @@ Tkapp_ExprLong(PyObject *self, PyObject *args)
...
@@ -1357,6 +1675,9 @@ Tkapp_ExprLong(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"s:exprlong"
,
&
s
))
if
(
!
PyArg_ParseTuple
(
args
,
"s:exprlong"
,
&
s
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
ENTER_TCL
ENTER_TCL
retval
=
Tcl_ExprLong
(
Tkapp_Interp
(
self
),
s
,
&
v
);
retval
=
Tcl_ExprLong
(
Tkapp_Interp
(
self
),
s
,
&
v
);
ENTER_OVERLAP
ENTER_OVERLAP
...
@@ -1378,6 +1699,7 @@ Tkapp_ExprDouble(PyObject *self, PyObject *args)
...
@@ -1378,6 +1699,7 @@ Tkapp_ExprDouble(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"s:exprdouble"
,
&
s
))
if
(
!
PyArg_ParseTuple
(
args
,
"s:exprdouble"
,
&
s
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
PyFPE_START_PROTECT
(
"Tkapp_ExprDouble"
,
return
0
)
PyFPE_START_PROTECT
(
"Tkapp_ExprDouble"
,
return
0
)
ENTER_TCL
ENTER_TCL
retval
=
Tcl_ExprDouble
(
Tkapp_Interp
(
self
),
s
,
&
v
);
retval
=
Tcl_ExprDouble
(
Tkapp_Interp
(
self
),
s
,
&
v
);
...
@@ -1401,6 +1723,7 @@ Tkapp_ExprBoolean(PyObject *self, PyObject *args)
...
@@ -1401,6 +1723,7 @@ Tkapp_ExprBoolean(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"s:exprboolean"
,
&
s
))
if
(
!
PyArg_ParseTuple
(
args
,
"s:exprboolean"
,
&
s
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
ENTER_TCL
ENTER_TCL
retval
=
Tcl_ExprBoolean
(
Tkapp_Interp
(
self
),
s
,
&
v
);
retval
=
Tcl_ExprBoolean
(
Tkapp_Interp
(
self
),
s
,
&
v
);
ENTER_OVERLAP
ENTER_OVERLAP
...
@@ -1575,13 +1898,42 @@ PythonCmdDelete(ClientData clientData)
...
@@ -1575,13 +1898,42 @@ PythonCmdDelete(ClientData clientData)
TCL_DECLARE_MUTEX
(
command_mutex
)
typedef
struct
CommandEvent
{
Tcl_Event
ev
;
Tcl_Interp
*
interp
;
char
*
name
;
int
create
;
int
*
status
;
ClientData
*
data
;
Tcl_Condition
done
;
}
CommandEvent
;
static
int
Tkapp_CommandProc
(
CommandEvent
*
ev
,
int
flags
)
{
if
(
ev
->
create
)
*
ev
->
status
=
Tcl_CreateCommand
(
ev
->
interp
,
ev
->
name
,
PythonCmd
,
ev
->
data
,
PythonCmdDelete
)
==
NULL
;
else
*
ev
->
status
=
Tcl_DeleteCommand
(
ev
->
interp
,
ev
->
name
);
Tcl_MutexLock
(
&
command_mutex
);
Tcl_ConditionNotify
(
&
ev
->
done
);
Tcl_MutexUnlock
(
&
command_mutex
);
return
1
;
}
static
PyObject
*
static
PyObject
*
Tkapp_CreateCommand
(
PyObject
*
self
,
PyObject
*
args
)
Tkapp_CreateCommand
(
PyObject
*
_
self
,
PyObject
*
args
)
{
{
TkappObject
*
self
=
(
TkappObject
*
)
_self
;
PythonCmd_ClientData
*
data
;
PythonCmd_ClientData
*
data
;
char
*
cmdName
;
char
*
cmdName
;
PyObject
*
func
;
PyObject
*
func
;
Tcl_Command
err
;
int
err
;
if
(
!
PyArg_ParseTuple
(
args
,
"sO:createcommand"
,
&
cmdName
,
&
func
))
if
(
!
PyArg_ParseTuple
(
args
,
"sO:createcommand"
,
&
cmdName
,
&
func
))
return
NULL
;
return
NULL
;
...
@@ -1590,19 +1942,40 @@ Tkapp_CreateCommand(PyObject *self, PyObject *args)
...
@@ -1590,19 +1942,40 @@ Tkapp_CreateCommand(PyObject *self, PyObject *args)
return
NULL
;
return
NULL
;
}
}
if
(
self
->
threaded
&&
self
->
thread_id
!=
Tcl_GetCurrentThread
()
&&
!
self
->
dispatching
)
{
PyErr_SetString
(
PyExc_RuntimeError
,
"main thread is not in main loop"
);
return
NULL
;
}
data
=
PyMem_NEW
(
PythonCmd_ClientData
,
1
);
data
=
PyMem_NEW
(
PythonCmd_ClientData
,
1
);
if
(
!
data
)
if
(
!
data
)
return
NULL
;
return
NULL
;
Py_XINCREF
(
self
);
Py_XINCREF
(
self
);
Py_XINCREF
(
func
);
Py_XINCREF
(
func
);
data
->
self
=
self
;
data
->
self
=
_
self
;
data
->
func
=
func
;
data
->
func
=
func
;
if
(
self
->
threaded
&&
self
->
thread_id
!=
Tcl_GetCurrentThread
())
{
CommandEvent
*
ev
=
(
CommandEvent
*
)
ckalloc
(
sizeof
(
CommandEvent
));
ev
->
ev
.
proc
=
(
Tcl_EventProc
*
)
Tkapp_CommandProc
;
ev
->
interp
=
self
->
interp
;
ev
->
create
=
1
;
ev
->
name
=
cmdName
;
ev
->
data
=
(
ClientData
)
data
;
ev
->
status
=
&
err
;
ev
->
done
=
NULL
;
Tkapp_ThreadSend
(
self
,
(
Tcl_Event
*
)
ev
,
&
ev
->
done
,
&
command_mutex
);
}
else
{
ENTER_TCL
ENTER_TCL
err
=
Tcl_CreateCommand
(
Tkapp_Interp
(
self
),
cmdName
,
PythonCmd
,
err
=
Tcl_CreateCommand
(
(
ClientData
)
data
,
PythonCmdDelete
);
Tkapp_Interp
(
self
),
cmdName
,
PythonCmd
,
(
ClientData
)
data
,
PythonCmdDelete
)
==
NULL
;
LEAVE_TCL
LEAVE_TCL
if
(
err
==
NULL
)
{
}
if
(
err
)
{
PyErr_SetString
(
Tkinter_TclError
,
"can't create Tcl command"
);
PyErr_SetString
(
Tkinter_TclError
,
"can't create Tcl command"
);
PyMem_DEL
(
data
);
PyMem_DEL
(
data
);
return
NULL
;
return
NULL
;
...
@@ -1615,16 +1988,31 @@ Tkapp_CreateCommand(PyObject *self, PyObject *args)
...
@@ -1615,16 +1988,31 @@ Tkapp_CreateCommand(PyObject *self, PyObject *args)
static
PyObject
*
static
PyObject
*
Tkapp_DeleteCommand
(
PyObject
*
self
,
PyObject
*
args
)
Tkapp_DeleteCommand
(
PyObject
*
_
self
,
PyObject
*
args
)
{
{
TkappObject
*
self
=
(
TkappObject
*
)
_self
;
char
*
cmdName
;
char
*
cmdName
;
int
err
;
int
err
;
if
(
!
PyArg_ParseTuple
(
args
,
"s:deletecommand"
,
&
cmdName
))
if
(
!
PyArg_ParseTuple
(
args
,
"s:deletecommand"
,
&
cmdName
))
return
NULL
;
return
NULL
;
if
(
self
->
threaded
&&
self
->
thread_id
!=
Tcl_GetCurrentThread
())
{
CommandEvent
*
ev
;
ev
=
(
CommandEvent
*
)
ckalloc
(
sizeof
(
CommandEvent
));
ev
->
ev
.
proc
=
(
Tcl_EventProc
*
)
Tkapp_CommandProc
;
ev
->
interp
=
self
->
interp
;
ev
->
create
=
0
;
ev
->
name
=
cmdName
;
ev
->
status
=
&
err
;
ev
->
done
=
NULL
;
Tkapp_ThreadSend
(
self
,
(
Tcl_Event
*
)
ev
,
&
ev
->
done
,
&
command_mutex
);
}
else
{
ENTER_TCL
ENTER_TCL
err
=
Tcl_DeleteCommand
(
Tkapp_Interp
(
self
)
,
cmdName
);
err
=
Tcl_DeleteCommand
(
self
->
interp
,
cmdName
);
LEAVE_TCL
LEAVE_TCL
}
if
(
err
==
-
1
)
{
if
(
err
==
-
1
)
{
PyErr_SetString
(
Tkinter_TclError
,
"can't delete Tcl command"
);
PyErr_SetString
(
Tkinter_TclError
,
"can't delete Tcl command"
);
return
NULL
;
return
NULL
;
...
@@ -1715,6 +2103,7 @@ Tkapp_CreateFileHandler(PyObject *self, PyObject *args)
...
@@ -1715,6 +2103,7 @@ Tkapp_CreateFileHandler(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"OiO:createfilehandler"
,
if
(
!
PyArg_ParseTuple
(
args
,
"OiO:createfilehandler"
,
&
file
,
&
mask
,
&
func
))
&
file
,
&
mask
,
&
func
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
tfile
=
PyObject_AsFileDescriptor
(
file
);
tfile
=
PyObject_AsFileDescriptor
(
file
);
if
(
tfile
<
0
)
if
(
tfile
<
0
)
return
NULL
;
return
NULL
;
...
@@ -1743,6 +2132,7 @@ Tkapp_DeleteFileHandler(PyObject *self, PyObject *args)
...
@@ -1743,6 +2132,7 @@ Tkapp_DeleteFileHandler(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"O:deletefilehandler"
,
&
file
))
if
(
!
PyArg_ParseTuple
(
args
,
"O:deletefilehandler"
,
&
file
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
tfile
=
PyObject_AsFileDescriptor
(
file
);
tfile
=
PyObject_AsFileDescriptor
(
file
);
if
(
tfile
<
0
)
if
(
tfile
<
0
)
return
NULL
;
return
NULL
;
...
@@ -1918,9 +2308,10 @@ Tkapp_CreateTimerHandler(PyObject *self, PyObject *args)
...
@@ -1918,9 +2308,10 @@ Tkapp_CreateTimerHandler(PyObject *self, PyObject *args)
/** Event Loop **/
/** Event Loop **/
static
PyObject
*
static
PyObject
*
Tkapp_MainLoop
(
PyObject
*
self
,
PyObject
*
args
)
Tkapp_MainLoop
(
PyObject
*
_
self
,
PyObject
*
args
)
{
{
int
threshold
=
0
;
int
threshold
=
0
;
TkappObject
*
self
=
(
TkappObject
*
)
_self
;
#ifdef WITH_THREAD
#ifdef WITH_THREAD
PyThreadState
*
tstate
=
PyThreadState_Get
();
PyThreadState
*
tstate
=
PyThreadState_Get
();
#endif
#endif
...
@@ -1928,7 +2319,10 @@ Tkapp_MainLoop(PyObject *self, PyObject *args)
...
@@ -1928,7 +2319,10 @@ Tkapp_MainLoop(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"|i:mainloop"
,
&
threshold
))
if
(
!
PyArg_ParseTuple
(
args
,
"|i:mainloop"
,
&
threshold
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
quitMainLoop
=
0
;
quitMainLoop
=
0
;
self
->
dispatching
=
1
;
while
(
Tk_GetNumMainWindows
()
>
threshold
&&
while
(
Tk_GetNumMainWindows
()
>
threshold
&&
!
quitMainLoop
&&
!
quitMainLoop
&&
!
errorInCmd
)
!
errorInCmd
)
...
@@ -1936,24 +2330,35 @@ Tkapp_MainLoop(PyObject *self, PyObject *args)
...
@@ -1936,24 +2330,35 @@ Tkapp_MainLoop(PyObject *self, PyObject *args)
int
result
;
int
result
;
#ifdef WITH_THREAD
#ifdef WITH_THREAD
if
(
self
->
threaded
)
{
/* Allow other Python threads to run. */
ENTER_TCL
result
=
Tcl_DoOneEvent
(
0
);
LEAVE_TCL
}
else
{
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS
PyThread_acquire_lock
(
tcl_lock
,
1
);
if
(
tcl_lock
)
PyThread_acquire_lock
(
tcl_lock
,
1
);
tcl_tstate
=
tstate
;
tcl_tstate
=
tstate
;
result
=
Tcl_DoOneEvent
(
TCL_DONT_WAIT
);
result
=
Tcl_DoOneEvent
(
TCL_DONT_WAIT
);
tcl_tstate
=
NULL
;
tcl_tstate
=
NULL
;
PyThread_release_lock
(
tcl_lock
);
if
(
tcl_lock
)
PyThread_release_lock
(
tcl_lock
);
if
(
result
==
0
)
if
(
result
==
0
)
Sleep
(
20
);
Sleep
(
20
);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS
}
#else
#else
result
=
Tcl_DoOneEvent
(
0
);
result
=
Tcl_DoOneEvent
(
0
);
#endif
#endif
if
(
PyErr_CheckSignals
()
!=
0
)
if
(
PyErr_CheckSignals
()
!=
0
)
{
self
->
dispatching
=
0
;
return
NULL
;
return
NULL
;
}
if
(
result
<
0
)
if
(
result
<
0
)
break
;
break
;
}
}
self
->
dispatching
=
0
;
quitMainLoop
=
0
;
quitMainLoop
=
0
;
if
(
errorInCmd
)
{
if
(
errorInCmd
)
{
...
@@ -1974,6 +2379,7 @@ Tkapp_DoOneEvent(PyObject *self, PyObject *args)
...
@@ -1974,6 +2379,7 @@ Tkapp_DoOneEvent(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"|i:dooneevent"
,
&
flags
))
if
(
!
PyArg_ParseTuple
(
args
,
"|i:dooneevent"
,
&
flags
))
return
NULL
;
return
NULL
;
CHECK_TCL_APPARTMENT
;
ENTER_TCL
ENTER_TCL
rv
=
Tcl_DoOneEvent
(
flags
);
rv
=
Tcl_DoOneEvent
(
flags
);
...
@@ -2068,6 +2474,7 @@ static PyMethodDef Tkapp_methods[] =
...
@@ -2068,6 +2474,7 @@ static PyMethodDef Tkapp_methods[] =
static
void
static
void
Tkapp_Dealloc
(
PyObject
*
self
)
Tkapp_Dealloc
(
PyObject
*
self
)
{
{
//CHECK_TCL_APPARTMENT;
ENTER_TCL
ENTER_TCL
Tcl_DeleteInterp
(
Tkapp_Interp
(
self
));
Tcl_DeleteInterp
(
Tkapp_Interp
(
self
));
LEAVE_TCL
LEAVE_TCL
...
@@ -2292,13 +2699,13 @@ EventHook(void)
...
@@ -2292,13 +2699,13 @@ EventHook(void)
#endif
#endif
#if defined(WITH_THREAD) || defined(MS_WINDOWS)
#if defined(WITH_THREAD) || defined(MS_WINDOWS)
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS
PyThread_acquire_lock
(
tcl_lock
,
1
);
if
(
tcl_lock
)
PyThread_acquire_lock
(
tcl_lock
,
1
);
tcl_tstate
=
event_tstate
;
tcl_tstate
=
event_tstate
;
result
=
Tcl_DoOneEvent
(
TCL_DONT_WAIT
);
result
=
Tcl_DoOneEvent
(
TCL_DONT_WAIT
);
tcl_tstate
=
NULL
;
tcl_tstate
=
NULL
;
PyThread_release_lock
(
tcl_lock
);
if
(
tcl_lock
)
PyThread_release_lock
(
tcl_lock
);
if
(
result
==
0
)
if
(
result
==
0
)
Sleep
(
20
);
Sleep
(
20
);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment