.\" Copyright (c) 2002-2007 Hypertriton, Inc.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
.\" (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd September 16, 2002
.Dt AG_EVENT 3
.Os
.ds vT Agar API Reference
.ds oS Agar 1.0
.Sh NAME
.Nm AG_Event
.Nd agar event system
.Sh SYNOPSIS
.Bd -literal
#include
.Ed
.Sh DESCRIPTION
The
.Nm
interface implements a system of virtual functions for purposes of servicing
.Em events ,
on top of
.Xr AG_Object 3 .
Event handler functions are provided with a list of typed 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.
.Pp
Event processing is triggered by the
.Fn AG_PostEvent
function, which causes the execution the event handler routine(s)
previously registered by
.Fn AG_SetEvent
(or
.Fn AG_AddEvent ) .
Event handlers are declared as:
.Pp
.nr nS 1
.\" NOMANLINK
.Ft void
.Fn MyEventHandler "AG_Event *event"
.Pp
.nr nS 0
.Pp
The
.Fa event
structure contains a list of typed
.Em arguments ,
constructed from the arguments provided to
.Fn AG_SetEvent
and
.Fn AG_PostEvent .
Event handler arguments can be retrieved either by
.Em index
or from a
.Em name
string, and Agar can provide optional runtime type-checking.
See
.Dq EVENT ARGUMENTS
for more details.
.Sh EVENT LOOPS
.nr nS 1
.Ft "void"
.Fn AG_EventLoop "void"
.nr nS 0
.Pp
NOTE:
Although the
.Nm
interface is part of the Agar-Core library,
.Fn AG_EventLoop
is actually part of the Agar-GUI library (it is documented in this manual
page for historical reasons).
.Pp
The event loop of an Agar application typically waits for events, invokes
GUI rendering routines and processes timer events.
Some applications will use a custom event loop routine, but
.Fn AG_EventLoop
happens to be suitable for most applications where it is necessary to strike
a good balance between accuracy of real-time events and CPU efficiency.
.Pp
For a graphical application using Agar-GUI,
.Fn AG_EventLoop
tries to update the display and process events in the most efficient way for
the underlying graphics system.
Usually, this involves computing delays which will allow a stable refresh
rate to be maintained (see
.Xr AG_SetRefreshRate 3 ) ,
input events to be serviced quickly and timed events (see
.Xr AG_Timeout 3
and
.Fn AG_SchedEvent )
to be executed at accurate points in time.
.Sh EVENT PROCESSING
.nr nS 1
.Ft "AG_Event *"
.Fn AG_SetEvent "AG_Object *obj" "const char *event_name" "void (*handler)(AG_Event *event)" "const char *fmt" "..."
.Pp
.Ft "AG_Event *"
.Fn AG_AddEvent "AG_Object *obj" "const char *event_name" "void (*handler)(AG_Event *event)" "const char *fmt" "..."
.Pp
.Ft "AG_Event *"
.Fn AG_FindEventHandler "AG_Object *obj" "const char *name"
.Pp
.Ft "void"
.Fn AG_UnsetEvent "AG_Object *obj" "const char *event_name"
.Pp
.Ft "int"
.Fn AG_PostEvent "AG_Object *sndr" "AG_Object *rcvr" "const char *event_name" "const char *fmt" "..."
.Pp
.Ft "int"
.Fn AG_SchedEvent "AG_Object *sndr" "AG_Object *rcvr" "Uint32 ticks" "const char *event_name" "const char *fmt" "..."
.Pp
.Ft "int"
.Fn AG_ReschedEvent "AG_Object *obj" "const char *event_name" "Uint32 ticks"
.Pp
.Ft "int"
.Fn AG_CancelEvent "AG_Object *obj" "const char *event_name"
.Pp
.Ft "void"
.Fn AG_ForwardEvent "AG_Object *sndr" "AG_Object *rcvr" "AG_Event *event"
.Pp
.nr nS 0
The
.Fn AG_SetEvent
function registers a new event handler to service events of type
.Fa name .
If an event handler is already registered for the given event type, it
is replaced.
The
.Fn AG_AddEvent
variant preserves any existing event handler, such that multiple handlers
can be invoked when the event is raised.
.Pp
If
.Fa name
is NULL, the event handler is not assigned a type, but may be referenced
by the pointer returned by
.Fa AG_SetEvent .
The
.Fa handler
argument specifies the event handler function.
.Pp
.Fa fmt
is a special format string indicating the types of the following arguments.
It is possible for the event handler routine to retrieve arguments by index.
For example, the
.Sq %s,%p,%i
format string specifies that the following arguments are a string, a pointer
and an
.Ft int .
They can be then retrieved by the event handler routine using:
.Bd -literal -offset indent
char *s = AG_STRING(1);
void *p = AG_PTR(2);
int i = AG_INT(3);
.Ed
.Pp
It is also possible to use a format string of the form
.Sq foo=%s,bar=%p,baz=%i ,
in which case the event handler could then use:
.Bd -literal -offset indent
char *s = AG_NAMED_STRING("foo");
void *p = AG_NAMED_PTR("bar");
int i = AG_NAMED_INT("baz");
.Ed
.Pp
See
.Dq EVENT ARGUMENTS
for more details.
.Pp
The
.Fn AG_FindEventHandler
function returns the
.Nm
structure for the specified event, or NULL if there are no handlers associated
with it.
.Pp
The
.Fn AG_UnsetEvent
function removes the named event handler from the list.
Any future execution of this event handler as scheduled by
.Fn 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.
.Pp
The
.Fn AG_PostEvent
function immediately executes the event handler function associated with the given
event type, if there is any.
.Fa fmt
is a format string and the arguments following it are inserted into the argument
vector passed to the event handler (following the arguments registered by
.Fn AG_SetEvent ) .
.Fn AG_PostEvent
returns 1 if an event handler was invoked, or 0 if there is no registered
event handler for the given event type.
.Pp
The
.Fn AG_SchedEvent
function is similar to
.Fn 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.
.Fn AG_SchedEvent
returns 0 on success or -1 if no matching event handler was found.
.Pp
The
.Fn 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.
.Fn AG_ReschedEvent
returns 0 on success or -1 if there was no matching event handler.
.Pp
.Fn 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.
.Pp
The
.Fn AG_ForwardEvent
function relays the given event to object
.Fa rcvr ,
passing
.Fa sndr
as the sender pointer.
.Sh EVENT ARGUMENTS
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
.Fa event
structure (see
.Dq STRUCTURE DATA ) .
.Pp
.nr nS 1
.Ft "AG_Object *"
.Fn AG_SELF "void"
.Pp
.Ft "AG_Object *"
.Fn AG_SENDER "void"
.Pp
.Ft "void *"
.Fn AG_PTR "int index"
.Pp
.Ft "AG_Object *"
.Fn AG_OBJECT "int index" "const char *classSpec"
.Pp
.Ft "char *"
.Fn AG_STRING "int index"
.Pp
.Ft "char"
.Fn AG_CHAR "int index"
.Pp
.Ft "Uchar"
.Fn AG_UCHAR "int index"
.Pp
.Ft "int"
.Fn AG_INT "int index"
.Pp
.Ft "Uint"
.Fn AG_UINT "int index"
.Pp
.Ft "long"
.Fn AG_LONG "int index"
.Pp
.Ft "Ulong"
.Fn AG_ULONG "int index"
.Pp
.Ft "float"
.Fn AG_FLOAT "int index"
.Pp
.Ft "double"
.Fn AG_DOUBLE "int index"
.Pp
.Ft "Uint8"
.Fn AG_UINT8 "int index"
.Pp
.Ft "Sint8"
.Fn AG_SINT8 "int index"
.Pp
.Ft "Uint16"
.Fn AG_UINT16 "int index"
.Pp
.Ft "Sint16"
.Fn AG_SINT16 "int index"
.Pp
.Ft "Uint32"
.Fn AG_UINT32 "int index"
.Pp
.Ft "Sint32"
.Fn AG_SINT32 "int index"
.Pp
.nr nS 0
The
.Fn AG_SELF
macro (equivalent to AG_PTR(0)) returns a pointer to the
.Xr AG_Object 3
receiving the event (the
.Fa rcvr
argument to
.Fn AG_PostEvent ) .
.Fn AG_SENDER
returns a pointer to the object sending the event (the
.Fa sndr
argument to
.Fn AG_PostEvent ) ,
if there is one.
.Pp
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
.Fn AG_PostEvent
.Em follow
the list of arguments provided by
.Fn AG_SetEvent .
If debugging was enabled at compile time, these macros also ensure type
safety.
.Pp
.Fn AG_PTR
returns a pointer, previously passed as a
.Sq %p
argument.
.Pp
.Fn AG_OBJECT
returns a pointer to an
.Xr AG_Object 3
previously passed as a
.Sq %[obj]
argument.
If type checking is enabled, a fatal error is raised if the object's class
specification does not match
.Fa classSpec .
.Pp
.Fn AG_STRING
returns a pointer to a string, previously passed as a
.Sq %s
argument.
The event handler is not allowed to modify the string.
.Pp
.Fn AG_CHAR ,
.Fn AG_UCHAR ,
.Fn AG_INT ,
.Fn AG_UINT ,
.Fn AG_LONG
and
.Fn AG_ULONG
return the specified native integral number, previously passed as a
.Sq %c ,
.Sq %C ,
.Sq %i ,
.Sq %u
or
.Sq %l
argument respectively.
.Pp
.Fn AG_FLOAT
and
.Fn AG_DOUBLE
return the specified native floating-point number, previously passed as
.Sq %f
or
.Sq %F
argument respectively.
.Pp
.Fn AG_UINT8 ,
.Fn AG_SINT8 ,
.Fn AG_UINT16 ,
.Fn AG_SINT16 ,
.Fn AG_UINT32
and
.Fn AG_SINT32
return the specified fixed-size integral number, previously passed as
.Sq %[u8] ,
.Sq %[s8] ,
.Sq %[u16] ,
.Sq %[s16] ,
.Sq %[u32]
or
.Sq %[s32]
argument respectively.
.Sh ARGUMENT MANIPULATION
In some cases it is desirable for functions to accept a list of event handler
arguments like
.Fn AG_SetEvent ,
and possibly manipulate its entries directly.
For example, the
.Xr AG_MenuAction 3
function of the GUI widget
.Xr AG_Menu 3
accepts a pointer to an event handler function, followed by an
.Fn AG_SetEvent
style format string and a variable list of arguments.
The following functions allow such manipulations.
.Pp
.nr nS 1
.Ft void
.Fn AG_EventInit "AG_Event *ev"
.Pp
.Ft void
.Fn AG_EventArgs "AG_Event *ev" "const char *fmt" "..."
.Pp
.Ft void
.Fn AG_EventPushPointer "AG_Event *ev" "const char *key" "void *val"
.Pp
.Ft void
.Fn AG_EventPushString "AG_Event *ev" "const char *key" "char *val"
.Pp
.Ft void
.Fn AG_EventPushChar "AG_Event *ev" "const char *key" "char val"
.Pp
.Ft void
.Fn AG_EventPushUChar "AG_Event *ev" "const char *key" "Uchar val"
.Pp
.Ft void
.Fn AG_EventPushInt "AG_Event *ev" "const char *key" "int val"
.Pp
.Ft void
.Fn AG_EventPushUint "AG_Event *ev" "const char *key" "Uint val"
.Pp
.Ft void
.Fn AG_EventPushLong "AG_Event *ev" "const char *key" "long val"
.Pp
.Ft void
.Fn AG_EventPushULong "AG_Event *ev" "const char *key" "Ulong val"
.Pp
.Ft void
.Fn AG_EventPushFloat "AG_Event *ev" "const char *key" "float val"
.Pp
.Ft void
.Fn AG_EventPushDouble "AG_Event *ev" "const char *key" "douvle val"
.Pp
.Ft void
.Fn AG_EVENT_PUSH_ARG "va_list ap, char formatChar, AG_Event *ev"
.Pp
.Ft void
.Fn AG_EventPopArgument "AG_Event *ev"
.Pp
.nr nS 0
The
.Fn AG_EventInit
routine initializes an
.Ft AG_Event
structure with no arguments.
.Pp
.Fn AG_EventArgs
initializes
.Fa ev
and also specifies a list of arguments (in the same format as
.Fn AG_SetEvent ) .
.Pp
The
.Fn AG_EventPush
functions append an argument to the end of the argument list for the specified
.Nm
structure.
.Pp
The
.Fn AG_EVENT_PUSH_ARG
macro also insert an argument, except that the type is obtained from
.Fa formatChar ,
assumed to be a character from an
.Fn AG_SetEvent
style format string, and the argument is retrieved using
.Xr va_arg 3 .
.Pp
.Fn AG_EventPopArgument
removes the last argument from the list.
.Sh STRUCTURE DATA
For the
.Ft AG_Event
structure:
.Pp
.Bl -tag -compact -width "AG_Variable *argv "
.It Ft char * name
String identifier for the event.
.It Ft Uint flags
See
.Dq EVENT FLAGS
section below.
.It Ft int argc
Argument count.
.It Ft AG_Variable *argv
Argument data (see
.Xr AG_Variable 3 ) .
.El
.Sh EVENT FLAGS
Acceptable
.Va flags
for the
.Nm
structure include:
.Pp
.Bl -tag -width "AG_EVENT_PROPAGATE "
.It 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
.Dv AG_THREADS
option.
.It AG_EVENT_PROPAGATE
Whenever this event is raised, automatically raise the same event for any
child object attached to the given object.
Unless
.Dv AG_EVENT_ASYNC
is used, it is safe to assume that the child object's handler is executed before
the parent's.
.It AG_EVENT_SCHEDULED
Event was previously scheduled for execution by
.Fn AG_SchedEvent
(read-only).
.El
.Sh EXAMPLES
The following code fragment demonstrates a typical
.Nm
usage in the Agar-GUI library.
We bind an action to the button press event, which is called
.Sq button-pushed .
This event is documented in the
.Xr 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
.Ft int ) .
.Bd -literal -offset indent
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");
.Ed
.Pp
The
.Ft AG_Button
API also provides an alternate constructor routine,
.Fn AG_ButtonNewFn ,
with which you can specify the default
.Sq button-pushed
event handler:
.Bd -literal -offset indent
AG_ButtonNewFn(NULL, 0, "Say hello", SayHello, "%s", "World");
.Ed
.Pp
The following code fragment does the same, specifying the arguments in
a more explicit way:
.Bd -literal -offset indent
AG_Button *btn = AG_ButtonNew(NULL, 0, "Say hello");
AG_Event *event = AG_SetEvent(btn, "button-pushed", SayHello, NULL);
AG_EventPushString(event, NULL, "World");
.Ed
.Pp
The following code fragment invokes an event handler routine directly,
independently of the object system:
.Bd -literal -offset indent
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);
.Ed
.Sh SEE ALSO
.Xr AG_Intro 3 ,
.Xr AG_Object 3 ,
.Xr AG_Timeout 3 ,
.Xr AG_Variable 3
.Sh HISTORY
The
.Nm
mechanism first appeared in Agar 1.0.
The
.Xr AG_Variable 3
structure was first used to represent event handler arguments in Agar 1.3.4.