Agar


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 AG_Event interface implements a system of virtual functions for purposes of servicing events, on top of AG_Object(3). Event handler functions are passed a list of zero or more arguments. Execution of event handlers can be delayed for a set amount of time, or marked for execution in a separate thread (where thread support is available).

Event processing is triggered by the AG_PostEvent() function, which causes the execution the event handler routine(s) previously registered by AG_SetEvent() or AG_AddEvent(). Event handlers are declared as:


void MyEventHandler (AG_Event *event)




The event structure contains the event arguments, which are most convenient retrieved using macros; see EVENT ARGUMENTS below for details.

EVENT LOOP

This manual page documents the general event system in the Agar-Core library. For information on the AG_EventLoop() function, see AG_EventLoop(3).

EVENT PROCESSING


AG_Event * AG_SetEvent (AG_Object *obj, const char *event_name, void (*fn)(AG_Event *event), const char *fnArgs, ...)

AG_Event * AG_AddEvent (AG_Object *obj, const char *event_name, void (*fn)(AG_Event *event), const char *fnArgs, ...)

AG_Event * AG_FindEventHandler (AG_Object *obj, const char *name)

void AG_UnsetEvent (AG_Object *obj, const char *event_name)

int AG_PostEvent (AG_Object *sndr, AG_Object *rcvr, const char *event_name, const char *fmt, ...)

int AG_SchedEvent (AG_Object *sndr, AG_Object *rcvr, Uint32 ticks, const char *event_name, const char *fmt, ...)

int AG_ReschedEvent (AG_Object *obj, const char *event_name, Uint32 ticks)

int AG_CancelEvent (AG_Object *obj, const char *event_name)

void AG_ForwardEvent (AG_Object *sndr, AG_Object *rcvr, AG_Event *event)


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 that should be passed on to the event handler function. See EVENT ARGUMENTS below for details.

In some circumstances it is useful to pass a NULL name argument to AG_SetEvent() or AG_AddEvent() and instead reference the event handler using the returned AG_Event * pointer returned by the function. This is useful when implementing custom interfaces accepting fnArgs style arguments.

The AG_FindEventHandler() function returns the AG_Event structure for the specified event, or NULL if there are no handlers associated with it.

The AG_UnsetEvent() function removes the named event handler from the list. Any future execution of this event handler as scheduled by AG_SchedEvent() will be cancelled. If this event handler is currently being executed (in the case of a multi-threaded timing scheme), the function waits for its termination.

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_SchedEvent() function is similar to AG_PostEvent(), except that the event is scheduled to occur in the given number of ticks (the meaning of which is specific to the timing scheme). It is not possible to schedule the execution of the same event handler multiple times. AG_SchedEvent() returns 0 on success or -1 if no matching event handler was found.

The AG_ReschedEvent() function reschedules a previously scheduled event of the given name to execute in the given number of ticks, using the same argument vector. AG_ReschedEvent() returns 0 on success or -1 if there was no matching event handler.

AG_CancelEvent() cancels any future execution of a previously scheduled event. The function returns -1 if no matching event was found, 1 if a scheduled event was cancelled, or 0 if there was nothing to cancel.

The AG_ForwardEvent() function relays the given event to object rcvr, passing sndr as the sender pointer.

EVENT ARGUMENTS

The 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 function. 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:
void
MyEventHandler(AG_Event *event)
{
	char *s = AG_STRING(1);
	void *p = AG_PTR(2);
	int i = AG_INT(3);
}

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:
void
MyEventHandler(AG_Event *event)
{
	char *s = AG_STRING_NAMED("foo");
	void *p = AG_PTR_NAMED("bar");
	int i = AG_INT_NAMED("baz");
}

The following argument specifiers are accepted:
"%p"An arbitrary pointer (void *).
"%Cp"An arbitrary pointer (const void *).
"%i"A signed integer argument (int).
"%u"An unsigned integer argument (Uint).
"%li"A signed long integer argument (long).
"%lu"An unsigned long integer argument (Ulong).
"%f"A real argument (float).
"%d"A real argument (double).
"%s"A string argument (char *).
"%Cs"A string argument (const char *).

The following macros allow event handler routines to retrieve the arguments passed to them. Variable arguments are supported - in that case, arguments can be retrieved directly from the event structure (see STRUCTURE DATA).


AG_Object * AG_SELF (void)

AG_Object * AG_SENDER (void)

void * AG_PTR (int index)

AG_Object * AG_OBJECT (int index, const char *classSpec)

char * AG_STRING (int index)

int AG_INT (int index)

Uint AG_UINT (int index)

long AG_LONG (int index)

Ulong AG_ULONG (int index)

float AG_FLOAT (int index)

double AG_DOUBLE (int index)

void * AG_PTR_NAMED (const char *key)

