TkGS Specification - Internals: TkGS_Objs
TkGS Specification - Internals: TkGS_Objs
Most public structures defined by TkGS, such as
TkGS_Color,
are in the same time device-independent from a user's point of view, and very
platform- and device-dependent from the implementor's point of view. For example,
a TkGS_Color specified by its RGB values could
hold any device-independent value internally, be it an XColor or a Windows
COLORREF or Pen Object. As the same color may be used on distinct devices, its
internal representation may change as well, however its external representation
remains the same, thus guaranteeing device-independence.
TkGS must then provide a structure that guarantees device-independence while
providing the best overall performance. To do so, it introduces the
TkGS_Obj structure. This structure is
very much inspired from Tcl's Tcl_Obj, in the sense that it
holds a device-independent visible part, and a device-dependent internal part
that is subject to change during the object's lifetime. Both share many
features, such as:
- Reference counting, allowing efficient memory management with
copy-on-write semantics;
- Internal representation shimmering without altering the external part.
- A unified way of defining new object types.
The main differences are:
- Tcl_Objs' external representations are strings.
TkGS_Objs' external representations can be anything such
as colors or drawing attributes;
- Both Tcl_Objs' external and internal representations may
change: an object can be turned into a list from its string representation, and
the internal list structure can be modified later on, thus invalidating the
old string representation. Only TkGS_Objs' external part may
change. For example, a color can be defined in a device-independent manner by
its RGB values. Its internal part may shimmer between many device-dependent
structures, but the RGB values will never be recomputed from its internal part.
The latter can be seen as a limitation, but in practice generating an object's
external representation from its internals may give unexpected results: a color's
internal values may have been dithered to match the display's color model. The only
possible interaction with objects is through device-independent calls, changing
a color's RGB values for example.
Like with Tcl_Objs, the internal representation of
TkGS_Objs may "shimmer" if subsequently used on different
devices. However such shimmering should seldom occur given the way objects are
used. An example is canvas printing: canvas items are most of the time drawn on
a window, and once in a while output to a PostScript file. The colors' internal
values may then change from screen device representation (eg. XColor) to
PostScript color, and back to screen once printing is complete.
This model provides the best compromise between performance and memory
footprint, and device drivers can fine-tune their implementation depending on
system specificities. For example, Object allocation on Windows are notably
slow, but such objects can be used on any device, so caching them provides
increased performances.
- TkGS_Obj
- Description
- This structure is very similar to Tcl_Obj.
It is not supposed to be used as is but rather as a base class for
more specific objects (colors, drawables...). Thus it only defines
room for type and internal representation, and no external
representation.
- Status
- Complete.
- Structure
-
typedef struct TkGS_Obj {
int refCount; /* When 0 the object will be freed. */
TkGS_ObjType *typePtr; /* Denotes the object's type. Always
* corresponds to the type of the object's
* internal rep. NULL indicates the object
* has no internal rep (has no type). */
union { /* The internal representation: */
long longValue; /* - a long integer value */
unsigned long ulongValue; /* - an unsigned long integer value */
double doubleValue; /* - a double-precision floating value */
VOID *otherValuePtr; /* - another, type-specific value */
struct { /* - internal rep as two values */
union {
long longValue;
unsigned long ulongValue;
VOID* otherValuePtr;
} value1, value2;
} twoValue;
} internalRep;
} TkGS_Obj;
- TkGS_ObjType
- Description
- This structure is very similar to Tcl_ObjType.
The main differences are the lack of a duplication procedure and the
baseTypePtr field.
- The latter actually describe the
real device-independent type of objects, since TkGS_Obj
is only a "virtual class" (using OOP terminology). For example, an
object can be a color, and its internal representation can be a
device-specific color structure. The object's base type won't change,
but the internal type may.
- The lack of duplication procedure is due to the fact that only the
public part can be safely duplicated.
- Status
- Nearly complete. The procedure prototypes may change (for example,
we may add more explicit error reporting to TkGS_SetFromAnyProc).
- Structure
-
typedef void (TkGS_FreeInternalRepProc) _ANSI_ARGS_((struct TkGS_Obj *objPtr));
typedef int (TkGS_SetFromAnyProc) _ANSI_ARGS_((struct TkGS_Obj *objPtr));
typedef struct TkGS_ObjType {
char *name; /* Name of the type, e.g. "XlibGC". */
TkGS_BaseType *baseTypePtr; /* Base type, eg. GC, Drawable... */
TkGS_FreeInternalRepProc *freeIntRepProc;
/* Called to free any storage for the type's
* internal rep. NULL if the internal rep
* does not need freeing. */
TkGS_SetFromAnyProc *setFromAnyProc;
/* Called to convert the object's internal
* rep to this type. Frees the internal rep
* of the old type. Returns TKGS_ERROR on
* failure, and TKGS_OK on success. NULL if
* the object is immutable */
} TkGS_ObjType;
- TkGS_BaseType
- Description
- This structure has no Tcl equivalent. This is due to the fact that all
Tcl objects have string representations (the "everything is a string" paradigm).
Thus this structure is used to describe the objects' public representation.
- The size field is used to specify the byte size of the object
of this type. Since TkGS_Obj is only a "virtual class", the
real size of objects depends on their external representation.
- Status
- Complete.
- Structure
-
typedef void (TkGS_FreeBaseProc) _ANSI_ARGS_((struct TkGS_Obj *objPtr));
typedef void (TkGS_DupBaseProc) _ANSI_ARGS_((struct TkGS_Obj *srcPtr,
struct TkGS_Obj *dupPtr));
typedef struct TkGS_BaseType {
char *name; /* Name of the base type, eg. "GC" */
int size; /* Byte size of TkGS_Objs of this type */
struct TkGS_ObjType *emptyTypePtr;
/* Used to initialize objects with no internal
* representation */
TkGS_FreeBaseProc *freeBaseProc;
/* Called to free any storage for the type's
* base rep. NULL if the base rep does not
* need freeing. */
TkGS_DupBaseProc *dupBaseProc;
/* Called to create a new object as a copy
* of an existing object. It only copies the
* public part of the object, not the
* internal part */
} TkGS_BaseType;
- TkGS_IncrRefCount
- TkGS_DecrRefCount
- Description
- This procedures are the exact counterparts of the corresponding
Tcl_Obj related procedures.
- TkGS_IncrRefCount increments an object's reference
count.
- TkGS_DecrRefCount decrements an object's reference
count, and if it reaches zero, frees the object.
- Status
- Specification complete. They are currently implemented as macros.
Like in Tcl, we may add debugging-specific implementations.
- Declaration
-
void TkGS_IncrRefCount(
TkGS_Obj *objPtr
);
void TkGS_DecrRefCount(
TkGS_Obj *objPtr
);
- Arguments
objPtr: a pointer to the object.
- Returned value
- None.
- Side effects
- The object's reference count is incremented or decremented. If it falls below 1,
the object is freed.
- TkGS_IsShared
- Description
- This procedure is the exact counterpart of the corresponding
Tcl_Obj related procedure. It checks whether the
object is shared, ie if its refcount is at least 2.
- Status
- Complete.
- Declaration
-
int TkGS_IsShared(
TkGS_Obj *objPtr
);
- Arguments
objPtr: a pointer to the object.
- Returned value
- 1 (true) if the object's reference count is at least 2,
else 0 (false).
- Side effects
- Memory is allocated.
- TkGS_ConvertToType
- Description
- This procedure is the exact counterpart of the corresponding
Tcl_Obj related procedure. It tries to convert
an object's internal part to a specific type. The new type must
have the same base type as the object (one can't convert a color
to a drawable for example).
- Status
- Nearly complete. The procedure prototypes may change (for example,
we may add more explicit error reporting).
- Declaration
-
int TkGS_ConvertToType(
TkGS_Obj *objPtr,
TkGS_ObjType *typePtr
);
- Arguments
objPtr: a pointer to the object.
typePtr: the new object type.
- Returned value
- TKGS_OK if the conversion succeeds.
- TKGS_ERROR if the conversion fails: if typePtr's and
objPtr's base types differ, or if typePtr's
conversion procedure fails.
- Side effects
- The object's internal representation may change.
- TkGS_DuplicateObj
- Description
- This procedure is the exact counterpart of the corresponding
Tcl_Obj related procedure. It creates a new object
that has the exact type and external representation as the given
object. It doesn't copy the internal part.
- Status
- Complete.
- Declaration
-
int TkGS_DuplicateObj(
TkGS_Obj *objPtr
);
- Arguments
objPtr: a pointer to the object to duplicate.
- Returned value
- A newly allocated object that is the duplicate of objPtr.
- Side effects
- Memory is allocated.
- TkGSNewObj
- Description
- This procedure is used to allocate a new object of a given base
type. It is not supposed to be called from outside TkGS.
- Newly allocated objects' type is the default type defined by the
base type's emptyTypePtr field. Thus all objects
are guaranteed to have a proper type field set. This differs from
Tcl_Objs which have their internal type set to NULL
by default.
- Status
- Internal use only. Unlikely to change.
- Declaration
-
TkGS_Obj *TkGSNewObj(
TkGS_BaseType *baseTypePtr
);
- Arguments
baseTypePtr: the object's base type descriptor.
- Returned value
- A pointer to the newly allocated object, or NULL in case of failure.
- Side effects
- Memory is allocated.
- TkGSFreeObj
- Description
- This procedure is used to free an existing object. It is not
supposed to be called from outside TkGS. Users should only call
the public TkGS_IncrRefCount and
TkGS_DecrRefCount for memory managemenet.
- Status
- Internal use only. Unlikely to change.
- Declaration
-
void TkGSFreeObj(
TkGS_Obj *objPtr
);
- Arguments
objPtr: a pointer to the object.
- Returned value
- None.
- Side effects
- Memory is freed (internal and external representations).
- Add better error reporting to some procedures. Should we use Tcl facilities (eg. interp)
or use more generic methods? The latter to ensure total independence from Tcl, for easier porting
to other languages such as Perl or Python. We may also use Tcl interps and let porters use
language-specific constructs.