Events
******

As indicated above, the main module of the Forms Library communicates with the objects by calling the associated handling routine with, as one of the arguments, the particular event for which action must be taken. In the following we assume that obj is the object to which the event is sent.

The following types of events can be sent to an object:

FL_DRAW
     The object has to be (re)drawn. To figure out the actual size of the object you can use the fields obj->x, obj->y, obj->w and obj->h. Many Xlib drawing routines require a window ID, which you can obtain from the object pointer using FL_ObjWin(obj). Some other aspects might also influence the way the object has to be drawn. E.g., you might want to draw the object differently when the mouse is on top of it or when the mouse is pressed on it. This can be figured out the following way: The field obj->belowmouse tells you whether the object is below the mouse. The field obj->pushed indicates whether the object is currently being pushed with the mouse. Finally, obj->focus indicate whether input focus is directed towards this object. Note that drawing of the object is the full responsibility of the object class, including the bounding box and the label, which can be found in the field obj->label. The Forms Library provides a large number of routines to help you draw object. See Drawing Objects, for more details on drawing objects and an overview of all available routines.

     One important caution about your draw event handling code: none of the high level routines (fl_freeze_form(), fl_deactivate_form()) etc. can be used. The only routines allowed to be used are (direct) drawing functions and object internal book keeping routines. Attribute modifying routines, such as fl_set_object_color() etc. are not allowed (using them can lead to infinite recursions). In addition, (re)drawing of other objects using fl_redraw_object() while handling FL_DRAW will also not work.

     Due to the way double buffering is handled, at the time the FL_DRAW event is passed to the handling function (and only then) FL_ObjWin(obj) might return a pixmap used as the backbuffer (at least if the object is double buffered). What that means is that FL_ObjWin(obj) should not be used when a real window is needed. For a real window you can change the window's cursor or query the mouse position within it. You can't do either of these with the backbuffer pixmap. If there is a need to obtain the real window ID the following routine can be used:

          Window fl_get_real_object_window(FL_OBJECT *)

     To summarize: use FL_ObjWin(obj) when drawing and use fl_get_real_object_window() for cursor or pointer routines. This distinction is important only while handling FL_DRAW events, FL_ObjWin(obj) should be used anywhere else.

FL_DRAWLABEL
     This event typically follows FL_DRAW and indicates that the object label needs to be (re)drawn. If the object in question always draws its label inside the bounding box and this is taken care of by handing FL_DRAW, you can ignore this event.

FL_ENTER
     This event is sent when the mouse has entered the bounding box and might require some action. Note also that the field obj->belowmouse in the object is being set. If entering an objects area only changes its appearance, redrawing it normally suffices. Don't do this directly! Always redraw the object by calling fl_redraw_object(). It will send an FL_DRAW event to the object but also does some other things (like setting window IDs and taking care of double buffering etc.).

FL_LEAVE
     The mouse has left the bounding box. Again, normally a redraw is enough (or nothing at all).

FL_MOTION
     Motion events get sent between FL_ENTER and FL_LEAVE events when the mouse position changes on the object. The mouse position is given as an argument to the handle routine.

FL_PUSH
     The user has pushed a mouse button on the object. Normally this requires some actual action. The number of the mouse button pushed is given in the key parameter, having one of the following values:

     FL_LEFT_MOUSE, FL_MBUTTON1
          Left mouse button was pressed.

     FL_MIDDLE_MOUSE, FL_MBUTTON2
          Middle mouse button was pressed.

     FL_RIGHT_MOUSE, FL_MBUTTON3
          Right mouse button was pressed.

     FL_SCROLLUP_MOUSE, FL_MBUTTON4
          Mouse scroll wheel was rotated in up direction.

     FL_SCROLLDOWN_MOUSE, FL_MBUTTON5
          Mouse scroll wheel was rotated in down direction.

FL_RELEASE
     The user has released the mouse button. This event is only sent if a FL_PUSH event was sent before. FL_PUSH event.

