AG_Function) represents a typed virtual function under an
AG_Object(3). Virtual functions are tagged with a case-insensitive string up to
AG_EVENT_NAME_MAX bytes in size.
An empty string denotes an anonymous virtual function.
Event handlers and virtual functions are declared as:
Virtual functions are passed a pointer to an AG_Event which contains a stack of up to AG_EVENT_ARGS_MAX arguments. Arguments are typed and may be tagged with a case-insensitive string (up to AG_VARIABLE_NAME_MAX bytes). How the argument stack is constructed is up to the developer. Typically, it is established by an initial AG_SetEvent() call to set up the callback function, followed by subsequent calls to AG_PostEvent() (so the event handler will see the AG_SetEvent() arguments followed by the AG_PostEvent() arguments, if any, see EVENT ARGUMENTS for details).
Agar objects can act as event senders or event receivers. Execution of event handlers can be delayed for a set amount of time, or marked for execution in a separate thread. AG_Event provides a thread-safe message passing system for multithreaded applications.
NOTE: This page documents Agar's high-level message passing system. For event loops and low-level event processing, see AG_EventLoop(3).
The AG_SetEvent() function registers a new event handler to service events of type name. If an event handler is already registered for the given event type, it is replaced. The AG_AddEvent() variant preserves any existing event handler, such that multiple handlers can be invoked when the event is raised. The fn argument is a pointer to the event handler function, and fnArgs is a special kind of format string specifying a list of arguments (see EVENT ARGUMENTS section).
The AG_Set<TYPE>Fn() routines create a virtual function with a return value of the specified TYPE. The optional name field may be empty or NULL, denoting an anonymous virtual function (which can still be referenced by the returned AG_Function() handle). Since event handlers and virtual functions are implemented identically, the AG_Function type is just an alias for AG_Event.
The AG_FindEventHandler() function searches for an event handler by name, returning a pointer to the AG_Event element on success or NULL if there is no match.
The AG_UnsetEvent() function deletes the named event handler.
The AG_PostEvent() function immediately executes the event handler function associated with the given event type, if there is any. The fn and fnArgs arguments to AG_PostEvent() are interpreted in the same way as AG_SetEvent() and AG_AddEvent(), but the arguments are appended at the end of the argument list. When the event handler function retrieves arguments by index (as opposed to using argument names), it is important to remember that the arguments to AG_PostEvent() follow the arguments given to AG_SetEvent() or AG_AddEvent().
The AG_PostEvent() function returns 1 if an event handler was invoked, or 0 if there is no registered event handler for the specified event.
The AG_PostEventByPtr() variant accepts a pointer to an AG_Event element, as opposed to looking up the event handler by name.
The AG_SchedEvent() function provides an interface similar to AG_PostEvent(), except that the event is scheduled to occur in the given number of ticks AG_SchedEvent() returns 0 on success or -1 if the timer could not be created. If the object is detached or destroyed, all events scheduled for execution are automatically cancelled. A more flexible interface for implementing timers is described in AG_Timer(3) (which AG_SchedEvent() uses internally).
The AG_ForwardEvent() function relays the given event to object rcvr, passing sndr as the sender pointer.
AG_SetEvent(), AG_AddEvent() and
AG_PostEvent() routines accept a special
fnArgs format string specifying a list of arguments to be passed to the event handler
For example, the
%s,%p,%i string specifies that the following arguments are a string, a pointer and an
int. The arguments would retrieved by the event handler function like so:
Named arguments are also supported. For example, the format string %s(foo),%p(bar),%i(baz) specifies string, pointer and integer arguments, which can be retrieved using:
The following argument specifiers are accepted:
The following macros extract the arguments contained in an AG_Event structure. If Agar is compiled with either --enable-debug or --enable-type-safety, they also check for potential accesses to incorrect types.
The AG_SELF() macro (equivalent to AG_PTR(0)) returns a pointer to the AG_Object(3) receiving the event (the rcvr argument to AG_PostEvent()). AG_SENDER() returns a pointer to the object sending the event (the sndr argument to AG_PostEvent()), if there is one.
The following macros return a specific item in the list of arguments. When retrieving arguments by index, note that the arguments to AG_PostEvent() follow the arguments to AG_SetEvent() (i.e., the arguments to AG_SetEvent() are pushed first onto the argument stack, followed by the arguments to AG_PostEvent(), if any). These macros ensure type safety if Agar is compiled with either --enable-debug or --enable-type-safety.
AG_PTR() returns a pointer, previously passed as a %p argument.
AG_OBJECT() returns a pointer to an AG_Object(3) (previously passed as a %p argument). It differs from AG_PTR() in that the object pointer is verified against the specified object class and a fatal error is raised if runtime type checking is in effect.
AG_STRING() returns a pointer to a string, previously passed as a %s argument. The event handler is not allowed to modify the string.
AG_INT(), AG_UINT(), AG_LONG() and AG_ULONG() return the specified native integral number, previously passed as a %i, %u, %li or %lu argument respectively.
AG_FLOAT(), AG_DOUBLE() and AG_LONG_DOUBLE() return the given floating-point number, previously passed as a %f, %d o %ld argument respectively.
The AG_*_NAMED() macros retrieve the given argument by name instead of by index. If there is no argument matching the name, a fatal error is raised.
In some cases it is desirable for functions to accept a list of event handler
AG_SetEvent(), and possibly manipulate its entries directly.
For example, the
AG_MenuAction(3) function of the GUI widget
AG_Menu(3) accepts a pointer to an event handler function, followed by an
AG_SetEvent() style format string and a variable list of arguments.
The following functions allow such manipulations.
The AG_EventInit() routine initializes an AG_Event structure with no arguments.
AG_EventArgs() initializes ev and also specifies a list of arguments (in the same format as AG_SetEvent()).
The AG_EventPush*() functions append an argument to the end of the argument list for the specified AG_Event structure.
The AG_EVENT_PUSH_ARG() macro also insert an argument, except that the type is obtained from formatChar, assumed to be a character from an AG_SetEvent() style format string, and the argument is retrieved using va_arg(3).
AG_EventPopArgument() removes the last argument from the list.
Under some circumstances, it is useful to gather
AG_Event objects into a simple queue.
For example, a custom event loop routine (see
AG_EventLoop(3)) or a low-level Agar driver (see
AG_Driver(3)) may gather events from input devices and later process them.
AG_EventQ structure describes a queue of events:
The following routines operate on the AG_EventQ structure:
The AG_InitEventQ() function initializes an AG_EventQ structure. AG_FreeEventQ() releases all resources allocated under an event queue.
AG_QueueEvent() inserts a named event in an event queue structure.
flags for the
AG_Event structure include:
The following code fragment demonstrates a typical
AG_Event usage in the Agar-GUI library.
We bind an action to the button press event, which is called
button-pushed. This event is documented in the
AG_Button(3) manual, and so are the arguments it appends to the list of arguments passed
to the event handler (in this case, a single
The AG_Button API provides a shorthand constructor routine, AG_ButtonNewFn(), which accepts the button-pushed event handler as argument:
The following code fragment is equivalent:
The following code fragment invokes a handler routine artificially:
|AG_EventLoop(3), AG_Intro(3), AG_Object(3), AG_Timer(3), AG_Variable(3)|
|The AG_Event mechanism first appeared in Agar 1.0. The AG_Variable(3) structure was first used to represent event handler arguments in Agar 1.3.4.|