[ << ] | [ >> ] |  |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

# 32. 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.

## 32.1 Version Information

The header file ``forms.h`' defines three symbolic constants which you can use to conditionally compile your application. They are

`FL_VERSION`

  The major version number.

`FL_REVISION`

  Revision number.

`FL_INCLUDE_VERSION`

  `1000 * 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 `1000 * version + 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 versions less than 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.

## 32.2 Initialization

The routine

    Display *fl_initialize(int *argc, char *argv[], const char *appclass,
                           XrmOptionDescList app_opt, int n_app_opt);

initializes the Forms Library and returns a pointer to the `Display` structure if a connection could be made, otherwise `NULL`. This function must be called before any other calls to the Forms Library (except `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

`argc, argv`

  Number and array of the command line arguments the application was started with. The application name is derived from `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 `.` or a star `*`.

`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).

`app_opt`

  Specifies how to parse the application-specific resources.

`n_app_opt`

  Number of entries in the option list.

The `fl_initialize()` function builds the resource database, calls the Xlib `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 `XrmSetDatabase()`, so the application can get at it if necessary.

All recognized options are removed from the argument list and their corresponding values set. The XForms library provides appropriate defaults for all options. The following are recognized by the library:

Option | Type | Meaning | Default
`-fldebug` level | int | Print debug information | 0 (off)
`-name` appname | string | Change application name | none
`-flversion` |  | Print version of the library |
`-sync` |  | Synchronous X11 mode (debug) | false
`-display` host:dpy | string | Set (remote) host | `$DISPLAY`
`-visual` class | string | TrueColor, PseudoColor... | best
`-depth` depth | int | Set prefered visual depth | best
`-vid` id | long | Set prefered visual ID | 0
`-private` |  | Force use of private colormap | false
`-shared` |  | Force use of shared colormap | false
`-stdcmap` |  | Force use of standard colormap | false
`-double` |  | Enable double buffering for forms | false
`-bw` width | int | Set object border width | 1
`-rgamma` gamma | float | Set red gamma | 1.0
`-ggamma` gamma | float | Set green gamma | 1.0
`-bgamma` gamma | float | Set blue gamma | 1.0

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 `-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 `fl_initialize()` is called) via the function

    void fl_set_visualID(long id);

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 `-g` as a command line option to indicate geometry, it might not work as `-g` matches `-ggamma` in the absence of `-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. Older version of the library used a larger default for the border width of 3.

As mentioned the `fl_initialize()` function removes all the above listed values from the command line arguments, leaving you with a cleaned-up list. To get again at the complete list you can use the function

    char **fl_get_cmdline_args( int *arg_cnt );

returning a copy to the values from the original list and their number via the `arg_cnt` argument.

Depending on your application XForms defaults may or may not be appropriate. E.g., on machines capable of 24 bits visuals, Forms Library always selects the deeper 24 bits visual. If your application only uses a limited number of colors, it might be faster if a visual other than 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 `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.

The following table lists the fields, masks and their meanings of `FL_IOPT`:

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` | Prefered visual, `TrueColor` etc.
`int doubleBuffer;` | `FL_PDDouble` | Simulate double buffering
`int buttonFontSize;` | `FL_PDButtonFontSize` | Default button label font size
`int menuFontSize;` | `FL_PDMenuFontSize` | Menu label font size
`int choiceFontSize;` | `FL_PDChoiceFontSize` | Choice label and choice text font size
`int browserFontSize;` | `FL_PDBrowserFontSize` | Browser label and text font size
`int inputFontSize;` | `FL_PDInputFontSize` | Input label and text font size
`int labelFontSize;` | `FL_PDLabelFontSize` | Label font size for all other objects (box, pixmap etc.)
`int pupFontSize;` | `FL_PDPupFontSize` | Font size for pop-ups
`int privateColormap;` | `FL_PDPrivateMap` | Select private colormap if appropriate
`int sharedColormap;` | `FL_PDSharedMap` | Force use of shared colormap
`int standardColormap;` | `FL_PDStandardMap` | Force use of standard colormap
`int scrollbarType;` | `FL_PDScrollbarType` | Scrollbar type to use for browser and input
`int ulThickness;` | `FL_PDULThickness` | Underline thickness
`int ulPropWidth;` | `FL_PDULPropWidth` | Underline width, 0 for const. width fonts
`int backingStore;` | `FL_PDBS` | Turn BackingStore on or off
`int coordUnit;` | `FL_PDCoordUnit` | Unit of measure: pixel, mm, point
`int borderWidth;` | `FL_PDBorderWidth` | Default border width
`} FL IOPT;` |  |

A special visual designation, `FL_DefaultVisual` and a 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 an arbitrary name that is specified with the `-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

    int fl_get_coordunit(void);
    void fl_set_coordunit(int coordUnit);

