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 | The major version number. |
FL_REVISION | Revision number. |
FL_INCLUDE_VERSION | Derived as FL_VERSION ![]() FL_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 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 prefered 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 scrollbarType | FL_PDScrollbarType | Scrollbar for browser and input |
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; |
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 resource or command line options. Note that
this function that not affect the popup border width, which
is controlled by fl_setpup_default_bw()
.
To change the default scrollbars (which are THIN_SCROLLBAR
s)
used in browser and input object, the following convenience function
can be used:
void fl_set_scrollbar_type(int type)
where type can be one of the following
which is equivalent to
FL_IOPT fl_cntl; fl_cntl.scrollbarType = type; fl_set_defaults(FL_PDScrollbarType, &fl_cntl);
It is recommended that this function be used before fl_initialize()
so the user has the option to override the default through
application resources.
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
'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 for objects having a non-rectangular box
might not work well. A non-rectangular 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 obj->dbl_background
after switching to double buffer.
Normally the Forms Library reports errors to stderr. This can be avoided or modified by registering an error handling function
void fl_set_error_handler(void (*user_handler) (const char *where, const char *fmt,...))
The library will call the user_handler
with a string
indicating where or which function an error occured, and a formatting
string (see sprintf3) followed by zero or more arguments.
To restore the default handler, set user_handler
to null.
You can call this function anytime or 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 stderr
void fl_set_error_logfp(FILE *fp)
For example, fl_set_error_logfp(fopen("/dev/null","w"))
turns off the default error reporting to stderr.
For some error messages, in addition to being printed to stderr, a dialog box will be shown that requires actions from the user. To turn this off and on, the following routine is available
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)
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, this function should be a no-op on the machine the forms are designed. 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.
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.
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.
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
FL_OBJECT *fl_get_object_component(FL_OBJECT *ob, int objclass, int type, int number)
where ob is the composite object; objclass and type are the component object's class ID and type; and 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 type to indicate any type of class objclass. Function returns the object handle if the requested object is found otherwise 0. For example, to obtain the object handle to the horizontail scrollbar in a browser, code similiar to the following can be used
hscrollbar = fl_get_object_component(browser, FL_SCROLLBAR, FL_HOR_THIN_SCROLLBAR, 0)
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)
where timeout (in milli-seconds) specifies the maximum time interval between two clicks to be considered a double-click (0 disables double-click detection).
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)
Use the following routine to obtain the object that has the focus on a form
FL_OBJECT *fl_get_focus_object(FL_FORM *form)
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)
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:
int fl_object_ps_dump(FL_OBJECT *ob, const char *fname);
The function will output the specified object in POSTSCRIPT.
If fname is null, the fselector will be called to prompt the file
name from the user. The function returns a negative number if no output is
generated due to error conditions. At the moment, only
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, the 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. Also the box underneath the object is by default no drawn and in the default black&white mode, all curves are drawn in black. See demo xyplotover.c for an example output.
It is possible to customerize the output by changing the postscript output control parameters via the following routine:
FLPS_CONTROL *flps_init(void)
The 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 need before calling fl_object_ps_dump()
. You should not
free the returned buffer.
The control structure has the following members
FLPS_COLOR
),
grayscale (FLPS_GRAYSCALE
),
and black&white (FLPS_BW
).
The default for xyplot is black and white.
In this mode, all drawings are black, on
a white background. If drawbox (see below)
is true, drawing color can be either white
or black depending on the specified color.
FLPS_AUTO
,
FLPS_PORTRAIT
and FLPS_LANDSCAPE
.
The default is FLPS_AUTO
.
To generate a POSTSCRIPT output of a form or forms, use the fd2ps program documented in Chapter 13.
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 and its associated icon if any. 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 15.5 and 15.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)
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 D
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_callbacks(Window win);
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), sigaction(2), 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 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.
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 timeout is removed, then the callback function is called. 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 21.1 for the
usage of FL_TIMER
object.
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.
To get the user name who is running the application, you can use the following routine
const char *fl_whoami(void)
To get a string form of the current date and time, the following routine is available:
const char *fl_now(void)
The format of the string is of the form Wed Jun 30 21:49:08 1993.
The following time related routine 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.
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.
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 | values |
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 | |
ulThickness | ULThickness | int | 1 | |
scrollbarType | ScrollbarType | string | thin | normal, thin, plain, nice |
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 application 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 programmatically
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 arbitrary 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 similar 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, ...);
Eventually 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 processing for a particular form, you can also do so for an object. Unlike in raw callbacks, you can not select individual events.
The mechanism 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 29.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 should 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 mechanism 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.
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)
.
When you (think you) encountered a bug in the XForms please report it by sending
a mail message to zhao@[bloch|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.