@node Part V Overview of Main Functions
@chapter Overview of Main Functions

In this chapter we give a brief overview of all the main functions
that are available. For an overview of all routines related to
specific object classes see Part III.

@ifnottex

@menu
* Version Information::
* Initialization::
* Creating Forms::
* Object Attributes::
* Doing Interaction::
* Signals::
* Idle Callbacks and Timeouts::
@end menu

@end ifnottex

@node Version Information
@section Version Information

The header file @file{forms.h} defines three symbolic constants which
you can use to conditionally compile your application. They are
@table @code
@tindex FL_VERSION
@anchor{FL_VERSION}
@item FL_VERSION
The major version number.

@tindex FL_REVISION
@anchor{FL_REVISION}
@item FL_REVISION
Revision number.

@tindex FL_INCLUDE_VERSION
@anchor{FL_INCLUDE_VERSION}
@item FL_INCLUDE_VERSION
@code{1000 * FL_VERSION + FL_REVISION}
@end table

There is also a routine that can be used to obtain the library version
at run time:
@findex fl_library_version()
@anchor{fl_library_version()}
@example
int fl_library_version(int *version, int *revision)
@end example
@noindent
The function returns a consolidated version information, computed as
@code{1000 * version + revision}. For example, for library version 1
revision 21 (1.21), the function returns a value of 1021 with
@code{version} and @code{revision} (if not @code{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 versions less than 1.

To obtain the version number of the library used in an executable, run
the command with @code{-flversion} option, which will print the
complete version information.


@node Initialization
@section Initialization

The routine
@findex fl_initialize()
@anchor{fl_initialize()}
@example
Display *fl_initialize(int *argc, char *argv[], const char *appclass,
                       XrmOptionDescList app_opt, int n_app_opt);
@end example
@noindent
initializes the Forms Library and returns a pointer to the
@code{Display} structure if a connection could be made, otherwise
@code{NULL}. This function must be called before any other calls
to the Forms Library (except @code{@ref{fl_set_defaults()}} and a few
other functions that alter some of the defaults of the library).

The meaning of the arguments is as follows
@table @code
@item argc, argv
Number and array of the command line arguments the application was
started with. The application name is derived from @code{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 a dot @code{.}
or a star @code{*}.

@item appclass
The application class name, which typically is the generic name for
all instances of this application. If no meaningful class name exists,
it is typically given (or converted to if non given) as the
application name with the first letter capitalized (second if the
first letter is an X).

@item app_opt
Specifies how to parse the application-specific resources.

@item n_app_opt
Number of entries in the option list.
@end table

The @code{@ref{fl_initialize()}} function builds the resource
database, calls the Xlib @code{XrmParseCommand()} function to parse
the command line arguments, and performs other per display
initialization. After the creation of the database, it is associated
with the display via @code{XrmSetDatabase()}, so the application can
get at it if necessary.

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:
@multitable @columnfractions 0.25 0.1 0.45 0.2
@item @strong{Option}
@tab @strong{Type}
@tab @strong{Meaning}
@tab @strong{Default}

@item @code{-fldebug} @i{level}
@tab int
@tab prints debug information
@tab 0

@item @code{-name} @i{appname}
@tab string
@tab changes application name
@tab none

@item @code{-flversion}
@tab
@tab prints the version of the library
@tab

@item @code{-sync}
@tab
@tab requests synchronous mode(debug)
@tab false

@item @code{-display} @i{host:dpy}
@tab string
@tab specifies remote host
@tab @code{$DISPLAY}

@item @code{-visual} @i{class}
@tab string
@tab TrueColor, PseudoColor...
@tab best

@item @code{-depth} @i{depth}
@tab int
@tab specifies prefered visual depth
@tab best

@item @code{-vid} @i{id}
@tab long
@tab specifies prefered visual ID
@tab

@item @code{-private}
@tab
@tab forces private colormap
@tab false

@item @code{-shared}
@tab
@tab forces shared colormap
@tab false

@item @code{-stdcmap}
@tab
@tab forces standard colormap
@tab false

@item @code{-double}
@tab
@tab enables double buffering
@tab false

@item -bw @i{width}
@tab int
@tab changes border width
@tab 1

@item -rgamma @i{gamma}
@tab float
@tab specifies red gamma
@tab 1.0

@item -ggamma @i{gamma}
@tab float
@tab specifies green gamma
@tab 1.0

@item -bgamma @i{gamma}
@tab float
@tab specifies blue gamma
@tab 1.0
@end multitable

In the above table "best" means the visual that has the most colors,
which may or may not be the server's default. There is a special
command option @code{-visual Default} that sets both the visual and
depth to the X servers default. If a visual ID is requested, it
overrides depth or visual if specified. The visual ID can also be
requested programmatically (before @code{@ref{fl_initialize()}} is
called) via the function
@findex fl_set_visualID()
@anchor{fl_set_visualID()}
@example
void fl_set_visualID(long id);
@end example

Note that all command line options can be abbreviated, thus if the
application program uses single character options, they might clash
with the built-ins. For example, if you use @code{-g} as a command
line option to indicate geometry, it might not work as @code{-g}
matches @code{-ggamma} in the absence of @code{-ggamma}. Thus you
should avoid using single character command line options.

If the border width is set to a negative number, all objects appear to
have a softer appearance. Some people might prefer @code{-bw -2}.

Depending on your application, XForms defaults may or may not be
appropriate. E.g., on machines capable of @w{24 bits} visuals, Forms
Library always selects the deeper @w{24 bits} visual. If your
application only uses a limited number of colors, it might
be faster if a visual other than @w{24 bits} 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
defaults programmatically without affecting the users' ability to
override them with command line options. For this, you can use the
following routine before calling @code{@ref{fl_initialize()}}:
@findex fl_set_defaults()
@anchor{fl_set_defaults()}
@tindex FL_IOPT
@anchor{FL_IOPT}
@example
void fl_set_defaults(unsigned long mask, FL_IOPT *flopt);
@end example
@noindent
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.

The following table lists the fields, masks and their meanings of
@code{FL_IOPT}:
@multitable @columnfractions 0.25 0.3 0.45
@headitem Structure
@tab Mask Name
@tab Meaning
@item @code{typedef struct @{}
@tab
@tab

@item @code{int debug;}
@tab @code{FL_PDDebug}
@tab Debug level (0-5)

@item @code{int depth;}
@tab @code{FL_PDDepth}
@tab Preferred visual depth

@item @code{int vclass;}
@tab @code{FL_PDVisual}
@tab Prefered visual, @code{TrueColor} etc.

@item @code{int doubleBffer;}
@tab @code{FL_PDDouble}
@tab Simulate double buffering

@item @code{int buttonFontSize;}
@tab @code{FL_PDButtonFontSize}
@tab Default button label font size

@item @code{int menuFontSize;}
@tab @code{FL_PDMenuFontSize}
@tab Menu label font size

@item @code{int choiceFontSize;}
@tab @code{FL_PDChoiceFontSize}
@tab Choice label and choice text font size

@item @code{int browserFontSize;}
@tab @code{FL_PDBrowserFontSize}
@tab Browser label and text font size

@item @code{int inputFontSize;}
@tab @code{FL_PDInputFontSize}
@tab Input label and text font size

@item @code{int labelFontSize;}
@tab @code{FL_PDLabelFontSize}
@tab Label font size for all other objects (box, pixmap etc.)

@item @code{int pupFontSize;}
@tab @code{FL_PDPupFontSize}
@tab Font size for pop-ups

@item @code{int privateColormap;}
@tab @code{FL_PDPrivateMap}
@tab Select private colormap if appropriate

@item @code{int sharedColormap;}
@tab @code{FL_PDSharedMap}
@tab Force use of shared colormap

@item @code{int standardColormap;}
@tab @code{FL_PDStandardMap}
@tab Force use of standard colormap
@item @code{int scrollbarType;}

@tab @code{FL_PDScrollbarType}
@tab Scrollbar type to use for browser and input
@item @code{int ulThickness;}

@tab @code{FL_PDULThickness}
@tab Underline thickness
@item @code{int ulPropWidth;}

@tab @code{FL_PDULPropWidth}
@tab Underline width, 0 for const. width fonts
@item @code{int backingStore;}
@tab @code{FL_PDBS}
@tab Turn BackingStore on or off

@item @code{int coordUnit;}
@tab @code{FL_PDCoordUnit}
@tab Unit of measure: pixel, mm, point

@item @code{int borderWidth;}
@tab @code{FL_PDBorderWidth}
@tab Default border width

@item @code{@} FL IOPT;}
@tab
@tab
@end multitable

A special visual designation, @code{FL_DefaultVisual} and a command
line option equivalent, @code{-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
an arbitrary name that is specified with the @code{-name} option.

Coordinate units can be in pixels, points (1/72 inch), mm
(millimeters), cp (centi-point, i.e., 1/100 of a point) or cmm
(centi-millimeter). The the type of unit in use can be queried or
set via the functions
@findex fl_get_coordunit()
@anchor{fl_get_coordunit()}
@findex fl_set_coordunit()
@anchor{fl_set_coordunit()}
@example
int fl_get_coordunit(void);
void fl_set_coordunit(int coordUnit);
@end example
@noindent
@code{coordUnit} can have the following values:
@tindex FL_COORD_PIXEL
@tindex FL_COORD_POINT
@tindex FL_COORD_MM
@tindex FL_COORD_centiPOINT
@tindex FL_COORD_centiMM
@code{FL_COORD_PIXEL}, @code{FL_COORD_POINT}, @code{FL_COORD_MM},
@code{FL_COORD_centiPOINT} and @code{FL_COORD_centiMM}.

The unit in use 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:
@example
int oldcoordUnit = fl_get_coordunit();
fl_set_coordunit(FL_COORD_POINT);
fl_bgn_form(...);    /* add more objects */
fl_end_form();
fl_set_coordunit(oldcoordunit);
@end example

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 fonts and 2 for bold fonts.

There exists a convenience function to set the application default
border width
@findex fl_set_border_width()
@anchor{fl_set_border_width()}
@example
void fl_set_border_width(int border_width)
@end example
@noindent
which is equivalent to
@example
FL_IOPT fl_cntl;
fl_cntl.borderWidth = border_width;
fl_set_defaults(FL_PDBorderWidth, &fl_cntl);
@end example

Typically this function, if used, should appear before
@code{@ref{fl_initialize()}} is called so the user has the option to
override the default via resource or command line options.

To change the default scrollbar type (which is @code{THIN_SCROLLBAR})
used in browser and input object, the following convenience function
can be used:
@findex fl_set_scrollbar_type()
@anchor{fl_set_scrollbar_type()}
@example
void fl_set_scrollbar_type(int type);
@end example
where @code{type} can be one of the following
@table @code
@item FL_NORMAL_SCROLLBAR
Basic scrollbar

@item FL_THIN_SCROLLBAR
Thin scrollbar

@item FL_NICE_SCROLLBAR
Nice scrollbar

@item FL_PLAIN_SCROLLBAR
Similar to thin scrollbar, but not as fancy
@end table

Setting the scrollbar type before calling @code{@ref{fl_initialize()}}
is equivalent to
@example
FL_IOPT fl_cntl;
fl_cntl.scrollbarType = type;
fl_set_defaults(FL_PDScrollbarType, &fl_cntl);
@end example

It is recommended that this function be used before
@code{@ref{fl_initialize()}} so the user has the option to override
the default through application resources.

Prior to version 0.80, the origin of XForms' 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., with the
origin at the upper-left hand corner, so no manual intervention is
required. To help those who lost the @code{.fd} files or otherwise
can't use a newer version of @code{fdesign}, a compatibility function
is provided
@findex fl_flip_yorigin()
@anchor{fl_flip_yorigin()}
@example
void fl_flip_yorigin(void);
@end example
@noindent
Note however that this function must be called prior to
@code{@ref{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
@findex fl_set_tabstop()
@anchor{fl_set_tabstop()}
@example
void fl_set_tabstop(const char *s);
@end example
@noindent
where @code{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
@code{"aaaaaaaa"}, i.e.@: eight @code{'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-bliting. 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 a 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:
@findex fl_set_form_dblbuffer()
@anchor{fl_set_form_dblbuffer()}
@findex fl_set_object_dblbuffer()
@anchor{fl_set_object_dblbuffer()}
@example
void fl_set_form_dblbuffer(FL_FORM *form, int yes);
void fl_set_object_dblbuffer(FL_OBJECT *obj, int yes);
@end example
@noindent
Currently double buffering for objects having a non-rectangular box
might not work well. A nonrectangular box means that there are regions
within the bounding box that should not be painted, which is not
easily done without complex and expensive clipping and unacceptable
inefficiency. XForms gets around this by painting these regions with
the form's backface color. In most cases, this should prove to be
adequate. If needed, you can modify the background of the pixamp by
changing @code{obj->dbl_background} after switching to double buffer.

Normally the Forms Library reports errors to @code{stderr}. This can
be avoided or modified by registering an error handling function
@findex fl_set_error_handler()
@anchor{fl_set_error_handler()}
@example
void fl_set_error_handler(void (*user_handler)(const char *where,
                                               const char *fmt,...));
@end example
@noindent
The library will call the @code{user_handler} function with a string
indicating in which function an error occured and a formatting string
(see @code{sprintf()}) followed by zero or more arguments. To restore
the default handler, call the function again with @code{user_handler}
set to @code{NULL}. You can call this function anytime and as many
times as you wish.

You can also instruct the default message handler to log the error to
a file instead of printing to @code{stderr}
@findex fl_set_error_logfp()
@anchor{fl_set_error_logfp()}
@example
void fl_set_error_logfp(FILE *fp);
@end example
@noindent
For example
@example
fl_set_error_logfp(fopen("/dev/null","w"));
@end example
redirects all error messages to @file{/dev/null}, effectively turning
off the default error reporting to @code{stderr}.

In XForms versions older than 1.0.01 for some error messages, in
addition to being printed to stderr, a dialog box were shown that
requires actions from the user. This could be turned off and on
with the function
@findex fl_show_errors()
@anchor{fl_show_errors()}
@example
void fl_show_errors(int show);
@end example
@noindent
where @code{show} indicates whether to show (1) or not show (0) the
errors. With newer versions of the Forms Library this function has
no effect.

The fonts used in all forms can be changed using the routine
@findex fl_set_font_name()
@anchor{fl_set_font_name()}
@example
int fl_set_font_name(int n, const char *name);
@end example
@noindent
where @code{n} is a number between 0 and @code{FL_MAXFONTS -1}. The
function returns @code{0} on success, @code{1} if called before proper
initialization of the library and @code{-1} for either invalid
arguments (@code{name} isn't set or isn't a name of a font that could
be found, @code{n} negative or larger or equal to @code{FL_MAXFONTS}).
@xref{Label Attributes and Fonts}, 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 @w{10 pt} font on a @w{75 DPI} monitor
will have the label overflow the button on a @w{100 DPI} monitor. This
comes about because a character of a @w{10 pt} font when rendered with
@code{75 DPI} resolution may have 10 pixels while the same character
in the same @w{10 pt} font with @w{100 DPI} resolution may have 14
pixels. Thus, when designing the interfaces, leave a few extra pixels
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, @w{75 DPI} and @w{100
DPI}. Due to the variations in monitor resolutions, the theoretically
identical sized font, say a @w{10 pt} font, can vary in sizes (pixels)
by up to 30%, depending on the server (rendering a font on a @w{80
DPI} monitor will cause errors in sizes regardless if a @w{75 DPI} or
@w{100 DPI} 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 @w{90 DPI} monitor using @w{75 DPI} 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:
@findex fl_adjust_form_size()
@anchor{fl_adjust_form_size()}
@example
double fl_adjust_form_size(FL_FORM *form);
@end example
This function works by computing the size (in pixels) of every object
on the form that has an inside label and compares it to the size of
the object. Scaling factors are computed if any object labels don't
fit. The maximum scaling factor found is then used to scale the form
so every object label fits inside the object. It will never shrink a
form. The function returns the resulting scaling factor. In scaling
the form the aspect ratio of the form is left unmodified 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, this function should be a no-op on the
machine the forms were designed on. Form Designer has a special option
@code{-compensate} and resource @code{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 allows explicit margin
specifications:
@findex fl_fit_object_label()
@anchor{fl_fit_object_label()}
@example
void fl_fit_object_label(FL_OBJECT *obj, FL_Coord hm, FL_Coord vm);
@end example
@noindent
where @code{hm} and @code{vm} are the horizontal and vertical margins
to leave on each side of the object, respectively. This function works
by computing the object labels 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 (and thus of all 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.

All colors with indices smaller than @code{FL_FREE_COL1} are used (or
can potentially be used) by the Forms Library. If you wish they can be
changed using the function prior to @code{@ref{fl_initialize()}}:
@findex fl_set_icm_color()
@anchor{fl_set_icm_color()}
@example
void fl_set_icm_color(FL_COLOR index, int r, int g, int b);
@end example
@noindent
Using this function you can actually change all entries in the
internal colormap (with @code{index} going up to
@code{FL_MAX_COLORS-1}). You may also inspect the internal colormap
using
@findex fl_get_icm_color()
@anchor{fl_get_icm_color()}
@example
void fl_get_icm_color(FL_COLOR index, int *r, int *g, int *b);
@end example

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 the application exits, all server
defaults are restored. The only exception is when exiting from a
callback that is activated by shortcuts. Thus it is recommended that
the cleanup routine @code{@ref{fl_finish()}} is called prior to
exiting an application or register it via @code{atexit()}.
@findex fl_finish()
@anchor{fl_finish()}
@example
void fl_finish(void);
@end example
In addition to restoring all server defaults, @code{@ref{fl_finish()}}
also shuts down the connection and frees dynamically allocated memory.


@node Creating Forms
@section Creating Forms

To start the definition of a form call
@findex fl_bgn_form()
@anchor{fl_bgn_form()}
@example
FL_FORM *fl_bgn_form(int type, FL_Coord w, FL_Coord h);
@end example
@noindent
@code{type} is the type of the box that is used as a background.
@code{w} and @code{h} give the width and height of the new form. The
function returns a pointer to the form created.

Once all objects required have been added to a form call
@findex fl_end_form();
@anchor{fl_end_form()}
@example
void fl_end_form(void);
@end example

Between these two calls objects and groups of objects are added to the
form. To start a new group of objects use
@findex fl_bgn_group()
@anchor{fl_bgn_group()}
@example
FL_OBJECT *fl_bgn_group(void);
@end example
@noindent
The function returns a pointer to the group (actually to an invisible
object of class
@tindex FL_BEGIN_GROUP
@code{FL_BEGIN_GROUP}). Groups can't be nested.

When all objects that are supposed to belong to the group are added
call
@tindex FL_END_GROUP
@findex fl_end_group()
@anchor{fl_end_group()}
@example
void fl_end_group(void);
@end example
@noindent
Also this function creates an (invisible) object, belonging to class
@code{FL_END_GROUP}, but since it can't be used its address isn ot
returned.

Groups are useful for two reasons. First of all, it is possible to
hide or deactivate groups of objects with a single function call. 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 will suffice.

The second reason for use of groups is 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.

Both forms and groups that have been ended by
@code{@ref{fl_end_form()}} or @code{@ref{fl_end_group()}} can be
"reopened" by using
@findex fl_addto_form()
@anchor{fl_addto_form()}
@findex fl_addto_group()
@anchor{fl_addto_group()}
@example
FL_FORM *fl_addto_form(FL_FORM *form)
FL_OBJECT *fl_addto_group(FL_OBJECT *group);
@end example
@noindent
Both functions return their argument on success and @code{NULL} on
failure (e.g. because a different group or form is still open).
On success further objects can be appended to the form or group.

To remove an object from a form use
@findex fl_delete_object()
@anchor{fl_delete_object()}
@example
void fl_delete_object(FL_OBJECT *obj);
@end example
@noindent
This does not yet destroy the object, it just breaks its connection to
the form it did belong to, so it can still be referenced.

To finally destroy an object use
@findex fl_free_object()
@anchor{fl_free_object()}
@example
void fl_free_object(FL_OBJECT *obj);
@end example
@noindent
If @code{@ref{fl_delete_object()}} hadn't been called for the object
this will happen now. The object receives a final event of type
@code{FL_FREEMEM} to allow it to free memory it did allocate and do
whatever other clean-up required. Finally all memory allocated for the
object is freed. After being freed an object should not be referenced.

A form as a whole, together with all the objects it contains can be
deleted by calling
@findex fl_free_form()
@anchor{fl_free_form()}
@example
void fl_free_form(FL_FORM *form);
@end example
@noindent
This will first hide the form (emitting warning if this is necessary),
then free all of its objects and finally release memory allocated for
the form.


@node Object Attributes
@section Object Attributes

A number of general routines are available for setting and querying
attributes. Unless stated otherwise, all attributes altering routines
affect the appearance or geometry of the object immediately if the
object is visible.

Since the object class and type of an object can't be changed anymore
once an object has been created there are only functions for querying
these attributes:
@findex fl_get_object_objclass()
@anchor{fl_get_object_objclass()}
@findex fl_get_object_type()
@anchor{fl_get_object_type()}
@example
int fl_get_object_objclass(FL_OBJECT *obj);
int fl_get_object_type(FL_OBJECT *obj);
@end example
@noindent
Receiving a negative value indicates that a @code{NULL} pointer
was passed to the functions.


To set the two colors that influence the appearance of the object use
@findex fl_set_object_color()
@anchor{fl_set_object_color()}
@example
void fl_set_object_color(FL_OBJECT *obj, FL_COLOR col1, FL_COLOR col2);
@end example
@noindent
and to find out about the colors of an object use
@findex fl_get_object_color()
@anchor{fl_get_object_color()}
@example
void fl_get_object_color(FL_OBJECT *obj,
                         FL_COLOR *col1, FL_COLOR *col2);
@end example


@findex fl_set_object_boxtype()
@anchor{fl_set_object_boxtype()}
@example
void fl_set_object_boxtype(FL_OBJECT *obj, int boxtype);
@end example
@noindent
Changes the shape of the box of the object. Please note that not all
possible boxtypes are suitable for all types of objects, see the
documentation for the different objects for limitations.


To find out the current boxtype of an object use
@findex fl_get_object_boxtype()
@anchor{fl_get_object_boxtype()}
@example
int fl_get_object_boxtype(FL_OBJECT *obj);
@end example
@noindent
Receiving a negative value indicates that a @code{NULL} pointer
was passed to the function.


There are also functions to change or query the border width of an object:
@findex fl_set_object_bw()
@anchor{fl_set_object_bw()}
@findex fl_get_object_bw()
@anchor{fl_get_object_bw()}
@example
void fl_set_object_bw(FL_OBJECT *obj, int bw);
void fl_get_object_bw(FL_OBJECT *obj, int *bw);
@end example
@noindent
If the requested border width is 0, -1 is used.


To change or inquire the objects position (relative to the form it
belongs to) the functions
@findex fl_set_object_position()
@anchor{fl_set_object_position()}
@findex fl_get_object_position()
@anchor{fl_get_object_position()}
@example
void fl_set_object_position(FL_OBJECT *obj, FL_Coord x, FL_Coord y);
void fl_get_object_position(FL_OBJECT *obj, FL_Coord *x, FL_Coord *y);
@end example
@noindent
exist. If the object is visible it's redrawn at the new position.

To change or inquire the size of an object use
@findex fl_set_object_size()
@anchor{fl_set_object_size()}
@findex fl_get_object_size()
@anchor{fl_get_object_size()}
@example
void fl_set_object_size(FL_OBJECT *obj, FL_Coord w, FL_Coord h);
void fl_get_object_size(FL_OBJECT *obj, FL_Coord *w, FL_Coord *h);
@end example
@noindent
When changing th size the position of the upper left hand corner of
the object remains unchanged.

To set or query both the position and size of an object the
functions
@findex fl_set_object_geometry()
@anchor{fl_set_object_geometry()}
@findex fl_get_object_geometry()
@anchor{fl_get_object_geometry()}
@example
void fl_set_object_geometry(FL_OBJECT *obj, FL_Coord x, FL_Coord y,
                            FL_Coord w, FL_Coord h);
void fl_get_object_geometry(FL_OBJECT *obj, FL_Coord *x, FL_Coord *y,
                            FL_Coord (*w, FL_Coord *h);
@end example
@noindent
can be used.

Please note: always use one of the above functions to change the
position and/or size of an object and don't try to change the
information stored in the object directly. There's some double
bookkeeping going on under the hood that makes sure that the objects
position and size won't change due to rounding errors when the
whole form gets resized and changing the internal information kept in
the objects structure would interfer with this.

There's a second function for calculation an objects geometry:
@findex fl_get_object_bbox()
@anchor{fl_get_object_bbox()}
@example
void fl_get_object_bbox(FL_OBJECT *obj, FL_Coord *x, FL_Coord *y,
                        FL_Coord *w, FL_Coord *h);
@end example
@noindent
The difference between this functions and
@code{@ref{fl_get_object_geometry()}} is that
@code{@ref{fl_get_object_bbox()}} returns the bounding box size that
has the label, which could be drawn outside of the object figured in.

Some objects in the library are composite objects that consist of
other objects. For example, the scrollbar object is made of a slider
and two scroll buttons. To get a handle to one of the components of
the composite object, the following routine is available:
@findex fl_get_object_component()
@anchor{fl_get_object_component()}
@example
FL_OBJECT *fl_get_object_component(FL_OBJECT *obj, int objclass,
                                   int type, int number);
@end example
@noindent
where @code{obj} is the composite object, @code{objclass} and
@code{type} are the component object's class ID and type; and
@code{number} is the sequence number of the desired object in case the
composite has more than one object of the same class and type. You can
use a constant -1 for @code{type} to indicate any type of class
@code{objclass}. The function returns the object handle if the
requested object is found, otherwise @code{NULL}. For example to
obtain the object handle to the horizontal scrollbar in a browser,
code similiar to the following can be used
@example
hscrollbar = fl_get_object_component(browser, FL_SCROLLBAR,
                                     FL_HOR_THIN_SCROLLBAR, 0)
@end example

To influence change the color, font size, font style, alignment and
text of the label of an object use
@findex fl_set_object_lcol()
@anchor{fl_set_object_lcol()}
@findex fl_set_object_lsize()
@anchor{fl_set_object_lsize()}
@findex fl_set_object_lstyle()
@anchor{fl_set_object_lstyle()}
@findex fl_set_object_lalign()
@anchor{fl_set_object_lalign()}
@findex fl_set_object_label()
@anchor{fl_set_object_label()}
@example
void fl_set_object_lcol(FL_OBJECT *obj, FL_COLOR 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);
@end example

To find out about the object labels color, font size, style, alignment
and the string itself use
@findex fl_get_object_lcol()
@anchor{fl_get_object_lcol()}
@findex fl_get_object_lsize()
@anchor{fl_get_object_lsize()}
@findex fl_get_object_lstyle()
@anchor{fl_get_object_lstyle()}
@findex fl_get_object_lalign()
@anchor{fl_get_object_lalign()}
@findex fl_get_object_label()
@anchor{fl_get_object_label()}
@example
FL_COLOR fl_get_object_lcol(FL_OBJECT *obj);
int fl_get_object_lsize(FL_OBJECT *obj);
int fl_get_object_lstyle(FL_OBJECT *obj);
int fl_get_object_lalign(FL_OBJECT *obj);
const char * fl_get_object_label(FL_OBJECT *obj);
@end example

To set a tool-tip text for an object use the following routine
@findex fl_set_object_helper()
@anchor{fl_set_object_helper()}
@example
void fl_set_object_helper(FL_OBJECT *obj, const char *helpmsg);
@end example
@noindent
where @code{helpmsg} is a text string (with possible embedded newlines
in it) that will be shown when the mouse hovers over the object for
nore than about @w{600 msec}. A copy of the string is made internally.

The boxtype, color and font for the tool-tip message displayed can be
customized further using the following routines:
@findex fl_set_tooltip_boxtype()
@anchor{fl_set_tooltip_boxtype()}
@findex fl_set_tooltip_color()
@anchor{fl_set_tooltip_color()}
@findex fl_set_tooltip_font()
@anchor{fl_set_tooltip_font()}
@example
void fl_set_tooltip_boxtype(int boxtype);
void fl_set_tooltip_color(FL_COLOR textcolor, FL_COLOR background);
void fl_set_tooltip_font(int style, int size);
@end example
@noindent
where @code{boxtype} is the backface of the form that displays the
text. The default is @code{FL_BORDER_BOX}. @code{textcolor} and
@code{background} specify the color of the text and the color of the
backface. The defaults for these are @code{FL_BLACK} and
@code{FL_YELLOW}. @code{style} and @code{size} are the font style and
size of the text.

There are four function for controlling how an object reacts to
resizing the form it belongs to or to find out what its current
settings are:
@findex fl_set_object_resize()
@anchor{fl_set_object_resize()}
@findex fl_get_object_resize()
@anchor{fl_get_object_resize()}
@findex fl_set_object_gravity()
@anchor{fl_set_object_gravity()}
@findex fl_get_object_gravity()
@anchor{fl_get_object_gravity()}
@example
void fl_set_object_resize(FL_OBJECT *obj, unsigned int howresize);
void fl_get_object_resize(FL_OBJECT *obj, unsigned int *howresize);
void fl_set_object_gravity(FL_OBJECT *obj, unsigned int NWgravity,
                           unsigned int SEgravity);
void fl_get_object_gravity(FL_OBJECT *obj, unsigned int *NWgravity,
                           unsigned int *SEgravity);
@end example
@noindent
@xref{Part I Doing Interaction, , Doing Interaction}, for more details
on the resizing behaviour of objects.

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 of the two functions
@findex fl_freeze_form()
@anchor{fl_freeze_form()}
@findex fl_unfreeze_form()
@anchor{fl_unfreeze_form()}
@example
void fl_freeze_form(FL_FORM *form);
void fl_unfreeze_form(FL_FORM *form);
@end example

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 @code{FL_STEP} event,
use the following routine
@findex fl_set_object_automatic()
@anchor{fl_set_object_automatic()}
@example
void fl_set_object_automatic(FL_OBJECT *obj, int yes);
@end example

To determine if an object receives @code{FL_STEP} events use
@findex fl_object_is_automatic()
@anchor{fl_object_is_automatic()}
@example
int fl_object_is_automatic(FL_OBJECT *obj);
@end example

To enable or disable an object to receive the FL_DBLCLICK event use
the following routine
@findex fl_set_object_dblclick()
@anchor{fl_set_object_dblclick()}
@example
void fl_set_object_dblclick(FL_OBJECT *obj, unsigned long timeout);
@end example
@noindent
where @code{timeout} specifies the maximum time interval (in msec)
between two clicks for them to be considered a double-click (using 0
disables double-click detection). To determine the current setting
of the timeout use
@findex fl_get_object_dblclick()
@anchor{fl_get_object_dblclick()}
@example
unsigned fl_get_object_dblclick(FL_OBJECT *obj);
@end example

To make an object or a group invisible or visible use the following
two functions
@findex fl_hide_object()
@anchor{fl_hide_object()}
@findex fl_show_object()
@anchor{fl_show_object()}
@example
void fl_hide_object(FL_OBJECT *obj);
void fl_show_object(FL_OBJECT *obj);
@end example
@noindent
@code{obj} can be the pseudo-object returned by
@code{@ref{fl_bgn_group()}} and then allows to hide or show whole
groups of objects.

To determine if an object is visible (given that the form it belongs
to is also visible) use
@findex fl_object_is_visible()
@anchor{fl_object_is_visible()}
@example
int fl_object_is_visible(FL_OBJECT *obj);
@end example

@findex fl_trigger_object()
@anchor{fl_trigger_object()}
@example
void fl_trigger_object(FL_OBJECT *obj);
@end example
@noindent
returns @code{obj} to the application program after calling its
callback if one exists.

@findex fl_set_focus_object()
@anchor{fl_set_focus_object()}
@example
void fl_set_focus_object(FL_FORM *form, FL_OBJECT *obj);
@end example
@noindent
sets the input focus in form @code{form} to object @code{obj}. Note
however, if this routine is used as a response to an @code{FL_UNFOCUS}
event, i.e., as an attempt to override the focus assignment by the
main loop from within an objects 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 the @code{FL_UNFOCUS} event the following routine
should be used:
@findex fl_reset_focus_object()
@anchor{fl_reset_focus_object()}
@example
void fl_reset_focus_object(FL_OBJECT *obj);
@end example

Use the following routine to obtain the object that has the focus on a
form
@findex fl_get_focus_object()
@anchor{fl_get_focus_object()}
@example
FL_OBJECT *fl_get_focus_object(FL_FORM *form);
@end example

The routine
@findex fl_set_object_callback()
@anchor{fl_set_object_callback()}
@example
void fl_set_object_callback(FL_OBJECT *obj,
                            void (*callback)(FL_OBJECT *, long),
                            long argument);
@end example
@noindent
binds a callback routine to an object.

 To invoke the callback manually (as opposed to invocation by the main
loop), use the following function
@findex fl_call_object_callback()
@anchor{fl_call_object_callback()}
@example
void fl_call_object_callback(FL_OBJECT *obj);
@end example
@noindent
If the object @code{obj} does not have a callback associated with it,
this call has not effect.

@findex fl_set_form_callback()
@anchor{fl_set_form_callback()}
@example
void fl_set_form_callback(FL_FORM *form,
                          void (*callback)(FL_OBJECT *, void *),
                          void *data);
@end example
@noindent
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.
@findex fl_last_event()
@anchor{fl_last_event()}
@example
const XEvent *fl_last_event(void);
@end example
@noindent

Sometimes, it may be desirable to obtain hardcopies of some objects
in a what-you-see-is-what-you-get (WYSISYG) way, especially those that
are dynamic and of vector-graphics in nature. To this end, the
following routine exists:
@findex fl_object_ps_dump()
@anchor{fl_object_ps_dump()}
@example
int fl_object_ps_dump(FL_OBJECT *obj, const char *fname);
@end example
@noindent
The function will output the specified object in PostScript. If
@code{fname} is @code{NULL}, a fselector will be shown to ask the user
for a file name. The function returns a negative number if no output
is generated due to errors. At the moment, only the @code{FL_XYPLOT}
object is supported.

The object must be visible at the time of the function call. The
hardcopy should mostly be WYSIWYG and centered on the printed page.
The orientation is determined such that a balanced margin results,
i.e., if the width of the object is larger than the height, landscape
mode will be used. Further, if the object is too big to fit on the
printed page, a scale factor will be applied so the object fits. The
box underneath the object is by default not drawn and in the default
black&white mode, all curves are drawn in black. See demo program
@file{xyplotover.c} for an example output.

It is possible to customize the output by changing the PostScript
output control parameters via the function
@findex flps_init()
@anchor{flps_init()}
@tindex FLPS_CONTROL
@example
FLPS_CONTROL *flps_init(void);
@end example
@noindent
A typical use is to call this routine to obtain a handle to the
PostScript output control structure and change the control structure
members to suit your needs before calling
@code{@ref{fl_object_ps_dump()}}. You should not free the returned
buffer.

The control structure has the following members
@table @code
@item int ps_color
The choices are full color (@code{FLPS_COLOR}), grayscale
(@code{FLPS_GRAYSCALE}) and black&white (@code{FLPS_BW}). The default
for xyplot is black and white. In this mode, all drawings are black,
on a white background. If @code{drawbox} (see below) is true, the
drawing color can be either white or black depending on the specified
color.

@item int orientation
Valid choices are @code{FLPS_AUTO}, @code{FLPS_PORTRAIT} and
@code{FLPS_LANDSCAPE}. The default is @code{FLPS_AUTO}.

@item auto_fit
By default, this is true so the object always fits the printed page.
Set it to false (0) to turn off auto-scaling.

@item int eps
Set this to 1 if output in EPS format is required.

@item int drawbox
Set this to 1 if the box of the object is to be drawn.

@item float xdpi, ydpi
These two are the screen resolution. The default is to use the actual
resolution of the display. Note by setting a dpi number smaller or
larger than the actual resolution, the output object is in effect
being enlarged or shrunken.

@item float paper_w
The paper width in inches. The default is @w{8.5 in}.

@item float paper_h
The paper height in inches. The default is @w{11 in}.
@end table

To generate a PostScript output of a form or forms, use the
@code{fd2ps} program documented in @ref{Part II Generating Hardcopies}.


@node Doing Interaction
@section Doing Interaction


To display the form @code{form} on the screen use
@findex fl_show_form()
@anchor{fl_show_form()}
@example
Window fl_show_form(FL_FORM *form, int place, int border,
                    const char *title);
@end example
@noindent
@code{place} controls the position and size of the form. @code{border}
indicates whether a border (window manager's decoration) should be
drawn around the form. If a border is to be drawn @code{title} is the
name of the window (and its associated icon). The routine returns the
window identifier of the form. For resource and identification
purposes, the form name is taken to be the title with spaces removed
and the first character lower-cased. E.g., if a form has a title
@w{@code{"Foo Bar}} the forms name is derived as @code{"fooBar"}.

For the the location and size of the window controlled by @code{place}
the following possibilities exist:
@table @code
@tindex FL_PLACE_SIZE
@item FL_PLACE_SIZE
The user can control the position but the size is fixed. Interactive
resizing is not allowed once the form becomes visible.

@tindex FL_PLACE_POSITION
@item FL_PLACE_POSITION
Initial position used will be the one set via
@code{@ref{fl_set_form_position()}}. Interactive resizing is allowed.

@tindex FL_PLACE GEOMETRY
@item FL_PLACE GEOMETRY
Place at the latest position and size (see also below) or the geometry
set via @code{@ref{fl_set_form_geometry()}} etc. A form so shown will
have a fixed size and interactive resizing is not allowed.

@tindex FL_PLACE_ASPECT
@item FL_PLACE_ASPECT
Allows interactive resizing but any new size will have the aspect ratio
as that of the initial size.

@tindex FL_PLACE_MOUSE
@item FL_PLACE_MOUSE
The form is placed centered below the mouse. Interactive resizing will
not be allowed unless this option is accompanied by
@code{@ref{FL_FREE_SIZE}} as in
@code{@ref{FL_PLACE_MOUSE}|@ref{FL_FREE_SIZE}}.

@tindex FL_PLACE_CENTER
@item FL_PLACE_CENTER
The form is placed in the center of the screen. If
@code{@ref{FL_FREE_SIZE}} is also specified, interactive resizing will
be allowed.

@tindex FL_PLACE_FULLSCREEN
@item FL_PLACE_FULLSCREEN
The form is scaled to cover the full screen. If
@code{@ref{FL_FREE_SIZE}} is also specified, interative resizing will
be allowed.

@tindex FL_PLACE_FREE
@item FL_PLACE_FREE
Both the position and size are completely free. The initial size used
is the designed size. Initial position, if set via
@code{@ref{fl_set_form_position()}}, will be used, otherwise
interactive positioning may be possible if the window manager allows
it.

@tindex FL_PLACE_HOTSPOT
@item FL_PLACE_HOTSPOT
The form is so placed that mouse is on the "hotspot". If
@code{@ref{FL_FREE_SIZE}} is also specified, interactive resizing will
be allowed.

@tindex FL_PLACE_CENTERFREE
@item FL_PLACE_CENTERFREE
Same as @code{@ref{FL_PLACE_CENTER}|@ref{FL_FREE_SIZE}}, i.e., place
the form at the center of the screen and allow resizing.

@tindex FL_PLACE ICONIC
@item FL_PLACE ICONIC
The form is shown initially iconified. The size and location used are
the window manager's default.
@end table

If no size is specified, the designed (or later scaled) size will be
used. Note that the initial position is dependent upon the window
manager used. Some window managers will allow interactive placement of
the windows and some will not.

There are three values that can be passed for @code{border}:
@table @code
@tindex FL_FULLBORDER
@item FL_FULLBORDER
Draw full border with title

@tindex FL_TRANSIENT
@item FL_TRANSIENT
Draw borders with possibly less decoration (depends on the window
managers behaviour)

@tindex FL_NOBORDER
@item FL_NOBORDER
Draw no border at all
@end table

Since multiple forms can be displayed at the same time note that using
@code{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 @code{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 @code{FL_TRANSIENT} is preferable. Also note that you
can't iconify a form that has no borders and under most window
managers forms displayed with @code{FL_TRANSIENT} can't be iconified
either.

One 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
@findex fl_set_app_mainform()
@anchor{fl_set_app_mainform()}
@example
void fl_set_app_mainform(FL_FORM *form);
@end example
@noindent
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
@findex fl_get_app_mainform()
@anchor{fl_get_app_mainform()}
@example
FL_FORM *fl_get_app_mainform(void);
@end example

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 (must be called before any full-bordered
form is shown):
@findex fl_set_app_nomainform()
@anchor{fl_set_app_nomainform()}
@example
void fl_set_app_nomainform(int yes);
@end example
@noindent
with a true flag.

All visible forms will have the properties @code{WM_CLASS},
@code{WM_CLIENT_MACHINE} and @code{WM_NAME} set. In addition, the
first full-bordered form will have the @code{WM_COMMAND} property set
and is by default the applications main form.

Sometimes it is necessary to have access to the window resource ID
before the window is mapped (shown). For this, the following routine
can be used
@findex fl_prepare_form_window()
@anchor{fl_prepare_form_window()}
@example
Window fl_prepare_form_window(FL_FORM *form, int place, int border,
const char *name);
@end example
@noindent
This routine creates a window that obeys any and all constraints just
as @code{@ref{fl_show_form()}} does but remains unmapped. To map such
a window, the following must be used
@findex fl_show_form_window()
@anchor{fl_show_form_window()}
@example
Window fl_show_form_window(FL_FORM *form);
@end example
@noindent
Between these two calls, the application program has full access to
the window and can set all attributes, such as icon pixmaps etc., that
are not set by @code{@ref{fl_show_form()}}.

The application program can raise a form to the top of the screen so
no other forms obscures it by calling
@findex fl_raise_form()
@anchor{fl_raise_form()}
@example
void fl_raise_form(FL_FORM *form);
@end example

To instead lower a form to the bottom of the stack use
@findex fl_lower_form()
@anchor{fl_lower_form()}
@example
void fl_lower_form(FL_FORM *form);
@end example

When placing a form on the screen using @code{FL_PLACE_GEOMETRY} for
the @code{place} argument to @code{@ref{fl_show_form()}} the position
and size can be set before by using the routines
@findex fl_set_form_position()
@anchor{fl_set_form_position()}
@findex fl_set_form_size()
@anchor{fl_set_form_size()}
@findex fl_set_form_geometry()
@anchor{fl_set_form_geometry()}
@findex fl_scale_form()
@anchor{fl_scale_form()}
@example
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_set_form_geometry(FL_FORM form*, FL_Coord x, FL_Coord y,
                          FL_Coord w, FL_Coord h);
void fl_scale_form(FL_FORM *form, double xsc, double ysc);
@end example
@noindent
where @code{@ref{fl_set_form_geometry()}} combines the functionality
of @code{@ref{fl_set_form_position()}} and
@code{@ref{fl_set_form_size()}} and the last routine,
@code{@ref{fl_scale_form()}}, scales the form in horizontal and
vertical direction by the factors passed to the function. These
routines can also be used when the form is visible.

Sometimes it is desirable to know how large the decoration are the
window manager puts around a forms window. They can be obtained by a
call of
@findex fl_get_decoration_sizes()
@anchor{fl_get_decoration_sizes()}
@example
void fl_get_decoration_sizes(FL_FORM *form, int *top, int *right,
                             int *bottom, int *left);
@end example
@noindent
This is especially useful if it is necessary to open a window at some
previously stored position since in that case one needs the position
of of the window, which deviates from the position reported for the
form by the window manager's decorations. Obviously, the above
function can't be used for forms that are embedded into another form.

The function
@findex fl_form_is_isconified()
@anchor{fl_form_is_isconified()}
@example
int fl_form_is_isconified(FL_FORM *form);
@end example
@noindent
allows to test if the (visible) window of a form is in iconified
state.

If interactive resizing is allowed (e.g., by showing the form with
@code{@ref{FL_PLACE_POSITION}}) it can be useful to limit the range of
the size of a form can take. To this end, the following functions are
available
@findex fl_set_form_minsize()
@anchor{fl_set_form_minsize()}
@findex fl_set_form_maxsize()
@anchor{fl_set_form_maxsize()}
@example
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);
@end example

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 the constraints only apply to the next call
of @code{@ref{fl_show_form()}} for the form.

To set or change the icon shown when a form is iconified use the
following routine
@findex fl_set_form_icon()
@anchor{fl_set_form_icon()}
@example
void fl_set_form_icon(FL_FORM *form, Pixmap icon, Pixmap mask);
@end example
@noindent
where @code{icon} can be any valid pixmap ID. (@xref{Pixmap Object},
for some of the routines that can be used to create pixmaps.) Note
that a previously set icon if not freed or modified in anyway.

If, for any reason, you would like to change the form title after the
form has been made visible, the following call can be used (this will
also change the icon title)
@findex fl_set_form_title()
@anchor{fl_set_form_title()}
@example
void fl_set_form_title(FL_FORM *form, const char *name);
@end example

The routine
@findex fl_hide_form()
@anchor{fl_hide_form()}
@example
void fl_hide_form(FL_FORM *form);
@end example
@noindent
hides the particular form, i.e., closes its window and all subwindows.

To check if a form is visible or not, the following function can be used
@findex fl_form_is_visible()
@anchor{fl_form_is_visible()}
@example
int fl_form_is_visible(FL_FORM *form)'
@end example
@noindent
The function can return that the form is visible
(@code{@ref{FL_VISIBLE}}), is invisible (@code{@code{FL_INSIBILE}}) or
in the processing of becoming invisible
(@code{@ref{FL_BEING_HIDDEN}}).

The most important function for doing the actual interaction with forms
is
@anchor{fl_do_forms()}
@findex fl_do_forms()
@example
FL_OBJECT *fl_do_forms(void);
@end example
@noindent
It starts the main loop of the program and returns only when the state
of an object changes that has no callback bound to it. A pointer to
this object is then returned.

A second way of doing interaction with the currently displayed forms
is using
@anchor{fl_check_forms()}
@findex fl_check_forms()
@example
FL_OBJECT *fl_check_forms(void);
@end example
@noindent
This routine returns @code{NULL} immediately unless the state of one
of the object (without a callback bound to it) changed. In that case a
pointer to this object gets returned.

Then there are two more functions:
@anchor{fl_do_only_forms()}
@findex fl_do_only_forms()
@anchor{fl_check_only_forms()}
@findex fl_check_only_forms()
@example
FL_OBJECT *fl_do_only_forms(void);
FL_OBJECT *fl_check_only_forms(void);
@end example
@noindent
Both functions do the same as @code{@ref{fl_do_forms()}} and
@code{@ref{fl_check_forms()}} except that they do not handle user
events generated by application windows opened via
@code{@ref{fl_winopen()}} or similar routines.

To activate or deactivate a form for user interaction you can use
@findex fl_activate_form()
@anchor{fl_activate_form()}
@findex fl_deactivate_form()
@anchor{fl_deactivate_form()}
@example
void fl_activate_form(FL_FORM *form);
void fl_deactivate_form(FL_FORM *form);
@end example

The same can also be done for all forms at once using
@findex fl_deactivate_all_forms()
@anchor{fl_deactivate_all_forms()}
@findex fl_activate_all_forms()
@anchor{fl_activate_all_forms()}
@example
void fl_deactivate_all_forms(void)
void fl_activate_all_forms(void)
@end example

You can also register callbacks for a form that are invoked whenever
the activation status of the form is changed:
@tindex FL_FORM_ATACTIVATE
@tindex FL_FORM_ATDEACTIVATE
@findex fl_set_form_atactivate()
@anchor{fl_set_form_atactivate()}
@findex fl_set_form_atdeactivate()
@anchor{fl_set_form_atdeactivate()}
@example
typedef void (*FL_FORM_ATACTIVATE)(FL_FORM *, void *);
FL_FORM_ACTIVATE fl_set_form_atactivate(FL_FORM *form,
                                        FL_FORM_ATACTIVATE callback,
                                        void *data);

typedef void (*FL_FORM_ATDEACTIVATE)(FL_FORM *, void *);
FL_FORM_ACTIVATE fl_set_form_atdeactivate(FL_FORM *form,
                                          FL_FORM_ATACTIVATE callback,
                                          void *data);
@end example

Also individual objects (or groups of objects if the argument of the
function is an object returned by @code{@ref{fl_bgn_group()}}) can be
activated and deactivated to enable or disable user interaction:
@findex fl_activate_object()
@anchor{fl_activate_object()}
@findex fl_deactivate_object()
@anchor{fl_deactivate_object()}
@example
void fl_activate_object(FL_OBJECT *obj);
void fl_deactivate_object(FL_OBJECT *obj);
@end example
@noindent
It is normally useful to give the user a visual clue when an object
gets deactivated, e.g., by graying out its label etc.

To find out if an object is active use
@findex fl_object_is_active()
@anchor{fl_object_is_active()}
@example
int fl_object_is_active(FL_OBJECT *obj);
@end example

@findex fl_redraw_object()
@anchor{fl_redraw_object()}
@example
void fl_redraw_object(FL_OBJECT *obj);
@end example
@noindent
This routine redraws the particular object. If @code{obj} is a group
it redraws the complete group. Normally you should never need this
routine because all library routines take care of redrawing objects
when necessary, but there might be situations in which an explicit
redraw is required.

To redraw an entire form use
@findex fl_redraw_form()
@anchor{fl_redraw_form()}
@example
void fl_redraw_form(FL_FORM *form);
@end example

For non-form windows, i.e., those created with
@code{@ref{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. @xref{Windowing Support}, for details.)

You may set up a callback routine for all user events using
@findex fl_set_event_callback()
@anchor{fl_set_event_callback()}
@example
FL_APPEVENT_CB fl_set_event_callback(int (*callback)(XEvent *ev, void *data),
                                     void *data);
@end example

It is also possible to set up callback functions on a per window/event
basis using the following routines:
@tindex FL_APPEVENT_CB
@findex fl_add_event_callback()
@anchor{fl_add_event_callback()}
@findex fl_remove_event_callback()
@anchor{fl_remove_event_callback()}
@example
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);
@end example
@noindent
These functions manipulate the event callback functions for the window
specified, which will be called when an event of type
@code{xevent_type} is pending for the window. If @code{xevent_type} is
0 it signifies a callback for all event for window @code{win}. Note
that the Forms Library does not solicit any event for the caller,
i.e.@: the Forms Library assumes the caller opens the window and
solicits all events before calling these routines.

To let the Forms Library handle event solicitation, the following
function may be used
@findex fl_activate_event_callbacks()
@anchor{fl_activate_event_callbacks()}
@example
void fl_activate_event_callbacks(Window win);
@end example


@node Signals
@section Signals

Typically, when a signal is delivered, the application does not know
what state the application is in, thus limiting the tasks a signal
handler can do. In a GUI system and with a main loop inside the
library, it's even harder to know what's safe or unsafe to do in a
signal handler. Given all these difficulties, the Forms Library's main
loop is made to be aware of signal activities and invoke signal
handlers only when it's appropriate to do so, thus removing most
limitations on what a signal handler can do.

The application program can elect to handle the receipt of a signal by
registering a callback function that gets called when a signal is
caught
@tindex FL_SIGNAL_HANDLER
@findex fl_add_signal_callback()
@anchor{fl_add_signal_callback()}
@example
typedef void (*FL_SIGNAL_HANDLER)(int, void *);

void fl_add_signal_callback(int signal, FL_SIGNAL_HANDLER sh,
                            void *data);
@end example

Only one callback per signal is permitted. By default,
@code{@ref{fl_add_signal_callback()}} will store the callback function
and initiate a 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 of XForms's functions as
well as Xlib functions as if they were reentrant. Further, a signal
callback registered his way 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 signals, a code fragment
similar to the following can be used:
@example
void clean_up(int signum, void *data) @{
    /* clean up, of course */
@}

/* call this somewhere after fl_initialize() */
fl_add_signal_callback(SIGINT, clean_up, &mydata);
@end example
@noindent
After this, whenever a @code{SIGINT} signal is received,
@code{clean_up()} is called.

To remove a signal callback, the following routine should be used
@findex fl_remove_signal_callback()
@anchor{fl_remove_signal_callback()}
@example
void fl_remove_signal_callback(int signal);
@end example

Although very easy to use, 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 @code{@ref{fl_add_signal_callback()}} prevents the application
program from using any, potentially more flexible, system signal
handling routines on some platforms. Also there might be perceptible
delays from the time a signal is delivered by the OS and the time its
callback is invoked by XForms' main loop. This delay can be particular
troublesome for timing sensitive tasks (playing music for example).

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 (@code{sigaction()} for
example).

To change the default behavior of the built-in signal facilities, the
following routine should be called prior to any use of
@code{fl_add_signal_callback(}) with a true value for @code{flag}:
@findex fl_app_signal_direct()
@anchor{fl_app_signal_direct()}
@example
void fl_app_signal_direct(int flag);
@end example
@noindent
After this call @code{@ref{fl_add_signal_callback()}} will not
initiate any actions to receive a signal. The application program
should handle the receipt and blocking of signals (via e.g.,
@code{signal(2)}, @code{sigaction(2)}, @code{sigprocmask(2}) 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 @code{signum}, possibly after performing some timing sensitive
tasks:
@findex fl_signal_caught()
@anchor{fl_signal_caught()}
@example
void fl_signal_caught(int signum);
@end example
@noindent
This routine is the only one in the library that can be safely called
from within a direct application signal handler. If multiple
invocations of @code{@ref{fl_signal_caught()}} occur before the main
loop is able to call the registered callback, the callback is called
only once.

The following example illustrates how to handle a timing critical
situation (for most application, idle callback, timeouts or
@code{FL_TIMER} object should be sufficient).

First, you need to define the function that will handle the timing
critical tasks. The function will be registered with the OS to be
invoked directly by it. There are limitations on what you can do
within a (OS) signal handler, in particular, GUI activity is not safe.
@example
void timing_critical_task(int sig) @{
    /* handle timing critical tasks that does not involve GUI */
    ...
    /* Now tell the library the signal has been delivered by the OS.
     * The library will invoke the xforms signal handler when it's
     * appropriate to do so */
    fl_signal_caught(sig);
@}
@end example
@noindent
Now define a (XForms) signal handler that will be responsible for
handling the response of the GUI upon receipt of the signal
@example
void gui_signal_handler(int sig, void *data) @{
    /* within an XForms signal handler, there is no limitation
     * on GUI activitity */
    fl_set_object_color(....);
    ...
@}
@end example

To make all this work, a set-up similar to the following can be used
@example
/* setup the signal */
fl_app_signal_direct(1);
setitimer(ITIMER_REAL, interval);

/* setup the OS signal handler */
signal(SIGALRM, timing_critical_tasks);

/* setup the XForms signal handler */
fl_add_signal_callback(SIGALRM, gui_signal_handler, &myData);
@end example


@node Idle Callbacks and Timeouts
@section Idle Callbacks and Timeouts

For application programs that need to perform some light, but
semi-continuous or periodic tasks, idle callback and timeouts (also
@code{FL_TIMER} objects) can be utilized.

To register an idle callback with the system, use the following routine
@tindex FL_APPEVENT_CB
@findex fl_set_idle_callback()
@anchor{fl_set_idle_callback()}
@example
typedef int (*FL_APPEVENT_CB)(XEvent *, void *);
FL_APPEVENT_CB fl_set_idle_callback(FL_APPEVENT_CB callback,
                                    void *user_data);
@end example
@noindent
where @code{callback} is the function that will get called whenever
the main loop is idle. The time interval between invocations of the
idle callback can vary considerably depending on interface activity
and other factors. A range between 50 and @w{300 msec} should be
expected.

It is possible to change what the library considers to be "idle" with
the following function:
@findex fl_set_idle_delta()
@anchor{fl_set_idle_delta()}
@example
void fl_set_idle_delta(long msec);
@end example
@noindent
Here @code{msec} is the minimum time interval of inactivity after
which the main loop is considered to be in an idle state. 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. The precision of timeouts tends to be
quite a bit better than that of idle callbacks since they internally
get prefered treatent. To register a timeout callback, the following
routine can be used
@tindex FL_TIMEOUT_CALLBACK
@findex fl_add_timeout()
@anchor{fl_add_timeout()}
@example
typedef void (*FL_TIMEOUT_CALLBACK)(int, void *);
int fl_add_timeout(long msec, FL_TIMEOUT_CALLBACK callback,
                   void *data);
@end example
@noindent
The function returns the timeout ID (note: the function will not
return 0 and -1, so the application can use these values to mark
invalid or expired timeouts). When the time interval specified by the
@code{msec} argument (in milli-second) is elapsed, the timeout is
removed and the callback function is called with the timeout ID as the
first argument. Although a timeout offers some control over the
timing, due to performance and CPU load compromises, while the
resolution can be better than @w{10 ms} under favourable conditions,
it can also be much worse, occasionally up to @w{150 ms}.

To remove a timeout before it triggers, use the following routine
@findex fl_remove_timeout()
@anchor{fl_remove_timeout()}
@example
void fl_remove_timeout(int id);
@end example
@noindent
where @code{id} is the timeout ID returned by
@code{@ref{fl_add_timeout()}}. @xref{Timer Object}, for the usage of
@code{FL_TIMER} object. For tasks that need more accurate timing the
use of signal should be considered.
