@@ -309,6 +309,7 @@ typedef struct {
309
309
int threaded ; /* True if tcl_platform[threaded] */
310
310
Tcl_ThreadId thread_id ;
311
311
int dispatching ;
312
+ PyObject * trace ;
312
313
/* We cannot include tclInt.h, as this is internal.
313
314
So we cache interesting types here. */
314
315
const Tcl_ObjType * OldBooleanType ;
@@ -574,6 +575,7 @@ Tkapp_New(const char *screenName, const char *className,
574
575
TCL_GLOBAL_ONLY ) != NULL ;
575
576
v -> thread_id = Tcl_GetCurrentThread ();
576
577
v -> dispatching = 0 ;
578
+ v -> trace = NULL ;
577
579
578
580
#ifndef TCL_THREADS
579
581
if (v -> threaded ) {
@@ -1316,6 +1318,29 @@ Tkapp_ObjectResult(TkappObject *self)
1316
1318
return res ;
1317
1319
}
1318
1320
1321
+ static int
1322
+ Tkapp_Trace (TkappObject * self , PyObject * args )
1323
+ {
1324
+ if (args == NULL ) {
1325
+ return 0 ;
1326
+ }
1327
+ if (self -> trace ) {
1328
+ PyObject * res = PyObject_CallObject (self -> trace , args );
1329
+ if (res == NULL ) {
1330
+ Py_DECREF (args );
1331
+ return 0 ;
1332
+ }
1333
+ Py_DECREF (res );
1334
+ }
1335
+ Py_DECREF (args );
1336
+ return 1 ;
1337
+ }
1338
+
1339
+ #define TRACE (_self , ARGS ) do { \
1340
+ if ((_self)->trace && !Tkapp_Trace((_self), Py_BuildValue ARGS)) { \
1341
+ return NULL; \
1342
+ } \
1343
+ } while (0)
1319
1344
1320
1345
/* Tkapp_CallProc is the event procedure that is executed in the context of
1321
1346
the Tcl interpreter thread. Initially, it holds the Tcl lock, and doesn't
@@ -1329,7 +1354,12 @@ Tkapp_CallProc(Tkapp_CallEvent *e, int flags)
1329
1354
int objc ;
1330
1355
int i ;
1331
1356
ENTER_PYTHON
1332
- objv = Tkapp_CallArgs (e -> args , objStore , & objc );
1357
+ if (e -> self -> trace && !Tkapp_Trace (e -> self , PyTuple_Pack (1 , e -> args ))) {
1358
+ objv = NULL ;
1359
+ }
1360
+ else {
1361
+ objv = Tkapp_CallArgs (e -> args , objStore , & objc );
1362
+ }
1333
1363
if (!objv ) {
1334
1364
* (e -> exc ) = PyErr_GetRaisedException ();
1335
1365
* (e -> res ) = NULL ;
@@ -1422,6 +1452,7 @@ Tkapp_Call(PyObject *selfptr, PyObject *args)
1422
1452
}
1423
1453
else
1424
1454
{
1455
+ TRACE (self , ("(O)" , args ));
1425
1456
1426
1457
objv = Tkapp_CallArgs (args , objStore , & objc );
1427
1458
if (!objv )
@@ -1464,6 +1495,8 @@ _tkinter_tkapp_eval_impl(TkappObject *self, const char *script)
1464
1495
CHECK_STRING_LENGTH (script );
1465
1496
CHECK_TCL_APPARTMENT ;
1466
1497
1498
+ TRACE (self , ("((ss))" , "eval" , script ));
1499
+
1467
1500
ENTER_TCL
1468
1501
err = Tcl_Eval (Tkapp_Interp (self ), script );
1469
1502
ENTER_OVERLAP
@@ -1493,6 +1526,8 @@ _tkinter_tkapp_evalfile_impl(TkappObject *self, const char *fileName)
1493
1526
CHECK_STRING_LENGTH (fileName );
1494
1527
CHECK_TCL_APPARTMENT ;
1495
1528
1529
+ TRACE (self , ("((ss))" , "source" , fileName ));
1530
+
1496
1531
ENTER_TCL
1497
1532
err = Tcl_EvalFile (Tkapp_Interp (self ), fileName );
1498
1533
ENTER_OVERLAP
@@ -1522,6 +1557,8 @@ _tkinter_tkapp_record_impl(TkappObject *self, const char *script)
1522
1557
CHECK_STRING_LENGTH (script );
1523
1558
CHECK_TCL_APPARTMENT ;
1524
1559
1560
+ TRACE (self , ("((ssss))" , "history" , "add" , script , "exec" ));
1561
+
1525
1562
ENTER_TCL
1526
1563
err = Tcl_RecordAndEval (Tkapp_Interp (self ), script , TCL_NO_EVAL );
1527
1564
ENTER_OVERLAP
@@ -1710,6 +1747,15 @@ SetVar(TkappObject *self, PyObject *args, int flags)
1710
1747
newval = AsObj (newValue );
1711
1748
if (newval == NULL )
1712
1749
return NULL ;
1750
+
1751
+ if (flags & TCL_GLOBAL_ONLY ) {
1752
+ TRACE ((TkappObject * )self , ("((ssssO))" , "uplevel" , "#0" , "set" ,
1753
+ name1 , newValue ));
1754
+ }
1755
+ else {
1756
+ TRACE ((TkappObject * )self , ("((ssO))" , "set" , name1 , newValue ));
1757
+ }
1758
+
1713
1759
ENTER_TCL
1714
1760
ok = Tcl_SetVar2Ex (Tkapp_Interp (self ), name1 , NULL ,
1715
1761
newval , flags );
@@ -1727,8 +1773,22 @@ SetVar(TkappObject *self, PyObject *args, int flags)
1727
1773
return NULL ;
1728
1774
CHECK_STRING_LENGTH (name1 );
1729
1775
CHECK_STRING_LENGTH (name2 );
1776
+
1730
1777
/* XXX must hold tcl lock already??? */
1731
1778
newval = AsObj (newValue );
1779
+ if (((TkappObject * )self )-> trace ) {
1780
+ if (flags & TCL_GLOBAL_ONLY ) {
1781
+ TRACE ((TkappObject * )self , ("((sssNO))" , "uplevel" , "#0" , "set" ,
1782
+ PyUnicode_FromFormat ("%s(%s)" , name1 , name2 ),
1783
+ newValue ));
1784
+ }
1785
+ else {
1786
+ TRACE ((TkappObject * )self , ("((sNO))" , "set" ,
1787
+ PyUnicode_FromFormat ("%s(%s)" , name1 , name2 ),
1788
+ newValue ));
1789
+ }
1790
+ }
1791
+
1732
1792
ENTER_TCL
1733
1793
ok = Tcl_SetVar2Ex (Tkapp_Interp (self ), name1 , name2 , newval , flags );
1734
1794
ENTER_OVERLAP
@@ -1815,6 +1875,28 @@ UnsetVar(TkappObject *self, PyObject *args, int flags)
1815
1875
1816
1876
CHECK_STRING_LENGTH (name1 );
1817
1877
CHECK_STRING_LENGTH (name2 );
1878
+
1879
+ if (((TkappObject * )self )-> trace ) {
1880
+ if (flags & TCL_GLOBAL_ONLY ) {
1881
+ if (name2 ) {
1882
+ TRACE ((TkappObject * )self , ("((sssN))" , "uplevel" , "#0" , "unset" ,
1883
+ PyUnicode_FromFormat ("%s(%s)" , name1 , name2 )));
1884
+ }
1885
+ else {
1886
+ TRACE ((TkappObject * )self , ("((ssss))" , "uplevel" , "#0" , "unset" , name1 ));
1887
+ }
1888
+ }
1889
+ else {
1890
+ if (name2 ) {
1891
+ TRACE ((TkappObject * )self , ("((sN))" , "unset" ,
1892
+ PyUnicode_FromFormat ("%s(%s)" , name1 , name2 )));
1893
+ }
1894
+ else {
1895
+ TRACE ((TkappObject * )self , ("((ss))" , "unset" , name1 ));
1896
+ }
1897
+ }
1898
+ }
1899
+
1818
1900
ENTER_TCL
1819
1901
code = Tcl_UnsetVar2 (Tkapp_Interp (self ), name1 , name2 , flags );
1820
1902
ENTER_OVERLAP
@@ -1981,6 +2063,8 @@ _tkinter_tkapp_exprstring_impl(TkappObject *self, const char *s)
1981
2063
CHECK_STRING_LENGTH (s );
1982
2064
CHECK_TCL_APPARTMENT ;
1983
2065
2066
+ TRACE (self , ("((ss))" , "expr" , s ));
2067
+
1984
2068
ENTER_TCL
1985
2069
retval = Tcl_ExprString (Tkapp_Interp (self ), s );
1986
2070
ENTER_OVERLAP
@@ -2011,6 +2095,8 @@ _tkinter_tkapp_exprlong_impl(TkappObject *self, const char *s)
2011
2095
CHECK_STRING_LENGTH (s );
2012
2096
CHECK_TCL_APPARTMENT ;
2013
2097
2098
+ TRACE (self , ("((ss))" , "expr" , s ));
2099
+
2014
2100
ENTER_TCL
2015
2101
retval = Tcl_ExprLong (Tkapp_Interp (self ), s , & v );
2016
2102
ENTER_OVERLAP
@@ -2040,6 +2126,9 @@ _tkinter_tkapp_exprdouble_impl(TkappObject *self, const char *s)
2040
2126
2041
2127
CHECK_STRING_LENGTH (s );
2042
2128
CHECK_TCL_APPARTMENT ;
2129
+
2130
+ TRACE (self , ("((ss))" , "expr" , s ));
2131
+
2043
2132
ENTER_TCL
2044
2133
retval = Tcl_ExprDouble (Tkapp_Interp (self ), s , & v );
2045
2134
ENTER_OVERLAP
@@ -2069,6 +2158,9 @@ _tkinter_tkapp_exprboolean_impl(TkappObject *self, const char *s)
2069
2158
2070
2159
CHECK_STRING_LENGTH (s );
2071
2160
CHECK_TCL_APPARTMENT ;
2161
+
2162
+ TRACE (self , ("((ss))" , "expr" , s ));
2163
+
2072
2164
ENTER_TCL
2073
2165
retval = Tcl_ExprBoolean (Tkapp_Interp (self ), s , & v );
2074
2166
ENTER_OVERLAP
@@ -2293,6 +2385,8 @@ _tkinter_tkapp_createcommand_impl(TkappObject *self, const char *name,
2293
2385
!WaitForMainloop (self ))
2294
2386
return NULL ;
2295
2387
2388
+ TRACE (self , ("((ss()O))" , "proc" , name , func ));
2389
+
2296
2390
data = PyMem_NEW (PythonCmd_ClientData , 1 );
2297
2391
if (!data )
2298
2392
return PyErr_NoMemory ();
@@ -2351,6 +2445,8 @@ _tkinter_tkapp_deletecommand_impl(TkappObject *self, const char *name)
2351
2445
2352
2446
CHECK_STRING_LENGTH (name );
2353
2447
2448
+ TRACE (self , ("((sss))" , "rename" , name , "" ));
2449
+
2354
2450
if (self -> threaded && self -> thread_id != Tcl_GetCurrentThread ()) {
2355
2451
Tcl_Condition cond = NULL ;
2356
2452
CommandEvent * ev ;
@@ -2476,6 +2572,8 @@ _tkinter_tkapp_createfilehandler_impl(TkappObject *self, PyObject *file,
2476
2572
return NULL ;
2477
2573
}
2478
2574
2575
+ TRACE (self , ("((ssiiO))" , "#" , "createfilehandler" , tfile , mask , func ));
2576
+
2479
2577
data = NewFHCD (func , file , tfile );
2480
2578
if (data == NULL )
2481
2579
return NULL ;
@@ -2507,6 +2605,8 @@ _tkinter_tkapp_deletefilehandler(TkappObject *self, PyObject *file)
2507
2605
if (tfile < 0 )
2508
2606
return NULL ;
2509
2607
2608
+ TRACE (self , ("((ssi))" , "#" , "deletefilehandler" , tfile ));
2609
+
2510
2610
DeleteFHCD (tfile );
2511
2611
2512
2612
/* Ought to check for null Tcl_File object... */
@@ -2541,6 +2641,7 @@ _tkinter_tktimertoken_deletetimerhandler_impl(TkttObject *self)
2541
2641
PyObject * func = v -> func ;
2542
2642
2543
2643
if (v -> token != NULL ) {
2644
+ /* TRACE(...) */
2544
2645
Tcl_DeleteTimerHandler (v -> token );
2545
2646
v -> token = NULL ;
2546
2647
}
@@ -2643,6 +2744,8 @@ _tkinter_tkapp_createtimerhandler_impl(TkappObject *self, int milliseconds,
2643
2744
2644
2745
CHECK_TCL_APPARTMENT ;
2645
2746
2747
+ TRACE (self , ("((siO))" , "after" , milliseconds , func ));
2748
+
2646
2749
v = Tktt_New (func );
2647
2750
if (v ) {
2648
2751
v -> token = Tcl_CreateTimerHandler (milliseconds , TimerHandler ,
@@ -2810,6 +2913,47 @@ Tkapp_WantObjects(PyObject *self, PyObject *args)
2810
2913
Py_RETURN_NONE ;
2811
2914
}
2812
2915
2916
+ /*[clinic input]
2917
+ _tkinter.tkapp.settrace
2918
+
2919
+ func: object
2920
+ /
2921
+
2922
+ Set the tracing function.
2923
+ [clinic start generated code]*/
2924
+
2925
+ static PyObject *
2926
+ _tkinter_tkapp_settrace (TkappObject * self , PyObject * func )
2927
+ /*[clinic end generated code: output=847f6ebdf46e84fa input=31b260d46d3d018a]*/
2928
+ {
2929
+ if (func == Py_None ) {
2930
+ func = NULL ;
2931
+ }
2932
+ else {
2933
+ Py_INCREF (func );
2934
+ }
2935
+ Py_XSETREF (self -> trace , func );
2936
+ Py_RETURN_NONE ;
2937
+ }
2938
+
2939
+ /*[clinic input]
2940
+ _tkinter.tkapp.gettrace
2941
+
2942
+ Get the tracing function.
2943
+ [clinic start generated code]*/
2944
+
2945
+ static PyObject *
2946
+ _tkinter_tkapp_gettrace_impl (TkappObject * self )
2947
+ /*[clinic end generated code: output=d4e2ba7d63e77bb5 input=ac2aea5be74e8c4c]*/
2948
+ {
2949
+ PyObject * func = self -> trace ;
2950
+ if (!func ) {
2951
+ func = Py_None ;
2952
+ }
2953
+ Py_INCREF (func );
2954
+ return func ;
2955
+ }
2956
+
2813
2957
/*[clinic input]
2814
2958
_tkinter.tkapp.willdispatch
2815
2959
@@ -2835,6 +2979,7 @@ Tkapp_Dealloc(PyObject *self)
2835
2979
ENTER_TCL
2836
2980
Tcl_DeleteInterp (Tkapp_Interp (self ));
2837
2981
LEAVE_TCL
2982
+ Py_XDECREF ( ((TkappObject * )self )-> trace );
2838
2983
PyObject_Free (self );
2839
2984
Py_DECREF (tp );
2840
2985
DisableEventHook ();
@@ -3045,6 +3190,8 @@ static PyMethodDef Tkapp_methods[] =
3045
3190
{
3046
3191
_TKINTER_TKAPP_WILLDISPATCH_METHODDEF
3047
3192
{"wantobjects" , Tkapp_WantObjects , METH_VARARGS },
3193
+ _TKINTER_TKAPP_SETTRACE_METHODDEF
3194
+ _TKINTER_TKAPP_GETTRACE_METHODDEF
3048
3195
{"call ", Tkapp_Call , METH_VARARGS },
3049
3196
_TKINTER_TKAPP_EVAL_METHODDEF
3050
3197
_TKINTER_TKAPP_EVALFILE_METHODDEF
0 commit comments