To ensure device-independence, TkGS defines a modular, extensible device driver architecture. That way, drawing operations can be performed on any kind of device: windows, full screen, printers, plotters, metafiles... For each type of device, one needs to write a device driver that acts as a translator between device-independent TkGS structures and calls and the underlying device-specific structures and calls (Win32, MacOS Toolbox, Xlib, DirectX, OpenGL, PostScript...).
Under TkGS, drawing operations are performed on drawables. Each drawable belongs to a specific device, and device-independent TkGS calls are rerouted to device-specific calls defined by a device driver. More specifically, each TkGS_Drawable belongs to a TkGS_Device, which is in fact an opaque token hiding a TkGS_DeviceDriver structure. Standard calls like TkGS_DrawRectangle are then rerouted to the corresponding device-driver-defined procedure (ie drawRectangle). The TkGS_DeviceDriver is actually quite close to a stubs table.
typedef TkGS_Drawable (TkGS_GetDrawableProc)
_ANSI_ARGS_((ClientData clientData));
typedef int (TkGS_UpdateDrawableStateProc)
_ANSI_ARGS_((TkGS_Drawable d, unsigned long valueMask));
typedef void (TkGS_DrawRectangleProc)
_ANSI_ARGS_((TkGS_Drawable d, int filled, int x,
int y, unsigned int width,
unsigned int height));
typedef void (TkGS_DrawEllipseProc)
_ANSI_ARGS_((TkGS_Drawable d, int filled, int x,
int y, unsigned int width,
unsigned int height));
typedef struct TkGS_DeviceDriver {
char *name; /* Name of device driver */
TkGS_GetDrawableProc *getDrawable;
TkGS_UpdateDrawableStateProc *updateDrawableState;
/* Drawing primitives */
TkGS_DrawRectangleProc *drawRectangle;
TkGS_DrawEllipseProc *drawEllipse;
} TkGS_DeviceDriver;