Next: Using Callback Functions, Previous: Periodic Events and Non-blocking Interaction, Up: Part I Doing Interaction [Contents][Index]
It is not atypical that an application program may need to take interaction from more than one form at the same time, Forms Library provides a mechanism with which precise control can be exercised.
By default, fl_do_forms()
takes
interaction from all forms that are shown. In certain situations, you
might not want to have interaction with all of them. For example, when
the user presses a quit button in a form you might want to ask a
confirmation using another form. You don’t want to hide the main form
because of that but you also don’t want the user to be able to press
buttons, etc. in this form. The user first has to give the confirmation.
So you want to temporarily deactivate the main form. This can be done
using the call
void fl_deactivate_form(FL_FORM *form);
To reactivate the form later again use
void fl_activate_form(FL_FORM *form);
It is a good idea to give the user a visual clue that a form is
deactivated. This is not automatically done mainly for performance
reasons. Experience shows that graying out some important objects on
the form is in general adequate. Graying out an object can be
accomplished by using fl_set_object_lcolor()
(see
objinactive.c. What objects to gray out is obviously
application dependent.
The following two functions can be used to register two callbacks that are called whenever the activation status of a form is changed:
typedef void (*FL_FORM_ATACTIVATE)(FL_FORM *, void *); FL_FORM_ATACTIVATE fl_set_form_atactivate(FL_FORM *form, FL_FORM_ATACTIVATE callback, void *data); typedef void (*FL_FORM_ATDEACTIVATE)(FL_FORM *, void *); FL_FORM_ATDEACTIVATE fl_set_form_atdeactivate(FL_FORM *form, FL_FORM_ATDEACTIVATE callback, void *data);
It is also possible to deactivate all current forms and reactivate them again. To this end use the functions:
void fl_deactivate_all_forms(void); void fl_activate_all_forms(void);
Note that deactivation works in an additive way, i.e., when deactivating a form say 3 times it also has to be activated 3 times to become active again.
One problem remains. Mouse actions etc. are presented to a program in
the form of events in an event queue. The library routines
fl_do_forms()
and fl_check_forms()
read this
queue and handle the events. When the application program itself also
opens windows, these windows will rather likely receive events as
well. Unfortunately, there is only one event queue. When both the
application program and the library routines would read events from
this one queue problems would occur and events missed. Hence, the
application program should not read the event queue itself.. To solve
this problem, the library maintains (or appears to maintain) a
separate event queue for the user. This queue behaves in exactly the
same way as the normal event queue. To access it, the application
program must use replacements for the usual Xlib routines. Instead of
using XNextEvent()
, the program will use
fl_XNextEvent()
, with the same parameters except the
Display *
argument. The following is a list of all replacement
routines:
int fl_XNextEvent(XEvent *xev); int fl_XPeekEvent(XEvent *xev); int fl_XEventsQueued(int mode); int fl_XPutbackEvent(XEvent *xev);
Note that these routines normally return 1
, but after a call of
fl_finish()
they return 1
instead.
Other events routines may be directly used if proper care is taken to
make sure that only events for the application windows not handled by
the library are removed. These routines include XWindowEvent()
,
XCheckWindowEvent()
etc.
To help find out when an event has occurred, whenever
fl_do_forms()
and fl_check_forms()
encounter
an event that is not meant for handling by the library but by the
application program itself they return a special object
FL_EVENT
. Upon receiving this special event, the
application program can and must remove the pending event from the
queue using fl_XNextEvent()
.
So the basis of a program with its own windows would look as follows:
/* define the forms */ /* display the forms */ /* open your own window(s) */ while (! ready) { obj = fl_do_forms(); /* or fl_check_forms() */ if (obj == FL_EVENT) { fl_XNextEvent(&xevent); switch (xevent.type) { /* handle the event */ } } else if (obj != NULL) /* handle the change in obj */ /* update other things */ } }
In some situations you may not want to receive these "user" events.
For example, you might want to write a function that pops up a form to
change some settings. This routine might not want to be concerned with
any redrawing of the main window, etc., but you also not want to
discard any events. In this case you can use the routines
fl_do_only_forms()
and fl_check_only_forms()
that will never return FL_EVENT
. The events don’t
disappear but will be returned at later calls to the normal routines
fl_do_forms()
etc.
It can’t be over-emphasized that it is an error to ignore
FL_EVENT
or use fl_XNextEvent()
without seeing
FL_EVENT
.
Sometimes an application program might need to find out more information about the event that triggered a callback, e.g., to implement mouse button number sensitive functionalities. To this end, the following routines may be called
long fl_mouse_button(void);
This function, if needed, should be called from within a callback. The
function returns one of the constants FL_LEFT_MOUSE
,
FL_MIDDLE_MOUSE
, FL_RIGHT_MOUSE
,
FL_SCROLLUP_MOUSE
or FL_SCROLLDOWN_MOUSE
,
indicating which mouse button was pushed or released. If the callback
is triggered by a shortcut, the function returns the keysym (ascii
value if ASCII) of the key plus
FL_SHORTCUT
. For example, if a button has a shortcut
<Ctrl>C
(ASCII value is 3), the button number returned upon
activation of the shortcut would be FL_SHORTCUT + 3
.
FL_SHORTCUT
can be used to determine if the callback is
triggered by a shortcut or not
if (fl_mouse_button() >= FL_SHORTCUT) /* handle shortcut */ else switch (fl_mouse_button()) { case FL_LEFTMOUSE: .... }
More information can be obtained by using the following routine that
returns the last XEvent
const XEvent *fl_last_event(void);
Note that if this routine is used outside of a callback function, the
value returned may not be the real "last event" if the program was
idling and, in this case, it returns a synthetic MotionNotify
event.
Some of the utilities used internally by the Forms Library can be used by the application programs, such as window geometry queries etc. Following is a partial list of the available routines:
void fl_get_winorigin(Window win, FL_Coord *x, FL_Coord *y); void fl_get_winsize(Window win, FL_Coord *w, FL_Coord *h); void fl_get_wingeometry(Window win, FL_Coord *x, FL_Coord *y, FL_Coord *w, FL_Coord *h);
All positions are relative to the root window.
There are also routines that can be used to obtain the current mouse position relative to the root window:
Window fl_get_mouse(FL_Coord *x, FL_Coord *y, unsigned int *keymask);
where keymask
is the same as used in XQueryPointer(3X11)
.
The function returns the window ID the mouse is in.
To obtain the mouse position relative to an arbitrary window, the following routine may be used
Window fl_get_win_mouse(Window win, FL_Coord *x, FL_Coord *y, unsigned int *keymask);
To print the name of an XEvent, the following routine can be used:
XEvent *fl_print_xevent_name(const char *where, const XEvent *xev);
The function takes an XEvent, prints out its name and some other info,
e.g., expose, count=n
. Parameter where
can be used to
indicate where this function is called:
fl_print_xevent_name("In tricky.c", &xevent);
Next: Using Callback Functions, Previous: Periodic Events and Non-blocking Interaction, Up: Part I Doing Interaction [Contents][Index]