AG_Object * AG_OBJECT_NAMED (const char *key, const char *classSpec)

char * AG_STRING_NAMED (const char *key)

int AG_INT_NAMED (const char *key)

Uint AG_UINT_NAMED (const char *key)

long AG_LONG_NAMED (const char *key)

Ulong AG_ULONG_NAMED (const char *key)

float AG_FLOAT_NAMED (const char *key)

double AG_DOUBLE_NAMED (const char *key)


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, keep in mind that the list of arguments passed by AG_PostEvent() follow the list of arguments provided by AG_SetEvent(). If debugging was enabled at compile time, these macros also ensure 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() and AG_DOUBLE() return the specified native floating-point number, previously passed as %f or %F 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.

ARGUMENT MANIPULATION

In some cases it is desirable for functions to accept a list of event handler arguments like 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.


void AG_EventInit (AG_Event *ev)

void AG_EventArgs (AG_Event *ev, const char *fmt, ...)

void AG_EventPushPointer (AG_Event *ev, const char *key, void *val)

void AG_EventPushString (AG_Event *ev, const char *key, char *val)

void AG_EventPushInt (AG_Event *ev, const char *key, int val)

void AG_EventPushUint (AG_Event *ev, const char *key, Uint val)

void AG_EventPushLong (AG_Event *ev, const char *key, long val)

void AG_EventPushULong (AG_Event *ev, const char *key, Ulong val)

void AG_EventPushFloat (AG_Event *ev, const char *key, float val)

void AG_EventPushDouble (AG_Event *ev, const char *key, douvle val)

void AG_EVENT_PUSH_ARG (va_list ap, char formatChar, AG_Event *ev)

void AG_EventPopArgument (AG_Event *ev)


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.

EVENT QUEUES

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. The AG_EventQ structure describes a queue of events:
typedef struct ag_event_queue {
	Uint     nEvents;
	AG_Event *events;
} AG_EventQ;

The following routines operate on the AG_EventQ structure:


void AG_InitEventQ (AG_EventQ *eq)

void AG_FreeEventQ (AG_EventQ *eq)

void AG_QueueEvent (AG_EventQ *eq, const char *event_name, const char *fmt, ...)



The AG_InitEventQ() function initializes an AG_EventQ structure. AG_FreeEventQ() releases all resources allocated under an event queue.

AG_QueueEvent() inserts an event in an event queue structure. The meaning of event_name as well as the syntax of fmt are identical to. AG_PostEvent().

STRUCTURE DATA

For the AG_Event structure:
char name* String identifier for the event.
Uint flags See EVENT FLAGS section below.
int argc Argument count.
AG_Variable *argv Argument data (see AG_Variable(3)).

EVENT FLAGS

Acceptable flags for the AG_Event structure include:
AG_EVENT_ASYNCArrange for the event handler to execute inside a separate thread that will be automatically created (and managed by the receiver object). This flag is only available if Agar was compiled with the AG_THREADS option.
AG_EVENT_PROPAGATEWhenever this event is raised, automatically raise the same event for any child object attached to the given object. Unless AG_EVENT_ASYNC is used, it is safe to assume that the child object's handler is executed before the parent's.
AG_EVENT_SCHEDULEDEvent was previously scheduled for execution by AG_SchedEvent() (read-only).

EXAMPLES

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 int).
void
SayHello(AG_Event *event)
{
	char *s = AG_STRING(1);    /* Given in AG_SetEvent() */
	int new_state = AG_INT(2); /* Passed by 'button-pushed',
	                              see AG_Button(3) */
	AG_TextMsg(AG_MSG_INFO, "Hello, %s! (state = %d)",
	    s, new_state);
}
AG_Button *btn = AG_ButtonNew(NULL, 0, "Say hello");
AG_SetEvent(btn, "button-pushed", SayHello, "%s", "World");

The AG_Button API also provides an alternate constructor routine, AG_ButtonNewFn(), with which you can specify the default button-pushed event handler:
AG_ButtonNewFn(NULL, 0, "Say hello", SayHello, "%s", "World");

The following code fragment does the same, specifying the arguments in a more explicit way:
AG_Button *btn = AG_ButtonNew(NULL, 0, "Say hello");
AG_Event *event = AG_SetEvent(btn, "button-pushed", SayHello, NULL);
AG_EventPushString(event, NULL, "World");

The following code fragment invokes an event handler routine directly, independently of the object system:
void
SayHello(AG_Event *event)
{
	char *foostring = AG_STRING(1);
	int fooint = AG_INT(2);
}
AG_Event event;
AG_EventArgs(&event, "%s,%d", "Foo string", 1234);
SayHello(&event);

SEE ALSO

AG_Intro(3), AG_EventLoop(3), AG_Object(3), AG_Timeout(3), AG_Variable(3)

HISTORY

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.