@@ -306,6 +306,7 @@ typedef struct {
306
306
int threaded ; /* True if tcl_platform[threaded] */
307
307
Tcl_ThreadId thread_id ;
308
308
int dispatching ;
309
+ PyObject * trace ;
309
310
/* We cannot include tclInt.h, as this is internal.
310
311
So we cache interesting types here. */
311
312
const Tcl_ObjType * OldBooleanType ;
@@ -570,6 +571,7 @@ Tkapp_New(const char *screenName, const char *className,
570
571
TCL_GLOBAL_ONLY ) != NULL ;
571
572
v -> thread_id = Tcl_GetCurrentThread ();
572
573
v -> dispatching = 0 ;
574
+ v -> trace = NULL ;
573
575
574
576
#ifndef TCL_THREADS
575
577
if (v -> threaded ) {
@@ -1306,6 +1308,29 @@ Tkapp_ObjectResult(TkappObject *self)
1306
1308
return res ;
1307
1309
}
1308
1310
1311
+ static int
1312
+ Tkapp_Trace (TkappObject * self , PyObject * args )
1313
+ {
1314
+ if (args == NULL ) {
1315
+ return 0 ;
1316
+ }
1317
+ if (self -> trace ) {
1318
+ PyObject * res = PyObject_CallObject (self -> trace , args );
1319
+ if (res == NULL ) {
1320
+ Py_DECREF (args );
1321
+ return 0 ;
1322
+ }
1323
+ Py_DECREF (res );
1324
+ }
1325
+ Py_DECREF (args );
1326
+ return 1 ;
1327
+ }
1328
+
1329
+ #define TRACE (_self , ARGS ) do { \
1330
+ if ((_self)->trace && !Tkapp_Trace((_self), Py_BuildValue ARGS)) { \
1331
+ return NULL; \
1332
+ } \
1333
+ } while (0)
1309
1334
1310
1335
/* Tkapp_CallProc is the event procedure that is executed in the context of
1311
1336
the Tcl interpreter thread. Initially, it holds the Tcl lock, and doesn't
@@ -1320,7 +1345,12 @@ Tkapp_CallProc(Tcl_Event *evPtr, int flags)
1320
1345
int objc ;
1321
1346
int i ;
1322
1347
ENTER_PYTHON
1323
- objv = Tkapp_CallArgs (e -> args , objStore , & objc );
1348
+ if (e -> self -> trace && !Tkapp_Trace (e -> self , PyTuple_Pack (1 , e -> args ))) {
1349
+ objv = NULL ;
1350
+ }
1351
+ else {
1352
+ objv = Tkapp_CallArgs (e -> args , objStore , & objc );
1353
+ }
1324
1354
if (!objv ) {
1325
1355
* (e -> exc ) = PyErr_GetRaisedException ();
1326
1356
* (e -> res ) = NULL ;
@@ -1413,6 +1443,7 @@ Tkapp_Call(PyObject *selfptr, PyObject *args)
1413
1443
}
1414
1444
else
1415
1445
{
1446
+ TRACE (self , ("(O)" , args ));
1416
1447
1417
1448
objv = Tkapp_CallArgs (args , objStore , & objc );
1418
1449
if (!objv )
@@ -1455,6 +1486,8 @@ _tkinter_tkapp_eval_impl(TkappObject *self, const char *script)
1455
1486
CHECK_STRING_LENGTH (script );
1456
1487
CHECK_TCL_APPARTMENT ;
1457
1488
1489
+ TRACE (self , ("((ss))" , "eval" , script ));
1490
+
1458
1491
ENTER_TCL
1459
1492
err = Tcl_Eval (Tkapp_Interp (self ), script );
1460
1493
ENTER_OVERLAP
@@ -1484,6 +1517,8 @@ _tkinter_tkapp_evalfile_impl(TkappObject *self, const char *fileName)
1484
1517
CHECK_STRING_LENGTH (fileName );
1485
1518
CHECK_TCL_APPARTMENT ;
1486
1519
1520
+ TRACE (self , ("((ss))" , "source" , fileName ));
1521
+
1487
1522
ENTER_TCL
1488
1523
err = Tcl_EvalFile (Tkapp_Interp (self ), fileName );
1489
1524
ENTER_OVERLAP
@@ -1513,6 +1548,8 @@ _tkinter_tkapp_record_impl(TkappObject *self, const char *script)
1513
1548
CHECK_STRING_LENGTH (script );
1514
1549
CHECK_TCL_APPARTMENT ;
1515
1550
1551
+ TRACE (self , ("((ssss))" , "history" , "add" , script , "exec" ));
1552
+
1516
1553
ENTER_TCL
1517
1554
err = Tcl_RecordAndEval (Tkapp_Interp (self ), script , TCL_NO_EVAL );
1518
1555
ENTER_OVERLAP
@@ -1702,6 +1739,15 @@ SetVar(TkappObject *self, PyObject *args, int flags)
1702
1739
newval = AsObj (newValue );
1703
1740
if (newval == NULL )
1704
1741
return NULL ;
1742
+
1743
+ if (flags & TCL_GLOBAL_ONLY ) {
1744
+ TRACE ((TkappObject * )self , ("((ssssO))" , "uplevel" , "#0" , "set" ,
1745
+ name1 , newValue ));
1746
+ }
1747
+ else {
1748
+ TRACE ((TkappObject * )self , ("((ssO))" , "set" , name1 , newValue ));
1749
+ }
1750
+
1705
1751
ENTER_TCL
1706
1752
ok = Tcl_SetVar2Ex (Tkapp_Interp (self ), name1 , NULL ,
1707
1753
newval , flags );
@@ -1719,8 +1765,22 @@ SetVar(TkappObject *self, PyObject *args, int flags)
1719
1765
return NULL ;
1720
1766
CHECK_STRING_LENGTH (name1 );
1721
1767
CHECK_STRING_LENGTH (name2 );
1768
+
1722
1769
/* XXX must hold tcl lock already??? */
1723
1770
newval = AsObj (newValue );
1771
+ if (((TkappObject * )self )-> trace ) {
1772
+ if (flags & TCL_GLOBAL_ONLY ) {
1773
+ TRACE ((TkappObject * )self , ("((sssNO))" , "uplevel" , "#0" , "set" ,
1774
+ PyUnicode_FromFormat ("%s(%s)" , name1 , name2 ),
1775
+ newValue ));
1776
+ }
1777
+ else {
1778
+ TRACE ((TkappObject * )self , ("((sNO))" , "set" ,
1779
+ PyUnicode_FromFormat ("%s(%s)" , name1 , name2 ),
1780
+ newValue ));
1781
+ }
1782
+ }
1783
+
1724
1784
ENTER_TCL
1725
1785
ok = Tcl_SetVar2Ex (Tkapp_Interp (self ), name1 , name2 , newval , flags );
1726
1786
ENTER_OVERLAP
@@ -1807,6 +1867,28 @@ UnsetVar(TkappObject *self, PyObject *args, int flags)
1807
1867
1808
1868
CHECK_STRING_LENGTH (name1 );
1809
1869
CHECK_STRING_LENGTH (name2 );
1870
+
1871
+ if (((TkappObject * )self )-> trace ) {
1872
+ if (flags & TCL_GLOBAL_ONLY ) {
1873
+ if (name2 ) {
1874
+ TRACE ((TkappObject * )self , ("((sssN))" , "uplevel" , "#0" , "unset" ,
1875
+ PyUnicode_FromFormat ("%s(%s)" , name1 , name2 )));
1876
+ }
1877
+ else {
1878
+ TRACE ((TkappObject * )self , ("((ssss))" , "uplevel" , "#0" , "unset" , name1 ));
1879
+ }
1880
+ }
1881
+ else {
1882
+ if (name2 ) {
1883
+ TRACE ((TkappObject * )self , ("((sN))" , "unset" ,
1884
+ PyUnicode_FromFormat ("%s(%s)" , name1 , name2 )));
1885
+ }
1886
+ else {
1887
+ TRACE ((TkappObject * )self , ("((ss))" , "unset" , name1 ));
1888
+ }
1889
+ }
1890
+ }
1891
+
1810
1892
ENTER_TCL
1811
1893
code = Tcl_UnsetVar2 (Tkapp_Interp (self ), name1 , name2 , flags );
1812
1894
ENTER_OVERLAP
@@ -1973,6 +2055,8 @@ _tkinter_tkapp_exprstring_impl(TkappObject *self, const char *s)
1973
2055
CHECK_STRING_LENGTH (s );
1974
2056
CHECK_TCL_APPARTMENT ;
1975
2057
2058
+ TRACE (self , ("((ss))" , "expr" , s ));
2059
+
1976
2060
ENTER_TCL
1977
2061
retval = Tcl_ExprString (Tkapp_Interp (self ), s );
1978
2062
ENTER_OVERLAP
@@ -2003,6 +2087,8 @@ _tkinter_tkapp_exprlong_impl(TkappObject *self, const char *s)
2003
2087
CHECK_STRING_LENGTH (s );
2004
2088
CHECK_TCL_APPARTMENT ;
2005
2089
2090
+ TRACE (self , ("((ss))" , "expr" , s ));
2091
+
2006
2092
ENTER_TCL
2007
2093
retval = Tcl_ExprLong (Tkapp_Interp (self ), s , & v );
2008
2094
ENTER_OVERLAP
@@ -2032,6 +2118,9 @@ _tkinter_tkapp_exprdouble_impl(TkappObject *self, const char *s)
2032
2118
2033
2119
CHECK_STRING_LENGTH (s );
2034
2120
CHECK_TCL_APPARTMENT ;
2121
+
2122
+ TRACE (self , ("((ss))" , "expr" , s ));
2123
+
2035
2124
ENTER_TCL
2036
2125
retval = Tcl_ExprDouble (Tkapp_Interp (self ), s , & v );
2037
2126
ENTER_OVERLAP
@@ -2061,6 +2150,9 @@ _tkinter_tkapp_exprboolean_impl(TkappObject *self, const char *s)
2061
2150
2062
2151
CHECK_STRING_LENGTH (s );
2063
2152
CHECK_TCL_APPARTMENT ;
2153
+
2154
+ TRACE (self , ("((ss))" , "expr" , s ));
2155
+
2064
2156
ENTER_TCL
2065
2157
retval = Tcl_ExprBoolean (Tkapp_Interp (self ), s , & v );
2066
2158
ENTER_OVERLAP
@@ -2286,6 +2378,8 @@ _tkinter_tkapp_createcommand_impl(TkappObject *self, const char *name,
2286
2378
!WaitForMainloop (self ))
2287
2379
return NULL ;
2288
2380
2381
+ TRACE (self , ("((ss()O))" , "proc" , name , func ));
2382
+
2289
2383
data = PyMem_NEW (PythonCmd_ClientData , 1 );
2290
2384
if (!data )
2291
2385
return PyErr_NoMemory ();
@@ -2344,6 +2438,8 @@ _tkinter_tkapp_deletecommand_impl(TkappObject *self, const char *name)
2344
2438
2345
2439
CHECK_STRING_LENGTH (name );
2346
2440
2441
+ TRACE (self , ("((sss))" , "rename" , name , "" ));
2442
+
2347
2443
if (self -> threaded && self -> thread_id != Tcl_GetCurrentThread ()) {
2348
2444
Tcl_Condition cond = NULL ;
2349
2445
CommandEvent * ev ;
@@ -2469,6 +2565,8 @@ _tkinter_tkapp_createfilehandler_impl(TkappObject *self, PyObject *file,
2469
2565
return NULL ;
2470
2566
}
2471
2567
2568
+ TRACE (self , ("((ssiiO))" , "#" , "createfilehandler" , tfile , mask , func ));
2569
+
2472
2570
data = NewFHCD (func , file , tfile );
2473
2571
if (data == NULL )
2474
2572
return NULL ;
@@ -2500,6 +2598,8 @@ _tkinter_tkapp_deletefilehandler(TkappObject *self, PyObject *file)
2500
2598
if (tfile < 0 )
2501
2599
return NULL ;
2502
2600
2601
+ TRACE (self , ("((ssi))" , "#" , "deletefilehandler" , tfile ));
2602
+
2503
2603
DeleteFHCD (tfile );
2504
2604
2505
2605
/* Ought to check for null Tcl_File object... */
@@ -2534,6 +2634,7 @@ _tkinter_tktimertoken_deletetimerhandler_impl(TkttObject *self)
2534
2634
PyObject * func = v -> func ;
2535
2635
2536
2636
if (v -> token != NULL ) {
2637
+ /* TRACE(...) */
2537
2638
Tcl_DeleteTimerHandler (v -> token );
2538
2639
v -> token = NULL ;
2539
2640
}
@@ -2636,6 +2737,8 @@ _tkinter_tkapp_createtimerhandler_impl(TkappObject *self, int milliseconds,
2636
2737
2637
2738
CHECK_TCL_APPARTMENT ;
2638
2739
2740
+ TRACE (self , ("((siO))" , "after" , milliseconds , func ));
2741
+
2639
2742
v = Tktt_New (func );
2640
2743
if (v ) {
2641
2744
v -> token = Tcl_CreateTimerHandler (milliseconds , TimerHandler ,
@@ -2803,6 +2906,47 @@ Tkapp_WantObjects(PyObject *self, PyObject *args)
2803
2906
Py_RETURN_NONE ;
2804
2907
}
2805
2908
2909
+ /*[clinic input]
2910
+ _tkinter.tkapp.settrace
2911
+
2912
+ func: object
2913
+ /
2914
+
2915
+ Set the tracing function.
2916
+ [clinic start generated code]*/
2917
+
2918
+ static PyObject *
2919
+ _tkinter_tkapp_settrace (TkappObject * self , PyObject * func )
2920
+ /*[clinic end generated code: output=847f6ebdf46e84fa input=31b260d46d3d018a]*/
2921
+ {
2922
+ if (func == Py_None ) {
2923
+ func = NULL ;
2924
+ }
2925
+ else {
2926
+ Py_INCREF (func );
2927
+ }
2928
+ Py_XSETREF (self -> trace , func );
2929
+ Py_RETURN_NONE ;
2930
+ }
2931
+
2932
+ /*[clinic input]
2933
+ _tkinter.tkapp.gettrace
2934
+
2935
+ Get the tracing function.
2936
+ [clinic start generated code]*/
2937
+
2938
+ static PyObject *
2939
+ _tkinter_tkapp_gettrace_impl (TkappObject * self )
2940
+ /*[clinic end generated code: output=d4e2ba7d63e77bb5 input=ac2aea5be74e8c4c]*/
2941
+ {
2942
+ PyObject * func = self -> trace ;
2943
+ if (!func ) {
2944
+ func = Py_None ;
2945
+ }
2946
+ Py_INCREF (func );
2947
+ return func ;
2948
+ }
2949
+
2806
2950
/*[clinic input]
2807
2951
_tkinter.tkapp.willdispatch
2808
2952
@@ -3038,6 +3182,8 @@ static PyMethodDef Tkapp_methods[] =
3038
3182
{
3039
3183
_TKINTER_TKAPP_WILLDISPATCH_METHODDEF
3040
3184
{"wantobjects" , Tkapp_WantObjects , METH_VARARGS },
3185
+ _TKINTER_TKAPP_SETTRACE_METHODDEF
3186
+ _TKINTER_TKAPP_GETTRACE_METHODDEF
3041
3187
{"call ", Tkapp_Call , METH_VARARGS },
3042
3188
_TKINTER_TKAPP_EVAL_METHODDEF
3043
3189
_TKINTER_TKAPP_EVALFILE_METHODDEF
0 commit comments