Phil Ringsmuth
Phil Ringsmuth

Reputation: 2037

How can I find out if a Tcl_Obj is a certain kind of ttk:: entity, such as ttk:entry?

I am working with a legacy (Desktop-style, as they're now known) Windows application built mostly in C and C++. When this application is running on a touchscreen Windows laptop, I need to automatically show the touch keyboard when the user taps inside an entry box on a dialog screen. This behavior is very common, and as far as I can tell, Microsoft disabled this formerly automatic behavior in Windows 8/8.1, and will be re-enabling it in Windows 10.

So... I can programmatically show the touch keyboard, that part is solved. What I'm trying to do now is catch when a ttk::entry widget receives focus and then activate the keyboard. The closest I've come is inside tk8.5.9/generic/tkFocus.c. There is a method called Tk_FocusObjCmd:

 /*
 *--------------------------------------------------------------
 *
 * Tk_FocusObjCmd --
 *
 *  This function is invoked to process the "focus" Tcl command. See the
 *  user documentation for details on what it does.
 *
 * Results:
 *  A standard Tcl result.
 *
 * Side effects:
 *  See the user documentation.
 *
 *--------------------------------------------------------------
 */

int
Tk_FocusObjCmd(
    ClientData clientData,  /* Main window associated with interpreter. */
    Tcl_Interp *interp,     /* Current interpreter. */
    int objc,           /* Number of arguments. */
    Tcl_Obj *CONST objv[])  /* Argument objects. */
{

This method is given, among other things, an array of Tcl_Obj objects. What I'm trying to do is find out if the one being acted on is of a certain type, such as ttk::entry. If it is, I will launch the touch keyboard. I've tried using object->typePtr->name, but that doesn't give me what I'd expected, and sometimes it crashes (haven't figured out why yet):

char *objectType = objv[1]->typePtr->name;

if (objectType)
{
    printf("Object Type: %s\n", objectType); // don't do this, it breaks sometimes.
}

This is where I'm stuck. I would greatly appreciate any insight to get me in the right direction.

Upvotes: 1

Views: 76

Answers (1)

Donal Fellows
Donal Fellows

Reputation: 137567

You're doing this very thoroughly wrong. What you should do is instead assume that you're passed a widget name (something like .a2.b5.c9) and then ask Tk to tell you what the class of the widget with that name is.

winfo class .a2.b5.c9

For an instance of a ttk::entry, this will return TEntry (unless you changed it by passing in the -class option on widget creation).

From the C level, you'd query the class by using Tk_Class(), which takes a single Tk_Window argument (which you can obtain via Tk_NameToWindow, passing in the string form of the argument value, which in turn you can obtain from Tcl_GetString). But it might be simpler to just use Tcl_VarEval, assuming non-evil window names…

if (Tcl_VarEval(interp, "winfo class ", Tcl_GetString(objPtr), NULL) == TCL_OK) {
    const char *className = Tcl_GetString(Tcl_GetObjResult(interp));
    // ...
}

(The truly cautious or those really keen on speed will use Tcl_EvalObjv, but that's a bit more complex.)

Upvotes: 1

Related Questions