`coordUnit` can have the following values: `FL_COORD_PIXEL`, `FL_COORD_POINT`, `FL_COORD_MM`, `FL_COORD_centiPOINT` and `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:

    int oldcoordUnit = fl_get_coordunit();
    fl_set_coordunit(FL_COORD_POINT);
    fl_bgn_form(...);    /* add more objects */
    fl_end_form();
    fl_set_coordunit(oldcoordunit);

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

    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()` is called so the user has the option to override the default via resource or command line options.

The cirrent setting of the borderwidth can also tested via

    int fl_get_border_width(void);

To change the default scrollbar type (which is `THIN_SCROLLBAR`) 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

`FL_NORMAL_SCROLLBAR`

  Basic scrollbar

`FL_THIN_SCROLLBAR`

  Thin scrollbar

`FL_NICE_SCROLLBAR`

  Nice scrollbar

`FL_PLAIN_SCROLLBAR`

  Similar to thin scrollbar, but not as fancy

Setting the scrollbar type before calling `fl_initialize()` 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 0.80 the origin of XForms' coordinate system was at the lower left-hand 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 `.fd` files or otherwise can't use a newer version of `fdesign`, a compatibility function is provided

    void fl_flip_yorigin(void);

Note however that this function must be called prior to `fl_initialize()` and is a no-op after that.

If this function has been called functions like `fl_get_object_position()` or `fl_get_object_bbox()`, reporting an objects positions and bounding box, will return `y`-coordinates in the old-fashioned coordinate system with the origin at the left bottom corner of the form. Similarly, the functions for setting or changing an objects position (`fl_set_object_position()` and `fl_move_object()`) then expect to receive arguments for the `y`-coordinates in this system. The `y`-coordinate stored in the object itself (i.e., `obj->y`) is always for the normal coordinate system with the origin at the top left corner.

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 `"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-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:

    void fl_set_form_dblbuffer(FL_FORM *form, int yes_no);
    void fl_set_object_dblbuffer(FL_OBJECT *obj, int yes_no);

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 pixmap 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` function with a string indicating in which function an error occured and a formatting string (see `sprintf()`) followed by zero or more arguments. To restore the default handler, call the function again with `user_handler` set to `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 `stderr`

    void fl_set_error_logfp(FILE *fp);

For example

    fl_set_error_logfp(fopen("/dev/null","w"));

redirects all error messages to ``/dev/null`', effectively turning off the default error reporting to `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

    void fl_show_errors(int show);

where `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 routines

    int fl_set_font_name(int n, const char *name);
    int fl_set_font_name_f(int n, const char *fmt, ,,,);

The first function just accepts a simple string while the second constructs the font name from a format string just as it's used for `printf()` etc. and the following arguments. The first argument, `n`, must be a number between 0 and `FL_MAXFONTS-1`. The function returns `0` on success, `1` if called before proper initialization of the library and `-1` for either invalid arguments (`name` or the result of the expansion of the format string doesn't name an available font, `n` negative or not less than `FL_MAXFONTS`). See section 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 10 pt font on a 75 DPI monitor will have the label overflow the button on a 100 DPI monitor. This comes about because a character of a 10 pt font when rendered with `75 DPI` resolution may have 10 pixels while the same character in the same 10 pt font with 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, 75 DPI and 100 DPI. Due to the variations in monitor resolutions, the theoretically identical sized font, say a 10 pt font, can vary in sizes (pixels) by up to 30%, depending on the server (rendering a font on a 80 DPI monitor will cause errors in sizes regardless if a 75 DPI or 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 90 DPI monitor using 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:

    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 compares it to the size of the object. Scaling factors are computed for all object labels that 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 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 `-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 has been established.