FL_DBLCLICK
     The user has pushed a mouse button twice within a certain time limit (FL_CLICK_TIMEOUT), which by default is 400 msec. This event is sent after two FL_PUSH, FL_RELEASE sequence. Note that FL_DBLCLICK is only generated for objects that have non-zero obj->click timeout fields and it will not be generated for events from the scroll wheel.

FL_TRPLCLICK
     The user has pushed a mouse button three times within a certain time window. This event is sent after a FL_DBLCLICK, FL_PUSH, FL_RELEASE sequence. Set click timeout to none-zero to activate FL_TRPLCLICK.

FL_FOCUS
     Input got focussed to this object. This type of event and the next two are only sent to objects for which the field obj->input is set to 1 (see below).

FL_UNFOCUS
     Input is no longer focussed on the object.

FL_KEYPRESS
     A key was pressed. The ASCII value (or KeySym if non-ASCII) is passed to the routine via the key argument, modifier keys can be retrieved from the state member of the XEvent also passed to the function via xev.

     This event only happens between FL_FOCUS and FL_UNFOCUS events. Not all objects are sent keyboard events, only those that have non-zero value in field obj->input or obj->wantkey.

FL_SHORTCUT
     The user used a keyboard shortcut. The shortcut used is given in the parameter key. See below for more on shortcuts.

FL_STEP
     A FL_STEP event is sent all the time (typically about 20 times a second but possibly less often because of system delays and other time-consuming tasks) to objects for which the field obj->automatic has been set to a non-zero value. The handling routine receives a synthetic MotionNotify event as the XEvent. This can be used to make an object change appearance without user action. Clock and timer objects use this type of event.

FL_UPDATE
     An FL_UPDATE event, like the FL_STEP event, also gets send about every 50 msec (but less often under high load) to objects while they are "pushed", i.e., between receiving a FL_PUSH and a FL_RELEASE event if their obj->want_update field is set. Like for the FL_STEP event the handling routine receives a synthetic MotionNotify event as the XEvent. This is typically used by objects that have to perform tasks at regular time intervals while they are "pushed" (e.g., counters that need to count up or down while the mouse is pushed on one of its buttons).

FL_ATTRIB
     An FL_ATTRIB event is sent to an object (via calling the handler function each object type must define for this purpose) whenever one of it's properties changes, be it its size, position, box type, border width, colors, label, label color, style or alignment etc. This can e.g., be used by the object to do preparations for later drawing of it or check that what got set is reasonable. It should not use this event to actually draw anything (this is to be done only when an FL_DRAW event is received). When the handler function for events is called all the arguments it gets passed are 0.

FL_FREEMEM
     This event is sent when the object is to be freed. All memory allocated for the object internally must be freed when this event is received.

FL_OTHER
     Events other than the above. These events currently include ClientMessage, Selection and possibly other window manager events. All information about the event is contained in xev parameter and mx and my may or may not reflect the actual position of the mouse.

Many of these events might make it necessary that the object has to be redrawn or partially redrawn. Always do this using the routine fl_redraw_object().

Shortcuts
=========

The Forms Library has a mechanism of dealing with keyboard shortcuts. In this way the user can use the keyboard rather than the mouse for particular actions. Obviously, only "active" objects can have shortcuts (i.e., not objects like boxes, texts etc.).

The mechanism works as follows. There is a routine

     void fl_set_object_shortcut(FL_OBJECT *obj, const char *str,
                                 int showit);

with which one can bind a series of keys to an object. E.g., when str is "acE#d^h" the keys 'a', 'c', 'E', <Alt>d and <Ctrl>h are associated with the object. The precise format is as follows: Any character in the string is considered as a shortcut, except '^' and '#', which stand for combinations with the <Ctrl> and <Alt> keys. (The case of the key following '#' or '^' is not important, i.e., no distiction is made between e.g., "^C" and "^c", both encode the key combination <Crl>C as well as <Crtl>C.) The key '^' itself can be set as a shortcut key by using "^^" in the string defining the shortcut. The key '#' can be obtained as a shortcut by using th string "^#". So, e.g., "#^#" encodes <ALT>#. The <Esc> key can be given as "^[".

