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;