There is a similar function that works the same way, but on an object-by-object basis and further allows explicit margin specifications:

    void fl_fit_object_label(FL_OBJECT *obj, FL_Coord hm, FL_Coord vm);

where `hm` and `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 `FL_FREE_COL1` are used (or can potentially be used) by the Forms Library. If you wish they can be changed using the following function prior to `fl_initialize()`:

    void fl_set_icm_color(FL_COLOR index, int r, int g, int b);

Using this function you can actually change all entries in the internal colormap (with `index` going up to `FL_MAX_COLORS-1`). You may also inspect the internal colormap using

    void fl_get_icm_color(FL_COLOR index, int *r, int *g, int *b);

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 `fl_finish()` is called prior to exiting an application or register it via `atexit()`.

    void fl_finish(void);

In addition to restoring all server defaults, `fl_finish()` also shuts down the connection and frees dynamically allocated memory.

## 32.3 Creating Forms

To start the definition of a form call

    FL_FORM *fl_bgn_form(int type, FL_Coord w, FL_Coord h);

When the form is created it automatically acquires one object, a box object covering the full area of the form, which is used as the background of the form. The `type` argument is the type of this box object, so you can "style" the look of your forms (but don't use any non-rectangular box types). `w` and `h` are the width and height of the new form. The function returns a pointer to the new form.

Note: if you look at the code generated by `fdesign` for the creation of a form you may notice that the type of this automatically assigned box is `FL_NO_BOX` (which is invisible) and that for the background another box of the same size but a different (visible) type is added. This is because in `fdesign` the very first object can't be accessed and thus its properties can not be adjusted (like the box type or its color that then becomes the background color of the form). By using an extra box, which can be accessed from within `fdesign`, that problem is circumvented.

There also exist functions for setting and requesting the background color of a form

    void fl_set_form_background_color(FL_FORM *form, FL_COLOR col);
    FL_COLOR fl_get_form_background_color(FL_FORM *form);

These functions use the color of the very first object of the form, or, if this is a box of type `FL_NO_BOX` as it is the case with forms created via code generated by `fdesign`, the color of the second object. If these object(s) don't exist the function can't work properly.

Once all objects required have been added to a form call

    void fl_end_form(void);

Between these two calls objects and groups of objects are added to the form with functions like `fl_add_button()`.

To start a new group of objects use

    FL_OBJECT *fl_bgn_group(void);

The function returns a pointer to the group (actually to an invisible pseudo-object of class `FL_BEGIN_GROUP`). Groups can't be nested.

When all objects that are supposed to belong to the group are added call

    void fl_end_group(void);

Also this function creates an (invisible) pseudo-object, belonging to class `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 `fl_end_form()` or `fl_end_group()` can be "reopened" by using

    FL_FORM *fl_addto_form(FL_FORM *form)
    FL_OBJECT *fl_addto_group(FL_OBJECT *group);

Both functions return their argument on success and `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

    void fl_delete_object(FL_OBJECT *obj);

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 and added to the same form again or some other form using

    void fl_add_object(FL_FORM *form, FL_OBJECT *obj);

even without "reopening" the form using `fl_addto_form()`.

To finally destroy an object use

    void fl_free_object(FL_OBJECT *obj);

If `fl_delete_object()` hadn't been called for the object this will happen now. The object receives a final event of type `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 can not be referenced anymore.

A form as a whole, together with all the objects it contains can be deleted by calling

    void fl_free_form(FL_FORM *form);

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.

## 32.4 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:

    int fl_get_object_objclass(FL_OBJECT *obj);
    int fl_get_object_type(FL_OBJECT *obj);

Receiving a negative value indicates that a `NULL` pointer was passed to the functions.

To set the two colors that influence the appearance of the object use

    void fl_set_object_color(FL_OBJECT *obj, FL_COLOR col1, FL_COLOR col2);

and to find out about the colors of an object use

    void fl_get_object_color(FL_OBJECT *obj,
                             FL_COLOR *col1, FL_COLOR *col2);

    void fl_set_object_boxtype(FL_OBJECT *obj, int boxtype);

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

    int fl_get_object_boxtype(FL_OBJECT *obj);

Receiving a negative value indicates that a `NULL` pointer was passed to the function.

