1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
/* trace.c,v 1.4 2005/09/12 03:11:01 jenglish Exp
*
* Copyright 2003, Joe English
*
* Simplified interface to Tcl_TraceVariable.
*
* PROBLEM: Can't distinguish "variable does not exist" (which is OK)
* from other errors (which are not).
*/
#include <tk.h>
#include "tkTheme.h"
#include "widget.h"
struct TtkTraceHandle_
{
Tcl_Interp *interp; /* Containing interpreter */
Tcl_Obj *varnameObj; /* Name of variable being traced */
Ttk_TraceProc callback; /* Callback procedure */
void *clientData; /* Data to pass to callback */
};
/*
* Tcl_VarTraceProc for trace handles.
*/
static char *
VarTraceProc(
ClientData clientData, /* Widget record pointer */
Tcl_Interp *interp, /* Interpreter containing variable. */
CONST char *name1, /* (unused) */
CONST char *name2, /* (unused) */
int flags) /* Information about what happened. */
{
Ttk_TraceHandle *tracePtr = clientData;
const char *name, *value;
Tcl_Obj *valuePtr;
if (flags & TCL_INTERP_DESTROYED) {
return NULL;
}
name = Tcl_GetString(tracePtr->varnameObj);
/*
* If the variable is being unset, then re-establish the trace:
*/
if (flags & TCL_TRACE_DESTROYED) {
Tcl_TraceVar(interp, name,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VarTraceProc, clientData);
tracePtr->callback(tracePtr->clientData, NULL);
return NULL;
}
/*
* Call the callback:
*/
valuePtr = Tcl_GetVar2Ex(interp, name, NULL, TCL_GLOBAL_ONLY);
value = valuePtr ? Tcl_GetString(valuePtr) : NULL;
tracePtr->callback(tracePtr->clientData, value);
return NULL;
}
/* Ttk_TraceVariable(interp, varNameObj, callback, clientdata) --
* Attach a write trace to the specified variable,
* which will pass the variable's value to 'callback'
* whenever the variable is set.
*
* When the variable is unset, passes NULL to the callback
* and reattaches the trace.
*/
Ttk_TraceHandle *Ttk_TraceVariable(
Tcl_Interp *interp,
Tcl_Obj *varnameObj,
Ttk_TraceProc callback,
void *clientData)
{
Ttk_TraceHandle *h = (Ttk_TraceHandle*)ckalloc(sizeof(*h));
int status;
h->interp = interp;
h->varnameObj = Tcl_DuplicateObj(varnameObj);
Tcl_IncrRefCount(h->varnameObj);
h->clientData = clientData;
h->callback = callback;
status = Tcl_TraceVar(interp, Tcl_GetString(varnameObj),
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VarTraceProc, (ClientData)h);
if (status != TCL_OK) {
Tcl_DecrRefCount(h->varnameObj);
ckfree((ClientData)h);
return NULL;
}
return h;
}
/*
* Ttk_UntraceVariable --
* Remove previously-registered trace and free the handle.
*/
void Ttk_UntraceVariable(Ttk_TraceHandle *h)
{
if (h) {
Tcl_UntraceVar(h->interp, Tcl_GetString(h->varnameObj),
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VarTraceProc, (ClientData)h);
Tcl_DecrRefCount(h->varnameObj);
ckfree((ClientData)h);
}
}
/*
* Ttk_FireTrace --
* Executes a trace handle as if the variable has been written.
*
* Note: may reenter the interpreter.
*/
int Ttk_FireTrace(Ttk_TraceHandle *tracePtr)
{
Tcl_Interp *interp = tracePtr->interp;
void *clientData = tracePtr->clientData;
const char *name = Tcl_GetString(tracePtr->varnameObj);
Ttk_TraceProc callback = tracePtr->callback;
Tcl_Obj *valuePtr;
const char *value;
/* Read the variable.
* Note that this can reenter the interpreter, and anything can happen --
* including the current trace handle being freed!
*/
valuePtr = Tcl_GetVar2Ex(interp, name, NULL, TCL_GLOBAL_ONLY);
value = valuePtr ? Tcl_GetString(valuePtr) : NULL;
/* Call callback.
*/
callback(clientData, value);
return TCL_OK;
}
/*EOF*/
|