[comp.windows.x] X11R3 Xt Callbacks question & bug report

csvsj@garnet.berkeley.edu (Steve Jacobson) (03/11/89)

We have just started trying to move our complex X application from R2 to
R3. (We've waited till now because we used HP widgets).

We use the closure member of the CallbackList structure to store client
data associated with the widget instance. Our application originally was
a SunView program, and SunView "objects" all have client data resources.
For the X version, we used the CallbackList structure for this purpose.
In many instances, we set a dummy destroy callback just so we could use the
closure structure member.

Question: Is there a more direct way to do this? Why isn't there a client
	  data resource in the core widget structure?

We were able to make this work in X11R2, though there were some things we
did because they worked without understanding why.

Here's an example:

static void
clear_values()
{
    int             i;
    Arg             args[10];
    XtCallbackRec   *callback;

    XtSetArg(args[0], XtNstring, "");
    XtSetArg(args[1], XtNinsertPosition, 0);
    XtSetArg(args[2], XtNvisibleInsert, TRUE);
    XtSetArg(args[3], XtNdestroyCallback, &callback);
    for (i = 0; i < text_count; i++)
    {
        XtSetValues(query_text_item[i], args, THREE);
        XtGetValues(query_text_item[i], &args[3], ONE);
        (callback+1)->closure = (caddr_t) 0;
    }
}

We didn't understand why we had to go to the 2nd callback list member when
we had only set one destroycallback. However, it worked. Subsequently,
we could use the same method to find out what the closure value was.

It's clear from the R3 changes memo and by looking at the code, that this
will no longer work. We haven't figured out how to make it work. Along the
way, we found a bug in the Xt Callback.c file.

The bug:

In the _XtGetCallbackList routine, the automatic variable callback_count
is not initialized to 0. In the code, it is incremented, then used in a
XtMalloc call. When we ran our application on our DEC GPX, the automatic
variable had a very large number in it, so the XtMalloc failed.
Linting the file points the problem out.

What we tried:

First, it looked like we no longer needed to look at the 2nd callback list
member if we had only set one. Second, it looked like we get a copy of
the list, so changing a closure value wouldn't change it where it counted.
I should state that these were guesses - in practice we have little idea
just what is going on here.

Here is our last attempt:

static void
clear_values()
{
    int             i;
    Arg             args[10];
    XtCallbackRec   *callback;

    XtSetArg(args[0], XtNstring, "");
    XtSetArg(args[1], XtNinsertPosition, 0);
    XtSetArg(args[2], XtNvisibleInsert, TRUE);
    XtSetArg(args[3], XtNdestroyCallback, &callback);
    for (i = 0; i < text_count; i++)
    {
        XtSetValues(query_text_item[i], args, THREE);
        XtGetValues(query_text_item[i], &args[3], ONE);
        callback->closure = (caddr_t) 0;
        XtSetValues(query_text_item[i], &args[3], ONE);
    }
}

This didn't work. First, it looked like this just added a destroy callback,
rather than replacing the original list. Second, the closure value in
both copies of the callback record were the same, and not the value we
expected. (The fact that both list members looked the same makes me doubt
the copy guess above.)

Obviously, I've not presented enough code here to replicate the problem,
but I hope I have made it clear what we are trying to do.

We would appreciate responses that either suggest a more direct way of
associating modifyable client data with widget instances or give us hints
about what we're supposed to do to change the code the worked with R2 to code
that works in R3.


Thanks.