Design Notes for the new Tkinter C Interface

This note currently contains original design notes (scribbled on a palm pilot one warm day in San Jose), and has not been checked against the actual implementation.

March 2000 | Fredrik Lundh

Types

The new C interface defines a number of object types:

Interpreter

This type holds a pointer to a Tcl interpreter instance. It should have the same layout as the corresponding object in the current version of Tkinter.

PyTclObject

This is a Python type implementation that wraps a Tcl object.

 struct {
     TclObj* object;
 } PyTclObject;

To create new PyTclObject instances, call the factory function with an ordinary Python object:

 PyString -> TclStringObj
 PyInt -> TclIntegerObj or TclStringObj (if too large)
 PyFloat -> TclFloatObj
 PyTuple -> TclArrayObj (?)

All other objects are converted to string objects (using PyObject_Str).

PyTclCommand

This type wraps a pointer to a Tcl command, and the associated client data.

 struct {
     /* true if command uses object interface */
     int use_obj_interface;
     /* command/client pointer */
     TclCmd* command;
     void* client_data;
 } PyTclCommandObject;

The factory function takes a command name, and looks it up using Tcl’s CommandInfo function. Note that this type doesn’t provide any additional methods; at this time, it’s main purpose is to provide information for the bound method type.

PyTclBoundMethodObject

This is a callable type which combines a PyTclCommandObject with a method name (as a PyTclObject string) and information on how to convert arguments and results.

 struct {
     PyTclCommandObject* command;
     PyTclObject* method;
     void* convert; /* to be defined */
 } PyTclBoundMethodObject;

The call hook accepts an argument tuple and a keyword dictionary. The values in the tuple are converted to PyTclObject’s. Simplified:

def makeargs(av, kw):
    size = 1 + len(av) + 2*len(kw)
    argv = tuple(size)
    argv[0] = method
    i = 1
    for v in av:
        if v is PyTclObject:
            argv[i] = v
        else:
            argv[i] = pytclobject(v)
        i = i + 1
    for k, v in kw:
        argv[i] = "-" + k
        if item is PyTclObject:
            argv[i+1] = v
        else:
            argv[i+1] = pytclobject(v)
        i = i + 2
     result = command->command(command->client_data, argv)
     return pytclobject(result)

To speed things up even further, we could use a dictionary mapping well-known option names to PyTclObject strings which *include* the leading hyphen.

New Tkinter Interface

The new Tkinter interface is data driven.

For each widget class, the interface uses a method table which is used by the getattr hook to create PyTclBoundMethod objects on the fly.

 class Scale(Widget):
     _tk_map = {
         "get": (PyTclObject("get"), None),
         "set": (PyTclObject("set"), None),
     }
     __getattr__ = Widget._tk_getattr

Global String Cache

The global string cache maps known Tkinter names (method names, and common option values as defined in the Tkconstants module) to Tcl string objects (PyTclObject).

 

A Django site. rendered by a django application. hosted by webfaction.