There are also functions to change or query the border width of an object:

    void fl_set_object_bw(FL_OBJECT *obj, int bw);
    void fl_get_object_bw(FL_OBJECT *obj, int *bw);

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

    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);

exist. If the object is visible it's redrawn at the new position.

An object can also be moved relative to its current position using the function

    void fl_move_object(FL_OBJECT *obj, FL_Coord dx, FL_Coord dy);

where `dx` and `dy` are the amounts by which the object is moved to the right and down.

To change or inquire about the size of an object use

    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);

When changing the size of the object the position of its upper left hand corner remains unchanged.

To set or query both the position and the size of an object the functions

    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);

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 interfere with this.

There's a second function for calculation an objects geometry:

    void fl_get_object_bbox(FL_OBJECT *obj, FL_Coord *x, FL_Coord *y,
                            FL_Coord *w, FL_Coord *h);

The difference between this functions and `fl_get_object_geometry()` is that `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:

    FL_OBJECT *fl_get_object_component(FL_OBJECT *obj, int objclass,
                                       int type, int number);

where `obj` 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`. The function returns the object handle if the requested object is found, otherwise `NULL`. For example to obtain the object handle to the horizontal 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)

To influence change the color, font size, font style, alignment and text of the label of an object use

    void fl_set_object_lcolor(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);
    void fl_set_object_label(FL_OBJECT *obj, const char *fmt, ...);

To find out about the object labels color, font size, style, alignment and the string itself use

    FL_COLOR fl_get_object_lcolor(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);

To set a tool-tip text for an object use the following routines

    void fl_set_object_helper(FL_OBJECT *obj, const char *helpmsg);
    void fl_set_object_helper_f(FL_OBJECT *obj, const char *fmt, ...);

where `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 600 msec. A copy of the string is made internally. The second functions accepts instead of a simple string a format string just as it's used for `printf()` etc., followed by as many further arguments as the format string contains format specifiers.

The boxtype, color and font for the tool-tip message displayed can be customized further using the following routines:

    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);

where `boxtype` is the backface of the form that displays the text. The default is `FL_BORDER_BOX`. `textcolor` and `background` specify the color of the text and the color of the backface. The defaults for these are `FL_BLACK` and `FL_YELLOW`. `style` and `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:

    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);

See section 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

    void fl_freeze_form(FL_FORM *form);
    void fl_unfreeze_form(FL_FORM *form);

The form is automatically redrawn once it is "unfrozen", so a call of `fl_redraw_form()` isn't required (and, while the form is "frozen", calling this function as well as `fl_redraw_object()` has no effects).

You may also freeze and unfreeze all forms at once by using

    void fl_freeze_all_forms(void);
    void fl_unfreeze_all_forms(void);

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 yes_no);

To determine if an object receives `FL_STEP` events use

    int fl_object_is_automatic(FL_OBJECT *obj);

To enable or disable an object to receive the `FL_DBLCLICK` event use the following routine

    void fl_set_object_dblclick(FL_OBJECT *obj, unsigned long timeout);

where `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

    unsigned fl_get_object_dblclick(FL_OBJECT *obj);

To make an object or a group invisible or visible use the following two functions

    void fl_hide_object(FL_OBJECT *obj);
    void fl_show_object(FL_OBJECT *obj);

`obj` can be the pseudo-object returned by `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

    int fl_object_is_visible(FL_OBJECT *obj);

    void fl_trigger_object(FL_OBJECT *obj);

returns `obj` to the application program after calling its callback if one exists.

    void fl_set_focus_object(FL_FORM *form, FL_OBJECT *obj);

sets the input focus in form `form` to 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 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 `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);

The routine

    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 X 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);

In other rare circumstances one might not be interested not in the X event but instead the internal XForms event resulting in the invocation of an object or form callback. This information can be obtained by calling

    int fl_current_event(void);

A callback invocation resulting from a call of `fl_call_object_callback()` will return `FL_TRIGGER`. For other possible return value see the chapter about XForms internal events. Calling this function is only useful while within an object or form callback, at all other times it returns just `FL_NOEVENT`.

Also in objects callback it might be of interest to find out if the mouse is on top of a certain letter of the (inside) label (one trivial use of this can be found in the program ``demo/strange_button.c`'. To find out about this use

    int fl_get_label_char_at_mouse(FL_OBJECT *obj);

