In this appendix we give a brief overview of all main routines that are available. For an overview of all routines related to specific object classes see Part iii.
The header file, forms.h, defines three symbolic constants which
you can use to conditionally compile your application. The three
symbolic constants are
| FL_VERSION |
|---|
| FL_REVISION |
| FL_INCLUDE_VERSIONFL_VERSIONxFL_REVISION |
There is also a routine that can be used to obtain the library version at run time:
int fl_library_version(int *version, int *revision)
The function returns a consolidated version information, computed as version x 1000 + revision. For example, for library version 1 revision 21 (1.21), the function returns a value of 1021 with version and revision (if not null) set to 1 and 21 respectively.
It is always a good idea to check if the header and the run time library are of the same version and take appropriate actions when they are not. This is especially important for version < 1.
To obtain the version number of the library used in an executable, run the command with -flversion option, which will print the complete version information.
The routine
Display *fl_initialize(int *argc, char *argv[], const char *appclass,
XrmOptionDescList app_opt, int n_app_opt)
initializes the Forms Library. It should always be called before
any other calls to the Forms Library are made (except fl_set_defaults()
and a few other functions that alter some of the defaults of the
library). The meaning of the arguments are as follows
argv[0] by stripping leading path names
and trailing period and extension, if any. Due to the way the X resources
(and command line argument parsing) work, the executable name should not contain .
or *.
The fl_initialize function builds the resource database,
calls Xlib XrmParseCommand(3X11) function to parse the command line,
and performs other per display initialization.
All recognized options are removed from the argument list and their corresponding values set. Forms Library provides appropriate defaults for all options. The following are the defaults:
| Options | Value Type | Meaning | Default |
|---|---|---|---|
| -debug level | int | prints debug information. | 0 |
| -name appname | string | changes application name | none |
| -sync | none | requests synchronous mode (debug) | false |
| -display host:dpy | string | specifies remote host | $DISPLAY |
| -visual class | string | TrueColor, PseudoColor... | best |
| -depth depth | int | specifies prefered visual depth. | best |
| -vid id | long | specifies preferred visual ID | |
| -private | none | forces private colormap. | false |
| -shared | none | forces shared colormap. | false |
| -stdcmap | none | forces standard colormap. | false |
| -double | none | enables double buffering | false |
| -bw width | int | changes border width | 3 |
| -rgamma gamma | float | specifies red gamma | 1.0 |
| -ggamma gamma | float | specifies green gamma | 1.0 |
| -bgamma gamma | float | specifies blue gamma | 1.0 |
``best" in the above table means the visual that
has the most colors, which may or may not be the server default. There
is a special command option -visual Default that sets both
the visual and depth to the X server default. If a visual ID is
requested, it overrides depth or visual if specified. Visual Id
can also be requested programmatically (before fl_initialize)
via the following function
void fl_set_visualID(long id)
If border width is set to a negative number, all objects appear
to be softer and some people might prefer
bw -2. .
Depending on your application, XForms defaults may or may not be appropriate. E.g., on machines capable of 24bits visuals, Forms Library always selects the deeper 24bits visual. If your application only uses a limited number of colors, it would typically be faster if a visual other than 24bits is selected.
There are a couple of ways to override the default
settings.
You can provide an application specific resource database distributed
with your program. The easiest way, however, is to set up your
own program default programmatically without affecting the users'
ability to override with command line options. For this, you can use
the following routine before
fl_initialize() :
void fl_set_defaults(unsigned long mask, FL_IOPT *flopt)
In addition to setting a preferred visual, this function can also be used to set other program defaults, such as label font size, unit of measure for form sizes etc.
See Table A.1
for a list of the masks and the members of
FL_IOPT.
A special visual designation, FL_DefaultVisual and command line
option equivalent -visual Default are provided to set
the program default to the server's default visual class and
depth.
If you set up your resource specifications to use class names instead of instance names, users can then list instance resources under arbitrary name that is specified with the -name option.
Coordinate units
can be in pixels,
points (1/72 inch), mm (milli-meters), cp (centi-point, i.e., 1/100 of
a point) or cmm (centi-millimeter). The pre-defined
designations (enums) for coordUnit are
FL_COORD_PIXEL,
FL_COORD_POINT,
FL_COORD_MM,
FL_COORD_centiPOINT, and
FL_COORD_centiMM.
coordUnit can be changed anytime, but typically you would
do this prior to creating a form, presumably to make the size of
the form screen resolution independent. The basic steps in doing
this may look something like the following:
int oldcoordUnit = fl_get_coordunit();
fl_set_coordunit(FL_COORD_POINT);
fl_bgn_form(...);
/* add more objects */
fl_end_form();
fl_set_coordunit(oldcoordunit);
As you can see, convenience functions fl_set_coordunit()
and fl_get_coordunit() are provided to change the
unit of measure.
Structure Mask Name Meaning
typedef struct {
int debug; FL_PDDebug Debug level (0-5)
int depth; FL_PDDepth Preferred visual depth
int vclass; FL_PDVisual Preferred visual. TrueColor etc
int doubleBuffer FL_PDDouble Simulate double buffering
int buttonFontSize FL_PDButtonFontSize Default Button label fontsize
int menuFontSize FL_PDMenuFontSize Menu label fontsize
int choiceFontSize FL_PDChoiceFontSize Choice label and choice text fontsize
int browserFontSize FL_PDBrowserFontSize Browser label and text fontsize
int inputFontSize FL_PDInputFontSize Input label and text fontsize
int labelFontSize FL_PDLabelFontSize label fontsize for all other objects (box, pixmap etc.)
int pupFontSize FL_PDPupFontSize Fontsize for pop-ups
int privateColormap FL_PDPrivateMap Select private colormap if appropriate
int sharedColormap FL_PDSharedMap Force shared colormap always
int standardColormap FL_PDStandardMap Force standard colormap
int leftScrollBar FL_PDLeftScrollBar Placement of scrollbar in browser
int ulThickness FL_PDULThickness Underline thickness
int ulPropWidth FL_PDULPropWidth Underline width. 0 for const. width
int coordUnit FL_PDCoordUnit Unit of measure: pixel, mm, point
int borderWidth FL_PDBorderWidth Height of an object
} FL_IOPT;
Table A.1: FL_IOPT structure
Some of the defaults are ``magic" in that their exact values depend
on the context or platform. For example, the underline thickness
by default is 1 for normal font and 2 for bold font.
There exists a convenience function to set the application default border
width
void fl_set_border_width(int border_width)
which is equivalent to
FL_IOPT fl_cntl;
fl_cntl.borderWidth = border_width;
fl_set_defaults(FL_PDBorderWidth, &fl_cntl);
Typically this function, if used, should appear before
fl_initialize() so the user has the option to override
the default via command line options.
Prior to version V0.80, the origin of XForms's coordinate system was
at the lower-left corner of the form. The new Form Designer will convert
the form definition file to the new coordinate system, i.e.,
origin at the upper-left, so no manual intervention is required. To
help those who lost the .fd files or otherwise can't use the new fdesign,
a compatibility function is provided
void fl_flip_yorigin(void)
Note however, this function must be called prior to fl_initialize
and is a no-op after that.
For proportional font, substituting tabs with spaces is not
always appropriate because this most likely will fail to align text
properly. Instead, a tab is treated as an absolute measure
of distance, in pixels, and a tab stop will always end
at multiples of this distance. Application program can
adjust this distance by setting the tab stops using the
following routine
void fl_set_tabstop(const char *s)
where s is a string whose width in pixels is to be used as
the tab length. The font used to calculate the width is the same
font that is used to render the string in which the tab is embedded. The
default is s = "aaaaaaaa", i.e., eight \verb'a'+s;
Before we proceed further, some comments about double buffering are in order.
Since Xlib does not support double buffering, Forms Library simulates this
functionality with pixmap bit-blting. In practice, the effect is hardly
distinguishable from double buffering and performance is on par with
multi-buffering extensions (It is slower than drawing into a window directly
on most workstations however). Bear in mind that pixmap can be resource
hungry, so use this option with discretion.
In addition to using double buffering throughout an application,
it is also possible to use double buffering on a per-form or per-object
basis by using the following routines:
void fl_set_form_dblbuffer(FL_FORM *form, int yes)
void fl_set_object_dblbuffer(FL_OBJECT *obj, int yes)
Currently double buffering requests for objects having a non-square box
are ignored.
Normally the Forms Library reports errors. This can be avoided using the routine
void fl_show_errors(int show)
show indicates whether to show (1) or not show (0) the errors.
The fonts used in all forms can be changed using the
routine
void fl_set_font_name(int numb,const char *name)
where numb is a number between 0 and (FL_MAXFONTS-1).
See section 3.11.3 for details.
A redraw of all forms is required to actually see the change
for visible forms.
Since the dimension of an object is typically given in pixels,
depending on the server resolution and the font used, this can
lead to unsatisfactory user interfaces. For example, a button
designed to (just) contain a label in a 10pt font on a 75 DPI monitor
will have the label overflow the button on a 100DPI monitor.
This comes about because a character in a 10pt font with
75DPI resolution may have 10 pixels while the same character
in the same 10 pt font with 100DPI resolution may have 14 pixels.
Thus when designing the interfaces, leave a few pixels extra
for the object. Or use a resolution independent unit, such
as point, or centi-point etc.
Using a resolution independent unit
for the object size should solve the font problems theoretically.
In practice, this approach may still prove to be vulnerable.
The reason is the discreteness of both the font
resolution and the monitor/server resolutions. The standard X fonts
only come in two discrete resolutions, 75 DPI and 100 DPI.
Due to the variations in monitor resolutions, the same
theoretically same sized font, say a 10pt font, can vary
in sizes (pixels) up to 30% depending on the server (rendering a font
on a 80DPI monitor will cause error in sizes regardless if 75 or 100DPI
font is used.) This has not even taken into account the fact that a
surprising number of systems have wrong font paths (e.g., a 90DPI monitor
using 75DPI fonts etc).
With the theoretical and practical problems associated
with X fonts, it is not practical for XForms to hard-code default
font resolution and it is not practical to use
the resolution information obtained from the server
either as information obtained from the server
regarding monitor resolution is highly unreliable.
Thus, XForms does not insist on using fonts with specific
resolutions and instead it leaves the freedom to select the default fonts
of appropriate resolutions to the system
administrators.
Given all these uncertainties regarding fonts, as a workaround,
XForms provides a function that can be used to adjust the object size
dynamically according to the actual fonts loaded:
double fl_adjust_form_size(FL_FORM *form, int xm, int vm)
This function works by computing the size (in pixels) of every object
on the form that has an inside label and comparing it to the size
of the object, scaling factors are computed if any object's
label does not fit. The maximum scaling factor found are used
to scale the form so every object label fits inside the object.
It will never shrink a form. The function returns the overall
scaling factor.
In scaling the form, the aspect ratio of the form is kept and all
object gravity specifications are ignored. Since this function
is meant to compensate for font size and server display resolution
variations, scaling is limited to 125% per invocation. The best
place to use this function is right after the creation of
the forms. If the forms are properly designed, on the machine
they are designed, this function should be a no-op. Form Designer has a
special flag -compensate and resource compensate to request
the emission of this function automatically for every form created.
It is likely that this will become the default once
the usefulness of it is established.
There is a similar function that works the same way, but on
an object-by-object basis and further it allows explicit
margin specifications:
void fl_fit_object_label(FL_OBJECT *obj, FL_Coord hm, FL_Coord vm);
where hm and vm are, respectively, the horizontal and vertical
margins to leave on each side of the object. This function works by
computing the object label size and comparing it to the object size.
If the label does not fit inside the object with the given margin,
the entire form the object is on is scaled so the object label
fits. In scaling the form, all gravity specification is ignored
but the aspect ratio of the form (thus of objects) is kept.
This function will not shrink a form. You can use this function
on as many objects as you choose. Of course the object has to
have a label inside the object for this function to work.
In some situations Forms Library may modify some of the server defaults.
All modified defaults are restored as early as possible by the main loop
and in general when an application exits, all server defaults
are restored. The only exception is that when exiting from a callback that
is activated by shortcuts. Thus it is recommended
that the cleanup routine fl_finish() be called
prior to exiting an application or register it via atexit(3)
void fl_finish(void)
In addition to restoring all server defaults, fl_finish()
will also shut down the connection.
Creating forms
FL_FORM *fl_bgn_form(int type,FL_Coord w,FL_Coord h)
Starts the definition of a form.
type is the type of the box
that is used as a background. w and h give the width and height
of the form. The function returns a pointer to the form created.
void fl_end_form()
End the definition of a form. . Between
these two calls, various objects, including group of objects,
are added to the form.
FL_OBJECT *fl_bgn_group()
Begin the definition of a group of objects inside the form. It returns
a pointer to the group. Groups should never be nested.
FL_OBJECT * fl_end_group(void)
Ends the definition of a group.
Groups are useful for two reasons. First of all, it is possible
to hide or deactivate groups of objects. This is often very handy
to dynamically change the appearance of a form depending on
the context or selected options. In addition, it can also
be used as a shortcut to set some particular attributes of
several objects. It is not uncommon that you want several
objects to maintain their relative positioning upon form
resizing. This requires to set the gravity for each object.
If these objects are placed inside a group, setting the gravity
attributes of the group would suffice.
The second reason for using groups is for radio buttons.
Radio buttons are considered related only if they belong
to the same group. Using groups is the only way to place
unrelated groups of radio buttons on a single form without
interference from each other.
void fl_addto_group(FL_OBJECT *group)
reopens a group for adding more objects to it. Any new objects
added are appended at the end of the group.
void fl_addto_form(FL_FORM *form)
Reopens a form for adding objects to it.
void fl_delete_object(FL_OBJECT *obj)
Removes an object from the form it is in.
void fl_free_object(FL_OBJECT *obj)
Frees the memory for an object.
(Object should be deleted first.) An object after being freed should
not be referenced.
void fl_free_form(FL_FORM *form)
Frees the memory for a form, together with all its objects. The form should
not be visible.
Doing interaction
long fl_show_form(FL_FORM *form,int place,int border,const char *title)
Displays a form on the screen. place controls
the position and size of the form. border indicates whether
a border (window manager's decoration) should be drawn around the form.
In this case title is the name of the window. The routine returns
the window identifier of the form. For resource and identification purposes,
the form name is taken to be the title with space removed
and the first character lower-cased. E.g., if a form has a title
Foo Bar the form name is derived as fooBar.
There are variations on the border requests:
FL_FULLBORDER full border with title showing.
FL_TRANSIENT border possibly with less decoration.
FL_NOBORDER no border at all.
Multiple forms can be displayed at the same moment.
Note that FL_NOBORDER might have adverse effect on
keyboard focus and is not very friendly
to other applications (it is close to impossible to move a form that
has no border). Thus use this feature with
discretion. The only situation where FL_NOBORDER is
appropriate is for automated demonstration suites or when the
application program must obtain an input or a mouse click
from the user, and even then all other forms should be deactivated
while a borderless form is active. For almost all situations where
the application must demand an action from the user, FL_TRANSIENT
is preferred. Also note you can't iconify a form that has no border
and under most window managers, FL_TRANSIENT form can't be
iconified either.
On additional property (under almost all window managers) of
a transient window is that it will stay on top of the
main form , which the application program can designate
using
void fl_set_app_mainform(FL_FORM *form)
By default, the main form is set automatically by the library to the first
full-bordered form shown.
To obtain the current main form, use the following routine
FL_FORM *fl_get_app_mainform(void)
In some situations, either because the concept of an application
main form does not apply (for example, an application might have multiple
full-bordered windows), or under some (buggy) window managers,
the designation of a main form may cause stacking order problems.
To workaround these, the following routine can be used to
disable the designation of a main form (before any full-bordered
form is shown)
void fl_set_app_nomainform(int flag)
with a true flag
All visible forms will have the following properties set
WM_CLASS
WM_CLIENT_MACHINE
WM_NAME
In addition, the first full border form will have
the WM_COMMAND
property set and is by default the application main form.
The application program can raise a form to the top of the screen so
no other forms obscure it by using the following routine
void fl_raise_form(FL_FORM *form)
Similar routine exists that lowers a form to the bottom of
the stack
void fl_lower_form(FL_FORM *form)
When placing a form on the screen using place FL_PLACE_GEOMETRY the
position and size can be set using the routines
void fl_set_form_position(FL_FORM *form, FL_Coord x, FL_Coord y)
void fl_set_form_size(FL_FORM *form, FL_Coord w, FL_Coord h)
void fl_scale_form(FL_FORM *form, double xsc, double ysc)
Where the last routine scales with a factor with respect to the current
size. These routines can also be used when the form is visible.
If interactive resizing is to be allowed, (e.g., form shown using
FL_PLACE_FREE), it can be useful to limit the range the size
of a form can take. To this end, the following functions are
available
void fl_set_form_minsize(FL_FORM *form, FL_Coord minw, FL_Coord minh);
void fl_set_form_maxsize(FL_FORM *form, FL_Coord maxw, FL_Coord maxh);
Although these two routines can be used before or after
a form becomes visible, not all window managers honor
such requests once the window is visible. Also note that
these constraints routines only applies to the next
fl_show_form().
To set or change the icon shown when a form is iconified, use the
following routine
void fl_set_form_icon(FL_FORM *form, Pixmap icon, Pixmap mask)
where icon can be any valid Pixmap ID. (See Sections
14.5 and 14.6 for some of the routines that
can be used to create Pixmaps) Note that the previous icon
if not freed or modified in anyway.
If for any reason, you would like to
change the form title after it is shown, the following call can
be used (this will also change the icon title)
void fl_set_form_title(FL_FORM *form, const char *name)
void fl_hide_form(FL_FORM *form)
hides the particular form, i.e., closes its window and all subwindows,
To check if a form is visible or not,
the following can be used
int fl_form_is_visible(FL_FORM *form)
FL_OBJECT *fl_do_forms(void)
Does the interaction with the currently displayed forms.
The routine ends when the state of some object changes. A pointer
to this object is returned if no callback is bound to it.
FL_OBJECT *fl_check_forms(void)
Second way of doing interaction with the currently displayed forms.
The routine returns immediately NULL
unless
the state of some object changes in which case a
pointer to this object is returned.
FL_OBJECT *fl_do_only_forms(void)
FL_OBJECT *fl_check_only_forms(void)
Same as fl_{do|check}_forms except that these routines do not
handle user events generated by application windows via
fl_winopen() or similar routines.
void fl_activate_form(FL_FORM *form)
Activates a form for user interaction.
void fl_deactivate_form(FL_FORM *form)
Deactivates a form to stop user interaction with it.
void fl_deactivate_all_forms(void)
void fl_activate_all_forms(void)
Activates or deactivates all forms to stop user interaction with them.
You can also register for a form callbacks that are invoked whenever
the activation status of the form is changed:
typedef void (*FL_FORM_ATACTIVATE)(FL_FORM *, void *);
FL_FORM_ACTIVATE fl_set_form_atactivate(FL_FORM *form,
FL_FORM_ATACTIVATE callback, void *data);
FL_FORM_ACTIVATE fl_set_form_atdeactivate(FL_FORM *form,
FL_FORM_ATACTIVATE callback, void *data);
void fl_activate_object(FL_OBJECT *obj)
Activates an object for user interaction.
void fl_deactivate_object(FL_OBJECT *obj)
Deactivates an object to stop user interaction with
it.
void fl_redraw_object(FL_OBJECT *obj)
This routine redraws the particular object. If obj is a group it
redraws the complete group. Normally you
should never need this routine because all library routines take care
of redrawing but there might be situations in which a redraw is required.
void fl_redraw_form(FL_FORM *form)
Setting attributes
A number of general routines are available for setting
attributes. Unless stated otherwise, all attributes
altering routines affect the appearance or geometry of
the object immediately if the object is visible.
void fl_set_object_color(FL_OBJECT *obj, int col1, int col2)
Sets the two colors that influence the appearance of the object.
void fl_set_object_boxtype(FL_OBJECT *obj, int boxtype)
Changes the shape of the bounding box of the object.
void fl_set_object_position(FL_OBJECT *ob, FL_Coord x, FL_Cood y)
sets a new position for the object. If the object is visible,
it is moved to the new location.
void fl_set_object_size(FL_OBJECT *ob, FL_Coord w, FL_Coord h)
changes the object size while keeping the upper-left corner of
the bounding box unchanged.
void fl_set_object_geometry(FL_OBJECT *ob, FL_Coord x, FL_Coord y,
FL_Coord w, FL_Coord h)
sets both the position of the size of an object.
To obtain the object geometry, use the following routines
void fl_get_object_geometry(FL_OBJECT *ob, FL_Coord *x, FL_Coord *y,
FL_Coord *w, FL_Coord *h)
void fl_get_object_bbox(FL_OBJECT *ob, FL_Coord *x, FL_Coord *y,
FL_Coord *w, FL_Coord *h)
The difference between these two functions is that
fl_get_object_bbox() returns the bounding box size
that has the label size figured in.
void fl_set_object_lcol(FL_OBJECT *obj, int lcol)
void fl_set_object_lsize(FL_OBJECT *obj, int lsize)
void fl_set_object_lstyle(FL_OBJECT *obj, int lstyle)
void fl_set_object_lalign(FL_OBJECT *obj, int align)
void fl_set_object_label(FL_OBJECT *obj, const char *label)
These routines set the color, size, style, alignment and text of the label
of the object.
void fl_set_object_resize(FL_OBJECT *obj, unsigned howresize)
void fl_set_object_gravity(FL_OBJECT *obj,
unsigned NWgravity, unsigned SEgravity)
If you change many attributes of a single object or many objects in a
visible form, the changed object is redrawn after each change. To avoid
this, put the changes between calls to
void fl_freeze_form(FL_FORM *form)
void fl_unfreeze_form(FL_FORM *form)
There are also routines that influence the way events are dispatched.
These routines are provided mainly to facilitate the development
of (unusual) new objects where attributes need to be changed
on the fly. These routines should not be used on the built-in ones.
To enable or disable an object to receive the FL_STEP event,
use the following routine
void fl_set_object_automatic(FL_OBJECT *obj, int flag)
To enable or disable an object to receive the FL_DBLCLICK event,
use the following routine
void fl_set_object_dblclick(FL_OBJECT *obj, int timeout)
void fl_show_object(FL_OBJECT *obj)
Makes the object, or the group if obj is a group,
visible .
void fl_hide_object(FL_OBJECT *obj)
makes the object or group invisible.
void fl_trigger_object(FL_OBJECT *obj);
returns obj to the application program or calls obj's
callback if one exists.
void fl_set_focus_object(FL_FORM *form,FL_OBJECT *obj)
Set the input focus in form form onto object obj.
Note however, if this routine is used as a response to
an FL_UNFOCUS event, i.e., as an attempt to override the
focus assignment by the main loop from within an object
event handler, this routine will not
work as the main loop assigns a new focus object upon
return from the object event handler, which undoes the
focus change inside the event handler. To override and only
when overriding the FL_UNFOCUS event, the following routine
should be used:
void fl_reset_focus_object(FL_OBJECT *obj)
void fl_set_object_callback(FL_OBJECT *obj,
void (*callback)(FL_OBJECT *, long),
long argument)
binds a callback routine to an object.
To invoke the callback manually (as opposed to invocation
by the main loop), use the following function
void fl_call_object_callback(FL_OBJECT *obj)
If the object obj does not have a callback associated with it,
this call has not effect.
void fl_set_form_callback(FL_FORM *form,
void (*callback)(FL_OBJECT *, void *), void *data)
Binds a callback routine to an entire form.
It is sometimes useful to obtain the last event from within
a callback function, e.g., to implement different functionalities
depending on which button triggers the callback. For this,
the following routine can be used from within a callback
function.
const XEvent *fl_last_event(void)
For non-form windows, i.e., those created with
fl_winopen() or similar routines by the application
program, the following means of interaction are provided
(note that these do not work on form windows, for which
a different set of functions exist. See Section C
for details)
void fl_set_event_callback(void (*callback)(void *xevent, void *data))
Sets up a callback routine for all user events.
It is possible to set up callback functions on a per window/event
basis using the following routines
typedef int (*FL_APPEVENT_CB)(XEvent *xev, void *user_data);
FL_APPEVENT_CB fl_add_event_callback(Window win, int xevent_type,
FL_APPEVENT_CB callback, void *user_data);
void fl_remove_event_callback(Window win, int xevent_type)
These functions manipulate
event callback functions for the window
specified and will be called when xevent_type is pending for
the window. If xevent_type is zero, it signifies a callback
for all event for window win. Note that
Forms Library does not solicit any event for the caller, i.e., Forms Library assumes
the caller opens the window and solicits all events before calling
these routines. To let Forms Library handle event solicitation, the following
function may be used
void fl_activate_event_callback(Window win);
The following routine can be used to sound the keyboard bell (if capable),
void fl_ringbell(int percent)
where percent can range from -100 to 100 with 0 being
the default volume setting of the keyboard. A value of 100
indicates maximum volume and a value of -100 indicates minimum
volume (off). Note that not all keyboards support volume variations.
There is another routine that might come in handy
void fl_gettime(unsigned long *sec, unsigned long *usec)
Upon function return, sec and usec are set
to the current time, expressed in seconds and microseconds
since 00:00 GMT January, 1970. This function is most useful
for computing time differences.
Signals
The application program can elect to handle the receipt of a signal
by registering a callback function that gets called when the
signal is raised and caught
typedef void (*FL_SIGNAL_HANDLER)(int, void *);
void fl_add_signal_callback(int signal, FL_SIGNAL_HANDLER sh, void *data);
Only one callback per signal is permitted.
By default, fl_add_signal_callback will store the callback function
and initiate mechanism for the OS to deliver the signal when it occurs.
When the signal is received by the library, the main loop will invoke the
registered callback function when it is appropriate to do so. The callback
function can make use of all XForms's functions as well as Xlib functions as if
there were re-entrant. Further, a signal callback so registered is persistent
and will cease to function only when explicitly removed.
It is very simple to use this routine. For example, to prevent
a program from exiting prematurely due to interrupts, code
fragment similar to the following can be used:
void clean_up(int signum, void *data)
{
/* clean up, of course */
}
/* and somewhere after fl_initialize */
fl_add_signal_callback(SIGINT, clean_up, &mydata);
After this, whenever interrupt is detected, clean_up is called.
To remove a signal callback, the following routine should be used
void fl_remove_signal_callback(int signal);
There are limitations with the default behavior outlined above. For example,
on some platforms, there is no blocking of signals of any kind while
handling a signal. In addition, use of fl_add_signal_callback
prevents the application program from using any, potentially more
flexible, system signal handling routines on some platforms.
In light of these limitations, provisions are made so an application program
may choose to take over the initial signal handling setup and receipt via
various system dependent methods (sigaction(2) for example).
To change the default behavior of built-in signal facilities,
the following routine should be called prior to any use of
fl_add_signal_callback with a true flag:
void fl_app_signal_direct(int flag)
After this call, fl_add_signal_callback will not
initiate any actions to receive a signal. The application
program should handle the receipt and blocking of a signal (via,
signal(2), sigaction2, sigprocmask2 etc.)
When the signal is received by the application program, it should call
the following routine to inform the main loop of the delivery
of the signal signum
void fl_signal_caught(int signum);
This routine is the only one in the library that can be
safely called from within a direct application signal handler.
If multiple invocation of fl_signal_caught occurs
before the main loop is able to call the registered callback,
the callback is called only once.
Idle callbacks and timeouts
For application programs that need to perform some light,
but semi-continuous or periodic tasks, idle callback and
timeouts (also FL_TIMER+) can be utilized.
To register an idle callback with the system, use the
following routine
typedef int (*FL_APPEVENT_CB)(XEvent *, void *);
FL_APPEVENT_CB
fl_set_idle_callback(FL_APPEVENT_CB callback, void *user_data)
where callback is the function that will get called whenever
the main loop is idle.
The time interval between any two consecutive invocations of the idle
callback can vary considerably depending on the interface activity
and other factors. A range between 50 and 300 milli-second should be
expected.
It is possible to change the the condition (intervals of inactivity)
based on which the main loop determines the idleness of the interface.
To this end, the following is available
void fl_set_idle_delta(long msec)
where msec is the minimum interval of inactivity to be considered
idle. However, it should be noted that under some conditions,
an idle callback can be called sooner than the minimum interval.
If the timing of the idle callback is of concern, timeouts should be
used. Timeouts are similar to idle callbacks but with the property
that the user can specify a minimum time interval that must
elapse before the callback is called. To register a timeout callback,
the following routine can be used
typedef void (*FL_TIMEOUT_CALLBACK)(int, void *)
int fl_add_timeout(long msec,
FL_TIMEOUT_CALLBACK callback, void *data)
The function returns the timeout ID. When the time interval
specified by msec (in milli-second) is elapsed, the callback
function is called. After the callback returns, the timeout is removed.
Although timeout offers some control over the timing, due to
performance and cpu load compromises, the resolution at best is only
0.05 seconds, and can occasionally be in the 0.05-0.15 seconds range.
To remove a timeout before it triggers, use the following
routine
void fl_remove_timeout(int ID)
where ID is the timeout ID returned by fl_add_timeout().
See also Section 19.1 for the usage of
FL_TIMER object.
Resources for Forms Library
Managing resources is an important part of programming with X.
Typical X programs use extensive resource database/management to customize
their appearances. With the help of Form Designer, there is little or no
need to specify any resources for the default appearance
of an application written using the Forms Library.
Because of this, complete resource support is somewhat
a low-priority task and currently only minimal support
is available. Nevertheless, more complete and useful
resource management system specific to the Forms Library can be
implemented using the services provided by the XForms.
Current Support
At the moment, all built-in XForms resources have a top level
class name XForm and a resource name xform.
Because of this incomplete specification,
most of the current resources are ``global", in the sense that
they affect all form windows. Eventually all resources
will be fully resolved, e.g., to specify
attribute foo of form formName, the resource name
can be appName.formName.foo instead of
(the current incomplete) appName.xform.foo.
The argument app_opt in fl_initialize() is a table of
structures listing your application's command line options. The
structure is defined as follows
typedef struct
{
char *option;
char *specifier;
XrmOptionKind argKind;
void *value;
} XrmOptionDescList, FL_CMD_OPT;
See XrmGetResource(3X11) for details.
After the initialization routine is called, all command line arguments,
both XForms built-in and application specific ones, are removed
from argc and argv and parsed into a standard
XResources database. To read your application specific options,
follow fl_initialize() with the following routine
int fl_get_app_resources(FL_resource *resource, int nresources);
Here resource is a table containing application specific
resources in the following format:
typedef struct
{
char *res_name; /* resource name without application name */
char *res_class; /* resource class */
FL_RTYPE type; /* C type of the variable */
void *var /* variable that will hold the value */
char *defval; /* default value in string form */
int nbytes; /* buffer size for string var. */
} FL_RESOURCE;
and the resource type FL_RTYPE type is one of the following
FL_SHORT for short variable
FL_BOOL for boolean variable (int)
FL_INT for int variable
FL_LONG for long variable
FL_FLOAT for float variable
FL_STRING for char [] variable
Note that the variable for FL_BOOL must be of type int.
It differs from FL_INT only in the way the resources
are converted, not in the way their values are stored. A boolean
variable is considered to be true (1) if any one of
True, true, Yes, yes, On, on, or 1 is specified as its value.
For string variables, the length for the destination buffer
must be specified.
fl_get_app_resources() simply looks up all entries specified
in FL_resource structure in all databases after prefixing
the resource name with the application name, which can be the new
name introduced by the -name option.
Summarized below are the currently recognized Forms Library built-in resources:
Resource Name Class Type Default
rgamma Gamma float 1.0
ggamma Gamma float 1.0
bgamma Gamma float 1.0
visual Visual string best
depth Depth int best
doubleBuffer DoubleBuffer bool false
privateColormap PrivateColormap bool false
standardColormap StandardColormap bool false
sharedColormap SharedColormap bool false
pupFontSize PupFontSize int 12pt
buttonFontSize FontSize int 10pt
sliderFontSize FontSize int 10pt
inputFontSize FontSize int 10pt
browserFontSize FontSize int 10pt
menuFontSize FontSize int 10pt
choiceFontSize FontSize int 10pt
ulPropWidth ULPropWidth bool true
ulThichness ULThickness int 1
leftScrollBar LeftScrollBar bool false
coordUnit CoordUnit string pixel
borderWidth BorderWidth int 3
Again, ``best" means that the Forms Library by default selects a visual
that has the most depth.
By default, resource files are read and merged in the order as
suggested by X11 R5 as follows:
/usr/lib/X11/app-defaults/<AppClassName>$XAPPRLESDIR/<AppClassName>RESOURCE_MANAGER property as set using xrdb
if RESOURCE_MANAGER is empty, ~/.Xdefaults
$XENVIRONMENT
if $XENVIORONMENT is empty, ~/.Xdefaults-hostname
All options set via resources may not be the final values
used because resource settings are applied at the time
object/form is created, thus any modifications after that
override the resource settings. For example, buttonLabelSize,
if set, is applied at the time the button is created
(fl_add_button()). Thus altering the size after the button
is created via fl_set_object_lsize() overrides whatever is
set by the resource database.
To run your application in PseudoColor with a depth of 8 and
a thick underline, specify the following resources
appname*visual: PseudoColor appname*depth: 8 appname*ulThickness: 2
Since resources based on a form by form basis are yet to be implemented, there is no point specifying anything more specific although appname.XForm.depth etc. would work correctly.
Let us assume that you have an application named myapp, and it accepts the options -foo level and -bar, and a filename. The proper way to initialize the Forms Library is as follows
FL_CMD_OPT cmdopt[] =
{
{"-foo", "*.foo", XrmoptionSepArg, 0},
{"-bar", ".bar", XrmoptionNoArg, "True"},
};
int foolevel, ifbar;
int deftrue; /* can only be set thru resources */
FL_resource res[] =
{
{"foo", "FooCLASS", FL_INT, &foolevel, "0"},
{"bar", "BarCLASS",FL_BOOL, &ifbar,"0"},
{"deftrue", "Whatever",FL_BOOL, &deftrue,"1"}
};
int
main(int argc, char *argv[])
{
fl_initialize(&argc, argv ,"MyappClass", cmdopt, 2);
fl_get_app_resources(res, 3);
if(argc == 1) /* missing filename */
fprintf(stderr,"Usage %s: [-foo level][-bar] filename\n","myapp");
/* rest of the program */
}
After this, both foolevel and ifbar are set either through resource files or command line options with the command line options overriding those set in the resource file. In case neither the command line nor the resource file specified the options, the default value string is converted.
There is another routine, the resource routine of the lowest level in XForms, might be useful if a quick& dirty option needs to be read:
const char *fl_get_resource(const char *res_name, const char *res_class,
FL_RTYPE type, char *defval, void *val, int nbytes)
res_name and res_class here must be complete
resource specifications (minus the appliation name) and should
not contain wildcard of any kind. The resource will be converted
according to the type and result stored in type.
nbytes is used only if the resource type is FL_STRING.
The function returns the string representation of the resource value.
If type is passed a value FL_NONE, the resource is not
converted and the pointer val is not referenced.
There is also a routine that allows the application program to set resources programatically
void fl_set_resource(const char *string, const char *value)
where string and value are a resource-value pair. The string can be a fully qualified resource name (minus the application name) or a resource class.
Routines fl_set_resource and fl_get_resource
can be used to store and retrieve arbitary strings and values
and may be useful to pass data around.
It is possible to implement your own form/object specific resources management system using the services mentioned above. For example, to implement a user-configurable form size, code similiar to the following can be used, assuming the form is named ``myform"
struct fsize { int width, height; } myformsize;
FL_resource res[] =
{
{"myform.width", "XForm.width", FL_INT, &(myform.width), "150"},
{"myform.height","XForm.height", FL_INT, &(myform.height), "150"},
};
fl_initialize(&argc, argv, app_class, 0, 0);
fl_get_app_resources(res,2);
/* create the forms */
myform = fl_bgn_form (myformsize.width, myformsize.height,.....);
Or (more realistically) you create the form first using fdesign and then scale it before it is shown:
fl_initialize(&argc, argv, app_class, 0, 0); fl_get_app_resources(res,2); /*create_all_forms here */ fl_set_form_size(myform, mysformsize.width, myformsize.height); fl_show_form(myform, ...);
Eventully form geometry and other things might be done via XForms internal routines, it is recommended that you name your form to be the form title with all spaces removed and first letter lower-cased, i.e., if a form is shown with a label Foo Bar, the name of the form should be fooBar.
This chapter describes some of the routines that may be used in special situations where more power or flexibility from Forms Library is needed. These routines are classified as ``dirty tricks" either because they can easily mess up the normal operation of Forms Library or they depend on internal information that might change in the future, or they rely too much on the underlying window systems. Thus whenever possible, try not to use these routines.
It is possible to by-pass the form event processing entirely by setting a ``raw callback'' that sits between the event reading and dispatching stage, thus a sneak preview can be implemented and optionally consume the event before the internal form processing machinery gets to it.
Use the following routines to register such a preemptive processing routine
typedef int (*FL_RAW_CALLBACK)(FL_FORM *, void *xevent);
FL_RAW_CALL_BACK fl_register_raw_callback(FL_FORM *form,
unsigned long mask,
FL_RAW_CALLBACK callback);
where mask is the event mask you are interested in (same as XEvent mask). The function returns the old handler for the event.
Currently only handlers for the following events are supported
Further there is only one handler for each event pair, (e.g., ButtonPress and ButtonRelease), thus you can't have two separate handlers for each pair although it is okay to register a handler only for one of them (almost always a mistake) if you know what you're doing. If you register a single handler for more than one pair of events, e.g., setting mask to KeyPressMask|ButtonPressMask, the returned old handler is random.
A special constant, FL_ALL_EVENT, is defined so that the
handler registered will received all events that are selected.
To select events, use fl_addto_selected_xevent().
Once an event handler is registered and the event is detected, then instead of doing the default processing by the dispatcher, the registered handler is invoked. The handler must return FL_PREEMPT if the event is gobbled up (consumed) and 0 otherwise so that the internal process can continue. See minput2.c for an example.
Just as you can by-pass the internal event procesing for a particular form, you can also do so for an object. Unlike in raw callbacks, you can not select individual events.
The mechnism provided is via the registration of a pre-handler for an object. The pre-handler will be called before the built-in object handler. By electing to handle some of the events, a pre-handler can, in effect, replace part of the built-in handler.
Chapter 27.1 has already discussed the API in detail, here we just repeat the discussion for completeness as any use of preemptive handler is considered ``dirty tricks".
To register a pre-handler, use the following routine
typedef int (*FL_HANDLEPTR)(FL_OBJECT *ob, int event,
FL_Coord mx, FL_Coord my,
int key, void *raw_event);
void fl_set_object_prehandler(FL_OBJECT *, FL_HANDLEPTR prehandler);
Where event is the generic event in the Forms Library, that is, FL_DRAW, FL_ENTER etc. Parameter mx, my are the mouse position and key is the key pressed. The last parameter raw_event is the (cast) XEvent that caused the invocation of the pre-handler.
Notice that the pre-handler has the same function prototype as the built-in handler. Actually they are called with the same exact parameters by the event dispatcher. The prehandler should return 0 if the processing by the built-in handler shoud continue. A return value of FL_PREEMPT will prevent the dispatcher from calling the built-in handler.
See demo program preemptive.c for an example.
Similar mechnism exists for registering a post-handler, i.e., a handler invoked after the built-in handler finishes. Whenever possible a post-handler should be used instead of a pre-handler.
Some of these routines are used internally by the Forms Library as an attempt to localize window system dependencies and may be of some general use. Be warned that these routines may subject to frequent changes, both in their API and/or functionality.
You can create and show a window with the following routines
Window fl_wincreate(const char *name) Window fl_winshow(Window win);
where parameter win in fl_winshow is the window ID
returned by fl_wincreate. Between the creation and showing
of the window, other attributes of the window can be set. Note
a window so opened is always a top level window and
uses all the Forms Library'f defaults (visual, depth etc.)
It is sometimes more convenient to create and show a window directly
Window fl_winopen(const char *name)
This will open a (top-level) window with a title name. A window
so opened can be drawn into as soon as the function returns, i.e.,
fl_winopen() waits until the window is ready to be drawn into.
The newly opened window will have the following default attributes
By default, the newly opened window will have a size of 320 by 200
pixels and has no other constraints. You can modify the default or
constraints using the following routines prior to calling
fl_winopen():
void fl_initial_winsize(FL_Coord w, FL_Coord h) void fl_winsize(FL_Coord w, FL_Coord h)
These two routines set the preferred window size. w and
h are the width and height of the window in pixels.
fl_winsize() in addition will make the window non-resizable
(You can still resize the window programmatically) by
setting the minimum and maximum window size to the requested size via
WMHints. The effect of a window having this property is
that it can't be interactively resized (provided the window manager cooperates).
It is sometimes desirable to have a window that is resizable but only within a useful range. To set such a constraint, use the following functions:
void fl_winminsize(Window window, FL_Coord minw, FL_Coord minh)
void fl_winmaxsize(Window window, FL_Corrd maxw, FL_Coord maxh)
These two routines can also be used after a window becomes visible. For windows to be created/opened, use 0 for the window parameter. For example, if we want to open a window of 640 by 480 pixels, and have it remain resizeable but within a permitted range, code similar to the following can be used:
fl_initial_winsize(640,480);
fl_winminsize(0, 100,100);
fl_winmaxsize(0, 1024,768)
win = fl_winopen("MyWin");
In addition to window size preference, you can also set preferred position of a window to be opened:
void fl_winposition(FL_Coord x, FL_Coord y)
where x and y are the coordinates of the upper-left corner of the window relative to the root window.
Or you can set the geometry in one function call
void fl_initial_wingeometry(FL_Coord x, FL_Coord y,
FL_Coord w, FL_Coord h)
void fl_wingeometry(FL_Coord x, FL_Coord y,
FL_Coord w, FL_Coord h)
Again, the fl_wingeometry will deny later interactive resizing.
There are other routines that can be used to change other aspects of the window to be created
fl_winaspect(Window win, FL_Coord x, FL_Coord y)
This will set the aspect ratio of the window in later interactive resizing.
To change the window title (and its associated icon title), use the following routine
void fl_wintitle(Window win, const char *title)
To install an icon for the window, use the following routine
void fl_winicon(Window win, Pixmap icon, Pixmap mask)
You can suppress the window manager's decoration or make the window a transient one by using the following routines
void fl_noborder(void) void fl_transient(void)
You can also set the background of the window to a certain color using the following call
void fl_winbackground(Window win, unsigned long pixel)
It is possible to set the change size of a window to some discrete steps:
void fl_winstepsize(Window win, int xunit, int yunit)
where xunit and yunit are the amount of changes per unit in the x- and y- directions respectively. Note that this only applies to interactive resizing.
To change constraints (size and aspect ratio) on an active window, you can use the following routine
void fl_reset_winconstraints(Window win)
The following routines are available to get information about an active window win:
void fl_get_winsize(Window win, FL_Coord *w, FL_Coord *h)
void fl_get_winorigin(Window win, FL_Coord *x, FL_Coord *y)
void fl_get_wingeometry(Window win, FL_Coord *x, FL_Coord *y,
FL_Coord *w, FL_Coord *h)
All units are in pixels. Origin of a window is measured from the upper left corner of the root window.
To change the size of window programmatically, the following routine is available:
int fl_winresize(Window win, FL_Coord neww, FL_Coord newh)
In addition to resizing the window, this routine will keep the original constraints. For example, if a window was not permitted to be interactively resized, after the resize, it remains unresizeable. Resizing is done by keeping the origin constant relative to the root window.
To move a window without resizing it, use the following call
void fl_winmove(Window win, FL_Coord newx, FL_Coord newy)
To move and resize a window, use the following routine
void fl_winreshape(Window win, FL_Coord newx, FL_Coord newy,
FL_Coord neww, FL_Coord newh)
To make a window invisible, use the following routine
void fl_winhide(Window win)
A hidden window can be shown again later using fl_winshow.
To hide and destroy a window, use the following calls
void fl_winclose(Window win)
There will be no events generated from fl_winclose, i.e.,
the function waits and eats all events for window win.
In addition, this routine also removes all callbacks
associated with the closed window.
The following routine can be used to check if a window is valid or not
int fl_winisvalid(Window win)
Note that excessive use of this function may negatively impact performance.
XForms also provides a convenience function to change the cursor shapes
void fl_set_cursor(Window win, int name)
where win must be a valid window identifier and name
is one of the symbolic cursor names (shapes) defined by standard X or
the integer value returned by fl_create_bitmap_cursor()
or one of the Forms Library's pre-defined symbolic names.
The symbolic cursor names (all starts with XC_) are defined
in <X11/cursorfont.h>. For example, to set a watch-shaped cursor
for form form, the following call may be made
fl_set_cursor(form->window, XC_watch);
The Forms Library defined a special symbolic constants, FL_INVISIBLE_CURSOR
that can be used to hide the cursor for window win:
fl_set_cursor(win, FL_INVISIBLE_CURSOR);
Depending on the structure of the application program, an
XFlush(fl_get_display()) may be required following
fl_set_cursor().
To reset the cursor to the XForms's default (an arrow pointing northwest), use the following routine
void fl_reset_cursor(Window win)
To change the color of a cursor, use the following routine
void fl_set_cursor_color(int name, FL_COLOR fg, FL_COLOR bg)
where fg and bg are the foreground and background color of the cursor respectively. If the cursor is being displayed, the color change is visible immediately.
It is possible to use cursors other than those defined by the standard cursor font by creating a bitmap cursor
int fl_create_bitmap_cursor(const char *source, const char *mask,
int w, int h, int hotx, int hoty)
where source and mask are two (x)bitmaps. The mask
defines the shape of the cursor. The pixels set to 1 in the mask
defines which source pixels are displayed. If mask is null, all
bits in source are displayed. hotx and hoty
are the hotspot of the cursor (relative to the source's origin).
The function returns the cursor ID which can be used
in fl_set_cursor() and fl_set_cursor_color()
etc.
See demo cursor.c for an example use of the cursor routines.
As stated earlier, fl_set_defaults() can be used to modify
Forms Library's default prior to calling fl_initialize(). Actually
this routine can also be used after fl_initialize() to
override the values set on the command line or application databases.
However, overriding users' preference should be done with
discretion. Further, setting privateColormap after
fl_initialize() has no effect.
This appendix deals with a number of (common) problems encountered by people using the Forms Library. Ways of avoiding them are presented.
fl_show_form(),
the application program blocks the execution (e.g., waiting for a socket
connection, starting a new process via fork() etc.). To fix this
problem, you can flush the X buffer manually using
XFlush(fl_get_display()) before blocking occurs or use an idle
callback to check the status of the blocking device or let
the main loop handle it for you via fl_add_io_callback().
XSync(fl_get_display(),0).
-visual Default,
or selecting the default visual and colormap programmatically using
fl_set_defaults().
When you (think you) encountered a bug in the XForms please report it by sending
a mail message to zhao@bragg.phys.uwm.edu. In this mail please
indicate the version of the library, the type of machine and OS version
you are running this on. Some sample code that exhibits the erratic
behavior would help greatly.
The name of the window manager, and an output
of xdpyinfo or any other relevant information (demo program
similar to your code works/fails etc) would also help.
Forms Library version can be obtained by holding the <Meta> key and pressing the
middle mouse button somewhere in one of the forms, or by running
fdesign with -flversion flag.
Give a short description of the problem and if possible.
Don't expect an immediate answer but we will do our best.