Another special character not mentioned yet is '&', which indicates function and arrow keys. Use a sequence starting with '&' and directly followed by a number between 1 and 35 to represent one of the function keys. For example, "&2" stands for the <F2> function key. The four cursors keys (up, down, right, and left) can be given as "&A", "&B", "&C" and "&D", respectively. The key '&' itself can be obtained as a shortcut by prefixing it with '^'.

The argument showit tells whether the shortcut letter in the object label should be underlined if a match exists. Although the entire object label is searched for matches, only the first alphanumerical character in the shortcut string is used. E.g., for the object label "foobar" the shortcut "oO" would result in a match at the first o in "foobar" while "Oo" would not. However, "^O" and "#O" would match since for keys used in combination with <Crtl> and <Alt> no distiction is made between upper and lower case.

To use other special keys not described above as shortcuts, the following routine must be used

     void fl_set_object_shortcutkey(FL_OBJECT *obj, unsigned int key);

where key is an X KeySym, for example XK_Home, XK_F1 etc. Note that the function fl_set_object_shortcutkey() always appends the key specified to the current shortcuts while fl_set_object_shortcut() resets the shortcuts. Of course, special keys can't be underlined.

Now, whenever the user presses one of these keys, an FL_SHORTCUT event is sent to the object. The key pressed is passed to the handle routine (in the argument key). Combinations with the <Alt> key are given by adding FL_ALT_MASK (currently the 25th bit, i.e., 0x1000000) to the ASCII value of the key. E.g., the key combinations <Alt>E and <Alt>e are passed as FL_ALT_MASK + 'E'. The object can now take action accordingly. If you use shortcuts to manipulate class object specific things, you will need to create a routine to communicate with the user, e.g., fl_set_NEW_shortcut(), and do your own internal bookkeeping to track what keys do what and then call fl_set_object_shortcut() to register the shortcut in the event dispatching module. The idea is NOT that the user himself calls fl_set_object_shortcut() but that the class provides a routine for this that also keeps track of the required internal bookkeeping. Of course, if there is no internal bookkeeping, a macro to this effect will suffice. For example fl_set_button_shortcut() is defined as fl_set_object_shortcut().

The order in which keys are handled is as follows: First for a key it is tested whether any object in the form has the key as a shortcut. If yes, the first of those objects gets the shortcut event. Otherwise, the key is checked to see if it is <Tab> or <Return>. If it is, the obj->wantkey field is checked. If the field does not contain FL_KEY_TAB bit, input is focussed on the next input field. Otherwise the key is sent to the current input field. This means that input objects only get a <Tab> or <Return> key sent to them if in the obj->wantkey field the FL_KEY_TAB bit is set. This is e.g., used in multi-line input fields. If the object wants all cursor keys (including <PgUp> etc.), the obj->wantkey field must have the FL_KEY_SPECIAL bit set.

To summarize, the obj->wantkey field can take on the following values (or the bit-wise or of them):

FL_KEY_NORMAL
     The default. The object receives left and right cursor, <Home> and <End> keys plus all normal keys (0-255) except <Tab> <Return>.

FL_KEY_TAB
     Object receives the <Tab>, <Return> as well as the <Up> and <Down> cursor keys.

FL_KEY_SPECIAL
     The object receives all keys with a KeySym above 255 which aren't already covered by FL_KEY_NORMAL and FL_KEY_TAB (e.g., function keys etc.)

FL_KEY_ALL
     Object receives all keys.

This way it is possible for a non-input object (i.e., if obj->input is zero) to obtain special keyboard event by setting obj->wantkey to FL_KEY_SPECIAL.