Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tcl extension: Understanding and using ClientData

Tags:

c

tcl

I am working to update old software (written to build against Tcl/Tk 8.3) so that it builds against more modern distributions. I am taking this as an opportunity to learn about C and Tcl, both of which I had never programmed in when this project began. So, I'm very novice.

One of the most confusing things for me in learning about the Tcl API is ClientData. Many functions in the API take it as an argument, but the C extension almost never uses it. I got the impression from this answer that the global definition is rarely used:

The whole-extension ClientData is intended for extensions that want to publish their own stub table ... that other extensions can build against. This is a very rare thing to want to do; leave at NULL if you don't want it.

So it seems that it is basically a void parameter that you then need to type cast or handle internally. But there are some places in the code where I need to interact with ClientData (e.g. for Idle Processes, as in the following):

typedef struct graph *Graph;

struct graph {
  int       num;
  int       hidden;
  int       needsRedraw;
...
};

flag drawNow(ClientData data) {
  Graph G;
  int g = (int) data;
  if (!(G = lookupGraph(g))) return TCL_OK;
  return drawGraph(G);
}

flag drawLater(Graph G) {
  if (!G->needsRedraw && !G->hidden) {
    G->needsRedraw = TRUE;
    Tcl_DoWhenIdle((Tcl_IdleProc *) drawNow, (ClientData) G->num);
  }
  return TCL_OK;
}

The cast to integer results in the following warning when I compile:

warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]

My main confusion is (ClientData) G->num---I don't understand what I am casting to, because I don't know what kind of a thing ClientData is. If I look in the Tcl sources, I do not find clarity:

tclCompile.h:220:typedef ClientData (AuxDataDupProc)  (ClientData clientData);
tclInt.h:2520:typedef ClientData (TclFSGetCwdProc2)(ClientData clientData);
tclOOInt.h:73:typedef ClientData (TclOO_PmCDCloneProc)(ClientData clientData);

A couple of final points: These compiler warnings existed before I started doing any updates to the code. The program appears to work on the old systems where the original code does compile and run. So, I am not sure if this warning amounts to anything... but it spooks me, and as long as I am spending time with the code and learning about C and Tcl, I was hoping to get to the bottom of it.

Apologies in advance if I did not provide enough relevant information. I'm happy to provide more, but this my current best effort at a good question.

like image 739
Chris Cox Avatar asked Mar 15 '23 21:03

Chris Cox


1 Answers

In general, ClientData means “pointer that Tcl promises it won't interpret for you”, and is virtually always something that will get handed back to you in a callback. Treat it like void * (which is what it is a typedef for).

The answer you refer to is talking specifically about the Tcl_PkgRequireEx function, where the ClientData stuff is used for passing around references to stub tables. You can use this to pass your own, but it's quite involved. It's a pretty rare thing though; most people never touch on those mysteries.

In general, it's more common to see it used in relation to Tcl_CreateCommand or Tcl_CreateObjCommand. There, the clientData parameter is a pointer that will get passed back to the implementation callback when the created command is called; this is great for commands that represent instances of classes and things like that. Tcl uses this for things like procedures; the proc command uses the clientData to pass a pointer to a structure describing the body script (and other stuff) to the C function that implements procedures. If you know a little bit about Tk, clientData is used extensively there to pass the low-level handle to the window structure.

With Tcl_DoWhenIdle, it's again a pointer being handed over to the callback. Different signature of callback function, of course, but same basic underlying idea.

If Tcl provided C++ APIs, it would probably do things a bit differently since it's possible to talk about pointers to an instance method in that language. But Tcl's API is a C API, so everything has to work like this.

like image 182
Donal Fellows Avatar answered Mar 21 '23 04:03

Donal Fellows