|
Note: The Agar manual pages follow certain conventions, notably
concerning function return values. Please read
AG_Intro(3)
first.
SYNOPSIS
DESCRIPTION
|
The Agar object system provides object-oriented programming functionality
(e.g., inheritance, virtual functions) to applications written in
different languages (currently C, C++, Objective C, Perl and Ada).
|
INITIALIZATION AND VFS FUNCTIONS
AG_Object * AG_ObjectNew (AG_Object *parent, const char *name, AG_ObjectClass *classInfo)
void AG_ObjectInit (AG_Object *obj, AG_ObjectClass *classInfo)
void AG_ObjectInitStatic (AG_Object *obj, AG_ObjectClass *classInfo)
void AG_ObjectAttach (AG_Object *new_parent, AG_Object *obj)
void AG_ObjectAttachToNamed (AG_Object *vfsRoot, const char *path, AG_Object *child)
void AG_ObjectDetach (AG_Object *obj)
void AG_ObjectMoveToHead (AG_Object *obj)
void AG_ObjectMoveToTail (AG_Object *obj)
void AG_ObjectMoveUp (AG_Object *obj)
void AG_ObjectMoveDown (AG_Object *obj)
void AG_ObjectDelete (AG_Object *obj)
AG_Object * AG_ObjectRoot (AG_Object *obj)
AG_Object * AG_ObjectParent (AG_Object *obj)
AG_Object * AG_ObjectFind (AG_Object *vfsRoot, const char *format, ...)
AG_Object * AG_ObjectFindS (AG_Object *vfsRoot, const char *name)
AG_Object * AG_ObjectFindParent (AG_Object *obj, const char *name, const char *type)
AG_Object * AG_ObjectFindChild (AG_Object *obj, const char *name)
int AG_ObjectCopyName (AG_Object *obj, char *pathbuf, size_t pathbuf_len)
void AG_ObjectLock (AG_Object *obj)
void AG_ObjectUnlock (AG_Object *obj)
void AG_LockVFS (AG_Object *obj)
void AG_UnlockVFS (AG_Object *obj)
void AG_ObjectSetName (AG_Object *obj, const char *fmt, ...)
void AG_ObjectSetNameS (AG_Object *obj, const char *name)
void AG_ObjectGenName (AG_Object *obj, AG_ObjectClass *classInfo, char *name, size_t len)
void AG_ObjectGenNamePfx (AG_Object *obj, const char *prefix, char *name, size_t len)
void AG_ObjectSetAttachFn (AG_Object *obj, void (*fn)(struct ag_event *), const char *fmt, ...)
void AG_ObjectSetDetachFn (AG_Object *obj, void (*fn)(struct ag_event *), const char *fmt, ...)
void AG_ObjectSetDebugFn (AG_Object *obj, void (*fn)(void *obj, void *userPtr, void *msg), void *userPtr)
AGOBJECT_FOREACH_CHILD (AG_Object *child, AG_Object *parent, TYPE type)
|
The
AG_ObjectNew() function allocates and initializes a new object instance of the given class.
The object is attached to
parent, unless the argument is NULL.
If
name is NULL, a unique name of the form
<class-name> #<number> is automatically generated.
If both
parent and
name are specified and the parent object already has a child of the given name,
AG_ObjectNew() fails and returns NULL.
The
AG_ObjectInit() function initializes an object of the specified class.
This involves invoking the
init() operation associated with every class in the inheritance hierarchy.
name specifies a name for the object instance (maximum
AG_OBJECT_NAME_MAX bytes and must not contain
" / " characters).
classInfo should point to an initialized
AG_ObjectClass structure (see
CLASSES section).
The
flags argument specifies a default set of flags (see
FLAGS section).
The
AG_ObjectInitStatic() function is a variant of
AG_ObjectInit() which marks the new object as statically-allocated.
(see description of the
AG_OBJECT_STATIC flag).
Objects are organized in a tree structure.
AG_ObjectAttach() attaches an object to a new parent and
AG_ObjectDetach() detaches an object from its current parent.
These operations raise
attached and
detached events.
Prior to detaching the object,
AG_ObjectDetach() cancels scheduled
AG_Timeout(3) events where the
AG_CANCEL_ONDETACH flag is set.
If
parent is NULL,
AG_ObjectAttach() is a no-op.
The
AG_ObjectMoveUp(), AG_ObjectMoveDown(), AG_ObjectMoveToHead() and
AG_ObjectMoveToTail() functions move the object in the parent object's list of child objects.
These functions are useful when the ordering is important - when the child
objects represent a stack, for instance.
The
fn AG_ObjectDeleteroutine invokes
AG_ObjectDetach() if the object is attached to a parent, followed by
AG_ObjectDestroy().
AG_ObjectAttachToNamed() is a variant of
AG_ObjectAttach() which looks up the parent inside the specified VFS using the pathname
path.
AG_ObjectRoot() returns a pointer to the root of the VFS which the given object is attached to.
AG_ObjectParent() returns the immediate parent of the given object.
AG_ObjectFind() performs a pathname lookup on the specified VFS.
The function returns a pointer to the target object on success,
otherwise NULL is returned.
AG_ObjectFindParent() performs a reverse lookup, starting from the specified object itself, up to
the root of the VFS.
For each element encountered, the object's name is compared against
name (if not-NULL) and the object class is compared against
type (if not NULL).
AG_ObjectFindChild() performs a name lookup on the immediate children of the specified object.
The function returns the matching object if it was found, otherwise NULL.
AG_ObjectCopyName() copies the absolute pathname of an object instance to a fixed-size buffer.
Under multithreading, the returned pathnames can be considered valid only
as long as the VFS of the object remains locked.
AG_ObjectLock() and
AG_ObjectUnlock() acquire or release the locking device associated with the given object.
This is a mutex protecting all read/write members of the
AG_Object structure, except
parent, root and the list of child objects
cobjs which are all considered part of the virtual filesystem and are instead
protected by
AG_LockVFS(). In most cases, it is best to use the
AG_ObjectLock() mutex as a general-purpose locking device for subclasses of
AG_Object, because it is guaranteed to be held during processing of events posted to the
object, or object operations such as
load() and
save().
The
AG_LockVFS() and
AG_UnlockVFS() functions acquire or release the lock protecting the layout of the entire
virtual system which the given object is part of.
Note that all lock/unlock functions are turned to no-ops if Agar is compiled
without threads support.
AG_ObjectSetName() changes the name of the given object.
If the object is attached to a VFS, it is assumed to be locked.
AG_ObjectGenName() generates an object name string unique to the specified parent object
obj. The class name is used as prefix, followed by a number.
The name is written to the fixed-size buffer
name of the given size
len. In a multithreaded context, the name is only guaranteed to remain unique as
long as the parent object's VFS is locked.
Similarly,
AG_ObjectGenNamePfx() generates a name using the specified prefix instead of the class name.
AG_ObjectSetAttachFn() and
AG_ObjectSetDetachFn() allow custom "attach" and "detach" hooks to be registered.
These hooks are used where it is necessary to control the order of the
child objects (for example, in the
AG_Window(3) system of Agar-GUI, the ordering of window objects is important as it
determines the order of rendering).
The hook function is expected to insert the child object somewhere into the
parent's
children list.
AG_ObjectSetDebugFn() specifies a function to process debug messages (as issued by
AG_Debug(3)) for the object.
This function is a no-op unless Agar was compiled with --enable-debug.
The
AGOBJECT_FOREACH_CHILD() macro iterates
child over every child object of
parent. The
child pointer is cast to the given structure
type, without type checking.
Example:
struct my_class *chld;
AGOBJECT_FOREACH_CHILD(chld, parent, my_class) {
printf("Child object: %s\\n", AGOBJECT(chld)->name);
}
|
CLASSES
void AG_RegisterClass (AG_ObjectClass *classInfo)
void AG_UnregisterClass (AG_ObjectClass *classInfo)
void AG_RegisterNamespace (const char *name, const char *prefix, const char *url)
void AG_UnregisterNamespace (const char *name)
AG_ObjectClass * AG_LookupClass (const char *classSpec)
AG_ObjectClass * AG_LoadClass (const char *classSpec)
void AG_RegisterModuleDirectory (const char *path)
void AG_UnregisterModuleDirectory (const char *path)
int AG_OfClass (AG_Object *obj, const char *pattern)
AG_ObjectClass * AG_ObjectSuperclass (AG_Object *obj)
AGOBJECT_FOREACH_CLASS (AG_Object *child, AG_Object *parent, TYPE type, const char *pattern)
|
The
AG_RegisterClass() function registers a new object class.
The
classInfo argument should point to an initialized
AG_ObjectClass structure, which is defined as:
typedef struct ag_object_class {
const char *name; /* Class name */
size_t size; /* Size of structure */
AG_Version ver; /* Version numbers */
void (*init)(void *obj);
void (*reinit)(void *obj);
void (*destroy)(void *obj);
int (*load)(void *obj, AG_DataSource *buf, const AG_Version *ver);
int (*save)(void *obj, AG_DataSource *buf);
void *(*edit)(void *obj);
} AG_ObjectClass;
The structure pointed by
classInfo is used directly, it is not duplicated.
Note that it is customary to overload
AG_ObjectClass. For example,
AG_WidgetClass in Agar-GUI (see
AG_Widget(3)) augments
AG_ObjectClass with widget-specific operations such as
draw() and
sizeRequest().
The
name string specifies the full inheritance hierarchy and name of this class.
Subclasses are separated by colons, as in
AG_Superclass:AG_Subclass, or alternatively,
Namespace(Superclass:Subclass) or
Namespace(Superclass:Subclass)@modules. If the optional
@modules string exists, it specifies a comma-separated list of dynamically-linked
library (modules) accessible from
AG_DSO(3). It is implied that
AG_Object is the "root class", so there is no need to specify it in the string.
size specifies the size in bytes of the object instance structure.
ver is the datafile version number (see
AG_Version(3)).
The
init() operation initializes an
AG_Object instance.
reinit() releases any element of the dataset that has been dynamically allocated.
It is invoked by the object system prior to
load() or
destroy().
The
destroy() operation is invoked from
AG_ObjectDestroy() to release any resources which are not handled by
reinit(). Note that
destroy() must not free the
AG_Object structure itself.
The
load() and
save() operations are responsible for archiving the dataset (see the
ARCHIVING section for more information).
When defined, the
edit() operation generates user interface elements allowing the user to edit
the object's dataset.
It is a generic operation, not dependent on any particular GUI library.
If using the Agar-GUI for example,
edit() is expected to create a
AG_Window(3) or a container widget such as
AG_Box(3).
Note that whenever the
init(), reinit(), load(), save() and
destroy() operations are used, they are invoked for every class in the inheritance
hierarchy of the given object.
AG_UnregisterClass() removes the specified object class.
AG_RegisterNamespace() registers a new namespace with the specified name, prefix and informational
URL.
For example, Agar registers its own namespace using:
AG_RegisterNamespace("Agar", "AG_", "http://libagar.org/");
Once the namespace is registered, it is possible to specify inheritance
hierarchies using the
namespace format:
Agar(Widget:Button):MyLib(MyButton)
or the equivalent
expanded format:
AG_Widget:AG_Button:MY_Button
The
AG_UnregisterNamespace() function removes all information about the specified namespace.
The
AG_LookupClass() function looks up the
AG_ObjectClass structure describing the specified class (in namespace or expanded format).
If there is no currently registered class matching the specification,
AG_LookupClass() returns NULL.
AG_LoadClass() ensures that the object class specified in
classSpec (see
AG_RegisterClass() for details on the format) is registered, possibly loading one or more
dynamic library files if they are specified in the string.
Dynamic library dependencies are given in the form of a terminating
@lib1,lib2,... string.
AG_LoadClass() scans the registered module directories (see
AG_RegisterModuleDirectory()) for the libraries specified in the string.
Bare library names are given (the actual filenames are platform-dependent).
Libraries that are found (and not already in memory) are loaded via
AG_DSO(3). The first library must define a
myFooClass symbol (where
myFoo is the name of the class transformed from
MY_Foo), for an
AG_ObjectClass structure describing the class (i.e., the same structure that is passed to
AG_RegisterClass()).
AG_UnloadClass() unregisters the specified class and also decrements the reference count of
any dynamically-located module associated with it.
If this reference count reaches zero, the module is removed from the current
process's address space.
The
AG_RegisterModuleDirectory() function adds the specified directory to the module search path.
AG_UnregisterModuleDirectory() removes the specified directory from the search path.
The
AG_OfClass() function returns 1 if the object is an instance of the class specified in
the
pattern, string.
The pattern may contain wildcards such as
MyClass:* or
MyClass:*:MySubclass:*.
The
AG_ObjectSuperclass() function returns a pointer to the
AG_ObjectClass structure describing the superclass of the given object (or if the object is
an instance of the base class, the base class is returned).
The
AGOBJECT_FOREACH_CLASS() macro iterates
child over every child object of
parent which is an instance of the class specified by
pattern. child is cast to the given structure
type. Example:
struct my_class *chld;
AGOBJECT_FOREACH_CLASS(chld, parent, my_class, "MyClass") {
printf("Object %s is an instance of MyClass\\n",
AGOBJECT(chld)->name);
}
|
DEPENDENCIES
int AG_ObjectInUse (AG_Object *obj)
AG_ObjectDep * AG_ObjectAddDep (AG_Object *obj, AG_Object *depobj, int persistent)
void AG_ObjectDelDep (AG_Object *obj, AG_Object *depobj)
Uint32 AG_ObjectEncodeName (AG_Object *obj, AG_Object *depobj)
int AG_ObjectFindDep (AG_Object *obj, Uint32 ind, AG_Object **objp)
|
AG_ObjectInUse() returns 1 if the given object is being referenced by another object instance
or 0 if it isn't.
AG_ObjectAddDep() either creates a new dependency upon
depobj or increments the reference count if one exists.
If the
persistent flag is set, the reference is preserved in object archives.
AG_ObjectDelDep() decrements the reference count upon
depobj and removes the dependency if the count reaches zero (unless the object has the
AG_OBJECT_PRESERVE_DEPS flag set).
AG_ObjectEncodeName() returns a 32-bit integer identifier for the dependency, suitable for writing
into data files.
It may return the special values 0 (NULL reference) and 1 (self-reference),
the meaning of which is object-specific.
AG_ObjectFindDep() tries to resolve the given 32-bit dependency identifier, return 0 on success
and -1 on failure.
|
RELEASING RESOURCES
void AG_ObjectDestroy (AG_Object *obj)
void AG_ObjectFreeDataset (AG_Object *obj)
void AG_ObjectFreeEvents (AG_Object *obj)
void AG_ObjectFreeVariables (AG_Object *obj)
void AG_ObjectFreeDeps (AG_Object *obj)
void AG_ObjectFreeDummyDeps (AG_Object *obj)
void AG_ObjectFreeChildren (AG_Object *obj)
|
The
AG_ObjectFreeDataset() function frees any dynamically allocated resources by invoking the
reinit() of every class in the inheritance hierachy.
The function also clears the
AG_OBJECT_RESIDENT flag.
Contrary to the
destroy() operation,
reinit() must leave the data structures in a consistent state (e.g., for a subsequent
load() operation).
The
AG_ObjectDestroy() function frees all resources reserved by the given object (and any of its
children that is not being referenced).
AG_ObjectDestroy() invokes the
reinit() and
destroy() operations of every class in the inheritance hierarchy.
Note that
AG_ObjectDestroy() also cancels any
AG_Timeout(3) event scheduled for future execution.
Unless the
AG_OBJECT_STATIC flag is set,
AG_ObjectDestroy() invokes
free(3) on the structure.
Internally,
AG_ObjectDestroy() invokes
AG_ObjectFreeEvents(), AG_ObjectFreeVariables(), AG_ObjectFreeDeps() and
AG_ObjectFreeChildren(), but these functions may be called directly in order to destroy and reinitialize
the event handler list, the
AG_Variable(3) table and destroy the child objects,
respectively.
In addition to reinitializing the event handler table,
AG_ObjectFreeEvents() also cancels scheduled events.
AG_ObjectFreeChildren() releases all resources allocated by child objects, under the specified parent
object.
The function assumes that none of the child objects are currently in use.
AG_ObjectFreeDummyDeps() removes entries in the dependency table where the reference count is zero
(which occur in objects that have the
AG_OBJECT_PRESERVE_DEPS flag set).
|
ARCHIVING
int AG_ObjectLoad (AG_Object *obj)
int AG_ObjectLoadFromFile (AG_Object *obj, const char *file)
int AG_ObjectLoadData (AG_Object *obj)
int AG_ObjectLoadDataFromFile (AG_Object *obj, const char *file)
int AG_ObjectLoadGeneric (AG_Object *obj)
int AG_ObjectLoadGenericFromFile (AG_Object *obj, const char *file)
int AG_ObjectSave (AG_Object *obj)
int AG_ObjectSaveAll (AG_Object *obj)
int AG_ObjectSaveToFile (AG_Object *obj, const char *path)
int AG_ObjectSerialize (AG_Object *obj, AG_DataSource *ds)
int AG_ObjectUnserialize (AG_Object *obj, AG_DataSource *ds)
int AG_ObjectReadHeader (AG_Object *obj, AG_ObjectHeader *header)
int AG_ObjectPageIn (AG_Object *obj)
int AG_ObjectPageOut (AG_Object *obj)
|
These functions implement archiving (or "serialization") of generic object
information and arbitrary datasets to an efficient, machine-independent
representation.
The
AG_ObjectLoad() function (and its variants) are used to load the generic part or the dataset
of either a single object or an object hierarchy, from archived data.
AG_ObjectLoad() invokes the
load() operation of every class in the inheritance hierarchy of the object.
AG_ObjectLoad(), AG_ObjectLoadGeneric() and
AG_ObjectLoadData() look for the archive file in the default search path (using the
load-path setting of
AG_Config(3)).
AG_ObjectLoadFromFile(), AG_ObjectLoadGenericFromFile() and
AG_ObjectLoadDataFromFile() will load the data from a specific file.
Note that when loading object hierarchies, objects will need to be allocated
and initialized from scratch.
This functionality requires that all classes be registered with
AG_RegisterClass().
The
AG_ObjectSave() function creates an archive of the given object in the default location
(i.e., the
save-path setting of
AG_Config(3)). AG_ObjectSave() invokes the
load() operation of every class in the inheritance hierarchy of the object.
The
AG_ObjectSaveAll() variant also saves the entire tree of child objects.
AG_ObjectSaveToFile() archives the given object to the specified file.
AG_ObjectSerialize() writes an archive of the given object to the specified
AG_DataSource(3), and
AG_ObjectUnserialize() reads an archive of the given object.
Note that the
AG_OBJECT_CHLD_AUTOSAVE feature will not work with these functions.
The
AG_ObjectReadHeader() routine decodes a standard Agar object archive header.
On success, it returns 0 and writes the information to the
header structure:
typedef struct ag_object_header {
char hier[AG_OBJECT_HIER_MAX]; /* Inheritance hierarchy */
char libs[AG_OBJECT_LIBS_MAX]; /* Library list */
char classSpec[AG_OBJECT_HIER_MAX]; /* Full class specification */
Uint32 dataOffs; /* Dataset offset */
AG_Version ver; /* AG_Object version */
Uint flags; /* Object flags */
} AG_ObjectHeader;
The
AG_ObjectPageIn() function loads an object's dataset into memory, assuming it is a persistent
object and its dataset can be found on storage.
On success, the
AG_OBJECT_RESIDENT flag is set.
AG_ObjectPageOut() checks whether an object is referenced by another object and if that is
not the case, the dataset is archived to storage and freed from memory.
Both functions return 0 on success or -1 if an error occured.
|
FLAGS
The following public
AG_Object flags are defined:
| AG_OBJECT_FLOATING_VARS | Remove all entries of the
AG_Variable(3) table in
AG_ObjectLoad(). By default, the existing table is preserved and entries are created or
replaced by items found in the archive.
| | AG_OBJECT_NON_PERSISTENT | Disables archiving of the object and its children.
If set,
AG_ObjectSave() becomes a no-op and
AG_ObjectLoad() calls will fail.
| | AG_OBJECT_INDESTRUCTIBLE | Advisory and application-specific.
| | AG_OBJECT_RESIDENT | Read-only flag set by the object system to indicate that the object's dataset
is currently resident in memory.
This flag is set by
AG_ObjectNew(), AG_ObjectLoadData() and
AG_ObjectPageIn() and is cleared by
AG_ObjectFreeDataset() and
AG_ObjectPageOut(). | | AG_OBJECT_PRESERVE_DEPS | Disable automatic removal of object dependencies when reference counts
reach 0.
| | AG_OBJECT_STATIC | Indicates that this object is either statically-allocated (or allocated
through another facility than
malloc(3)). The
AG_ObjectDestroy() operation will not call
free(3) on the structure.
| | AG_OBJECT_READONLY | Advisory and application-specific.
| | AG_OBJECT_REOPEN_ONLOAD | If the object has a
edit operation, arrange for all graphical interface elements (as returned by
edit) to be automatically destroyed and recreated after any
AG_ObjectLoad() call.
This flag is useful for complex objects where the graphical interface
references elements of the dataset.
| | AG_OBJECT_REMAIN_DATA | Prevent the object's dataset from being automatically freed (with
AG_ObjectFreeDataset()) as a result of an
AG_ObjectPageOut() call, when the reference count reaches zero.
| | AG_OBJECT_DEBUG | Enable per-object debugging; application-specific.
| | AG_OBJECT_NAME_ONATTACH | Request that
AG_ObjectAttach() calls automatically generates a name for the child object being attached.
The name will be unique in the parent.
| | AG_OBJECT_CHLD_AUTOSAVE | Arrange for child objects to be automatically saved along with the object
when
AG_ObjectSave*() is invoked.
|
|
EVENTS
The
AG_Object mechanism generates the following events:
attached (void)
| The object has been attached to another.
This event originates from the parent object.
The linkage lock is held during the execution of the event handler.
| detached (void)
| The object has been detached from its parent.
The linkage lock is held during the execution of the event handler.
This event originates from the parent.
| child-attached (void)
| Same as
attached(), except that the event is sent from the child to the parent.
| child-detached (void)
| Same as
detached(), except that the event is sent from the child to the parent.
| moved (AG_Object *new_parent)
| The object has been moved from its current parent to
new_parent. The linkage lock is held during the execution of the event handler.
This event originates from the previous parent.
| renamed (void)
| The object's name has changed.
| object-post-load-data (const char *path)
| Invoked by
AG_ObjectLoadData(), on success.
If the object was loaded from file,
path is the pathname of the file.
| bound (AG_Variable *V)
| A new variable binding has been created, or the value of an existing binding
has been updated; see
AG_Variable(3) for details.
|
|
EXAMPLES
|
See
demos/objsystem in the Agar source distribution.
|
SEE ALSO
HISTORY
|
The
AG_Object interface appeared in
Agar 1.0
| |