The function returns the index of the character in the label of the object the mouse is on or `-1` if it's not over the label. Note that this function has some limitations: it can only be used on labels inside of the object and the label string may not contain underline characters (and the label can't be a symbol) - if you try to use it on labels that don't satisfy these requirements `-1` is returned.

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 *obj, const char *fname);

The function will output the specified object in PostScript. If `fname` is `NULL`, a file selector 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 `FL_XYPLOT` object is supported. Nothe that this function isn't part of the statndard XForms library (`libforms`) but the XForms image library (`libflimage` discussed in Images.

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 ``xyplotover.c`' for an example output.

It is possible to customize the output by changing the PostScript output control parameters via the function

    FLPS_CONTROL *flps_init(void);

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 `fl_object_ps_dump()`. You should not free the returned buffer.

The control structure has the following members

`int ps_color`

  The choices are full color (`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, the drawing color can be either white or black depending on the specified color.

`int orientation`

  Valid choices are `FLPS_AUTO`, `FLPS_PORTRAIT` and `FLPS_LANDSCAPE`. The default is `FLPS_AUTO`.

`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.

`int eps`

  Set this to 1 if output in EPS format is required.

`int drawbox`

  Set this to 1 if the box of the object is to be drawn.

`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.

`float paper_w`

  The paper width in inches. The default is 8.5 in.

`float paper_h`

  The paper height in inches. The default is 11 in.

To generate a PostScript output of a form or forms, use the `fd2ps` program documented in Generating Hardcopies.

## 32.5 Doing Interaction

To display the form `form` on the screen use one of

    Window fl_show_form(FL_FORM *form, int place, int border,
                        const char *title);
    Window fl_show_form(FL_FORM *form, int place, int border,
                        const char *fmt, ...);

