TkGS Specification - Porting Tk code to TkGS

Introduction

Drawing operations are currently performed through the Xlib Emulation Layer. Drawing code usually passes the display and window identifier to Xlib drawing primitives, along with GC structures. In this case, the drawable is the window. In other cases, an off-screen pixmap is first build then copied on the window, the drawable is then the pixmap. Displays and windows are immediately available, GCs are build using XCreateGC, modified using XChangeGC and freed using XFreeGC. They can also be created via TkGS_CreateGC and freed with TkGS_FreeGC at the cost of being unmodifiable.

With TkGS, drawing code will first need to call a function like TkGS_GetWindowDrawable to get a drawable from a window, or TkGS_CreatePixmap to build a pixmap. Drawing parameters will then be set on the drawable and not on the GC. Code will be able to set or query the drawable's state using the above specified functions. Then each drawing primitive will be called, using the current parameters. Once the drawing is complete, the drawable will have to be released using TkGS_ReleaseDrawable, which will free all the associated graphics structures.

The following example shows the difference between two typical widget drawing procedures, the first using Xlib and the second using TkGS:

Xlib example:

void DisplayWidget(clientData)
    ClientData clientData; /* Information about widget. */
{
    Widget *widgetPtr = (Widget*) clientData;
    Tk_Window tkwin = widgetPtr->tkwin;
    Display display = TkGS_Display(tkwin);
    Drawable drawable = Tk_WindowId(tkwin);
    GC gc;
    XGCValues gcValues;
    unsigned long mask;

    /* Create GC */
    gcValues.foreground = widgetPtr->bgColorPtr->pixel;
    mask = GCForeground;
    gc = XCreateGC(widget->display, drawable, mask, &gcValues);

    /* Fill the widget's background */
    XFillRectangle(display, drawable, gc, x, y, width, height);

    /* Free GC */
    XFreeGC(display, gc);
}

TkGS example:

void DisplayWidget(clientData)
    ClientData clientData; /* Information about widget. */
{
    Widget *widgetPtr = (Widget*) clientData;
    Tk_Window tkwin = widgetPtr->tkwin;
    TkGS_Drawable drawable;
    TkGS_GCValues gcValues;
    unsigned long mask;

    /* Get drawable */
    drawable = TkGS_GetWindowDrawable(tkwin);

    /* Set GC values */
    gcValues.foreground = widgetPtr->bgColor;
    mask = TkGS_GCForeground;
    TkGS_SetGCValues(drawable, mask, &gcValues);

    /* Fill the widget's background */
    TkGS_DrawRectangle(drawable, 1, x, y, width, height);

    /* Release drawable */
    TkGS_ReleaseDrawable(drawable);
}

You can see that both procedures are quite similar. The only notable difference, apart from the names, is the call to TkGS_GetWindowDrawable in the TkGS version, and the call to Xlib's XFreeGC being replaced by TkGS_ReleaseDrawable. In practice, converting code from Xlib to TkGS should be a matter of renaming structures, adding drawable initialization and release code, and reorganizing GC access. This should bring better encapsulation and more suited resource management across platforms.

TODO