Note: The Agar manual pages follow certain conventions, notably concerning function return values. Please read AG_Intro(3) first.
SYNOPSIS
#include <agar/core.h> |
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
|
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() variant of AG_ObjectInit() implicitely sets the AG_OBJECT_STATIC flag (see FLAGS). The AG_ObjectInitNamed() variant either implicitely calls AG_ObjectSetNameS() if the name argument is non-NULL, or it sets the AG_OBJECT_NAME_ONATTACH flag if the name is NULL (see FLAGS for details). 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
|
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
RELEASING RESOURCES
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). The AG_ObjectRemain() function specifies the behavior of AG_ObjectPageOut() once a dataset is no longer in use. The default behavior is to free the dataset. If an argument of AG_OBJECT_REMAIN_DATA is passed, the dataset will be kept in memory. |
ARCHIVING
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:
|
EVENTS
The
AG_Object mechanism generates the following events:
|
EXAMPLES
| See demos/objsystem in the Agar source distribution. |
SEE ALSO
| AG_Intro(3), AG_Event(3), AG_Variable(3), AG_Timeout(3) |
HISTORY
| The AG_Object interface appeared in Agar 1.0 |