`place` controls the position and size of the form. `border` indicates whether a border (window manager's decoration) should be drawn around the form. If a border is to be drawn `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 `"Foo Bar` the forms name is derived as `"fooBar"`. The only difference between the two functions is that the first one accepts a simple string for the title while the second expects a format string like `printf()`, followed by the appropriate number of arguments.

For the the location and size of the window controlled by `place` the following possibilities exist:

`FL_PLACE_SIZE`

  The user can control the position but the size is fixed. Interactive resizing is not allowed once the form becomes visible.

`FL_PLACE_POSITION`

  Initial position used will be the one set via `fl_set_form_position()`. Interactive resizing is allowed.

`FL_PLACE GEOMETRY`

  Place at the latest position and size (see also below) or the geometry set via `fl_set_form_geometry()` etc. A form so shown will have a fixed size and interactive resizing is not allowed.

`FL_PLACE_ASPECT`

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

`FL_PLACE_MOUSE`

  The form is placed centered below the mouse. Interactive resizing will not be allowed unless this option is accompanied by `FL_FREE_SIZE` as in `FL_PLACE_MOUSE|FL_FREE_SIZE`.

`FL_PLACE_CENTER`

  The form is placed in the center of the screen. If `FL_FREE_SIZE` is also specified, interactive resizing will be allowed.

`FL_PLACE_FULLSCREEN`

  The form is scaled to cover the full screen. If `FL_FREE_SIZE` is also specified, interative resizing will be allowed.

`FL_PLACE_FREE`

  Both the position and size are completely free. The initial size used is the designed size. Initial position, if set via `fl_set_form_position()`, will be used, otherwise interactive positioning may be possible if the window manager allows it.

`FL_PLACE_HOTSPOT`

  The form is so placed that mouse is on the "hotspot". If `FL_FREE_SIZE` is also specified, interactive resizing will be allowed.

`FL_PLACE_CENTERFREE`

  Same as `FL_PLACE_CENTER|FL_FREE_SIZE`, i.e., place the form at the center of the screen and allow resizing.

`FL_PLACE ICONIC`

  The form is shown initially iconified. The size and location used are the window manager's default.

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 `border`:

`FL_FULLBORDER`

  Draw full border with title

`FL_TRANSIENT`

  Draw borders with possibly less decoration (depends on the window managers behaviour)

`FL_NOBORDER`

  Draw no border at all

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

    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 (must be called before any full-bordered form is shown):

    void fl_set_app_nomainform(int yes_no);

with a true flag.

All visible forms will have the properties `WM_CLASS`, `WM_CLIENT_MACHINE` and `WM_NAME` set. In addition, the first full-bordered form will have the `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 routines can be used

    Window fl_prepare_form_window(FL_FORM *form, int place, int border,
                                  const char *name);
    Window fl_prepare_form_window_f(FL_FORM *form, int place, int border,
                                    const char *fmt, ...);

These routines create a window that obeys any and all constraints just as `fl_show_form()` does but remains unmapped. The only difference between the two functions is that the first one takes a simple string for the forms name while the second expects a format string like `printf()`, followed by the appropriate number of further arguments.

To map such a window, the following must be used

    Window fl_show_form_window(FL_FORM *form);

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 `fl_show_form()`.

The application program can raise a form to the top of the screen so no other forms obscures it by calling

    void fl_raise_form(FL_FORM *form);

To instead lower a form to the bottom of the stack use

    void fl_lower_form(FL_FORM *form);

When placing a form on the screen using `FL_PLACE_GEOMETRY` for the `place` argument to `fl_show_form()` the position and size can be set before by 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_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);

where `fl_set_form_geometry()` combines the functionality of `fl_set_form_position()` and `fl_set_form_size()` and the last routine, `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

    void fl_get_decoration_sizes(FL_FORM *form, int *top, int *right,
                                 int *bottom, int *left);

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

    int fl_form_is_iconified(FL_FORM *form);

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 `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

    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 the constraints only apply to the next call of `fl_show_form()` for the 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 section 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 calls can be used (they will also change the icon title)

    void fl_set_form_title(FL_FORM *form, const char *name);
    void fl_set_form_title_f(FL_FORM *form, const char *fmt, ...);

(While the first function expects a simple string, the second has to be called with a format string as `printf()` etc., followed by the corresponding number of arguments.)

The routine

    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 function can be used

    int fl_form_is_visible(FL_FORM *form)'

The function can return that the form is visible (`FL_VISIBLE`), is invisible (`FL_INVISIBLE`) or is in the processing of becoming invisible (`FL_BEING_HIDDEN`).

The most important function for doing the actual interaction with forms is

    FL_OBJECT *fl_do_forms(void);

It starts the main loop of the program and returns only when either the state of an object changes that has no callback bound to it or `fl_finish()` is called in a callback. In the first case the address of the object is returned, in the latter `NULL`.

A second way of doing interaction with the currently displayed forms is using

    FL_OBJECT *fl_check_forms(void);

This routine returns `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. `NULL` also gets returned after a call of `fl_finish()`.

Then there are two more functions:

    FL_OBJECT *fl_do_only_forms(void);
    FL_OBJECT *fl_check_only_forms(void);

Both functions do the same as `fl_do_forms()` and `fl_check_forms()` except that they do not handle user events generated by application windows opened via `fl_winopen()` or similar routines.

To activate or deactivate a form for user interaction you can use

    void fl_activate_form(FL_FORM *form);
    void fl_deactivate_form(FL_FORM *form);

The same can also be done for all forms at once using

    void fl_deactivate_all_forms(void)
    void fl_activate_all_forms(void)

To find out if a form is currently active call

    int fl_form_is_activated(FL_FORM *form);

A return value of 0 tells you that the form is currently deactivated.

You can also register callbacks for a form 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);

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

Also individual objects (or groups of objects if the argument of the function is an object returned by `fl_bgn_group()`) can be activated and deactivated to enable or disable user interaction:

    void fl_activate_object(FL_OBJECT *obj);
    void fl_deactivate_object(FL_OBJECT *obj);

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

    int fl_object_is_active(FL_OBJECT *obj);

    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 objects when necessary, but there might be situations in which an explicit redraw is required.

To redraw an entire form use

    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 Windowing Support for details.)

