.\" 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.