AG_Event
—
agar event system
The AG_Event
interface implements a system of virtual
functions for purposes of servicing events. An
AG_Object(3)
may act as an event sender, or an event receiver. 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.
NOTE: This manual page documents Agar's high-level event
processing interface. For more information on low-level event processing,
see
AG_EventLoop(3).
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_Function *
AG_SetVoidFn
(AG_Object
*obj, void (*fn)(AG_Event
*event), const char
*fnArgs, ...);
AG_Function *
AG_SetIntFn
(AG_Object
*obj, int (*fn)(AG_Event
*event), const char
*fnArgs, ...);
AG_Function *
AG_SetUint8Fn
(AG_Object
*obj, Uint8
(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetSint8Fn
(AG_Object
*obj, Sint8
(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetUint16Fn
(AG_Object
*obj, Uint16
(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetSint16Fn
(AG_Object
*obj, Sint16
(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetUint32Fn
(AG_Object
*obj, Uint32
(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetSint32Fn
(AG_Object
*obj, Sint32
(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetUint64Fn
(AG_Object
*obj, Uint64
(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetSint64Fn
(AG_Object
*obj, Sint64
(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetFloatFn
(AG_Object
*obj, float
(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetDoubleFn
(AG_Object
*obj, double
(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetLongDoubleFn
(AG_Object
*obj, long double
(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetStringFn
(AG_Object
*obj, size_t
(*fn)(AG_Event *event, char *buf, size_f buf_size),
const char *fnArgs,
...);
AG_Function *
AG_SetPointerFn
(AG_Object
*obj, void
*(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetConstPointerFn
(AG_Object
*obj, const void
*(*fn)(AG_Event *event),
const char *fnArgs,
...);
AG_Function *
AG_SetTextFn
(AG_Object
*obj, AG_Text
*(*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_PostEventByPtr
(AG_Object
*sndr, AG_Object
*rcvr, AG_Event
*event, const char
*fmt, ...);
int
AG_SchedEvent
(AG_Object
*sndr, AG_Object
*rcvr, Uint32
ticks, const char
*event_name, const char
*fmt, ...);
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.
The AG_Set<TYPE>Fn
() family of
functions create a virtual function with a return value of the specified
TYPE. By default, virtual functions are unnamed (and referenced by the
returned AG_Function
() handle). Names can still be
assigned to virtual functions by setting the name
field. 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.
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.
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.
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
().
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)).
Acceptable flags for the AG_Event
structure include:
- AG_EVENT_ASYNC
- Arrange 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_PROPAGATE
- Automatically forward events of this type to all attached child objects.
If
AG_EVENT_ASYNC
is also set, the event handlers
of the child objects are executed concurrently.
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 provides a shorthand
constructor routine, AG_ButtonNewFn
(), which accepts
the ‘button-pushed’ event handler as argument:
AG_ButtonNewFn(NULL, 0, "Say hello", SayHello, "%s", "World");
The following code fragment is equivalent:
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 a handler routine
artificially:
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);
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.