You may set up a callback routine (of type `FL_APPEVENT_CB` for all user events using

    typedef int (*FL_APPEVENT_CB)(XEvent *, void *);
    FL_APPEVENT_CB fl_set_event_callback(FL_APPEVENT_CB callback, void *data);

The function returns the previously set callback (or `NULL`).

It is also 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 the event callback functions for the window specified, which will be called when an event of type `xevent_type` is pending for the window. If `xevent_type` is 0 it signifies a callback for all event for window `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

    void fl_activate_event_callbacks(Window win);

## 32.6 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

    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 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:

    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);

After this, whenever a `SIGINT` signal is received, `clean_up()` is called.

To remove a signal callback, the following routine should be used

    void fl_remove_signal_callback(int signal);

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 `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 (`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 `fl_add_signal_callback(`) with a true value for `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 signals (via e.g., `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`, possibly after performing some timing sensitive tasks:

    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 invocations of `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 `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.

    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);
    }

Now define a (XForms) signal handler that will be responsible for handling the response of the GUI upon receipt of the signal

    void gui_signal_handler(int sig, void *data) {
        /* within an XForms signal handler, there is no limitation
         * on GUI activitity */
        fl_set_object_color(....);
        ...
    }

To make all this work, a set-up similar to the following can be used

    /* 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);

## 32.7 Idle Callbacks and Timeouts

For application programs that need to perform some light, but semi-continuous or periodic tasks, idle callback and timeouts (also `FL_TIMER` objects) 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 invocations of the idle callback can vary considerably depending on interface activity and other factors. A range between 50 and 300 msec should be expected. While the idle callback is executed it won't be called again (i.e., no call of any XForms function from within the idle callback function will call the idle callback function), so it does not need to be reentrant.

It is possible to change what the library considers to be "idle" with the following function:

    void fl_set_idle_delta(long msec);

Here `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

    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 (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 `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 10 ms under favourable conditions, it can also be much worse, occasionally up to 150 ms.

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 section Timer Object, for the usage of `FL_TIMER` object. For tasks that need more accurate timing the use of signal should be considered.

## 32.8 Global Variables and Macros

For convenience the library exports a number of global variables. These are:

`FL_OBJECT *FL_EVENT`

  This is a special object returned by `fl_do_forms()` etc. when an X event is received that isn't coming from a form under the control of the library, e.g., for a window that was opened directly via Xlib functions. Upon receiving this special event the application program can and must remove the pending event from the queue using `fl_XNextEvent()`.

`FL_FORM *fl_current_form`

  This variable is always set to the currently active form.

`Display *fl_display`

  This variable is set to the display (X server) the program is connected to and is needed as an argument for many Xlib functions. It's recommended not to use this global variable but instead either the function `fl_get_display()` or `FL_FormDisplay()` (the latter accepts a form pointer as its argument and will also be safe in future versions of the library that may support multiple connections).

`int fl_screen`

  This variable is set to the default screen of the display connection.

`Window fl_root`

  This variable is set to the root window.

`Window fl_vroot`

  Some window managers have problems with obtaining the corrent root window and applications don't work with the normal root windows. In this case `fl_vroot` can be used instead.

`int fl_scrw, fl_scrh`

  These variables contain the screens width and height.

`int fl_mode`

  The variable contains the visual mode in use, it should be one of the Xlib constants `PseudoColor`, `TrueColor`, `DirectColor`, `StaticColor`, `GrayScale or `StaticGray`. Alternatively, the functions `fl_get_vclass()` or `fl_get_form_vclass()`` can be used (the latter accepts a form pointer as its argument and is thus also safe for future versions that may allow multiple connections).

`FL_State fl_state[6]`

  This array of structure of type `FL_State` contains a lot of information about the graphics mode, where each structure has the information for each of the visual modes. Of interest is only the entry for the visual mode in use, `fl_vmode`.

`double fl_dpi`
`double fl_get_dpi()`

  The `fl_dpi` variable contains the screen resolution (in dots per inch), averaged over the resolutions in `x`- and `y`-direction. The funtion is a convenience macros with the same result.

`Visual *fl_visual`
`Visual *fl_get_visual()`

  Convenience macros that expands to the `Visual` pointer in use. Same as `fl_state[fl_vmode].xvinfo->visual`.

`Colormap fl_colormap`
`Colormap fl_get_colormap()`

  Convenience macros that expands to the currently used `Colormap`. Same as `fl_state[fl_vmode].colormap`.

`char *fl_ul_magic_char`

  This variable points to the character used to indicate underlining in labels and other texts. If it appears as the very first character of a string all characters in that string are underlined, otherwise the character direct in front of it. Per default it's set to `'\b'`.

[ << ] | [ >> ] |  |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

This document was generated on January 5, 2026 using texi2html 1.82.