next up previous contents index
Next: Index Up: XForms Online Manual Previous: Designing your own object

Appendices

 

Overview of main routines

 

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.

Version Information

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 tex2html_wrap_inline9607 1000 + 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 tex2html_wrap_inline9607 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. 

Initialization

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

argc,argv
Command line parameters. 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 . or *.

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 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:dpystring 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 buttonFontSizeFL_PDButtonFontSizeDefault Button label fontsize
int menuFontSizeFL_PDMenuFontSize Menu label fontsize
int choiceFontSizeFL_PDChoiceFontSize Choice label and choice text fontsize
int browserFontSizeFL_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 privateColormapFL_PDPrivateMapSelect private colormap if appropriate
int sharedColormapFL_PDSharedMapForce shared colormap always
int standardColormapFL_PDStandardMapForce standard colormap
int scrollbarTypeFL_PDScrollbarTypeScrollbar 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;
Table A.1: FL_IOPT structure

 

Some of the defaults are ``magic" in that their exact values depend on the context or platform. For example, the underline thickness by default is 1 for normal font and 2 for bold font.

There exists a convenience function to set the application default border width

   

   void fl_set_border_width(int border_width)

which is equivalent to

  FL_IOPT fl_cntl;
  fl_cntl.borderWidth = border_width;
  fl_set_defaults(FL_PDBorderWidth, &fl_cntl);

Typically this function, if used, should appear before fl_initialize() so the user has the option to override the default via 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_SCROLLBARs) 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
The basic scrollbar.
FL_THIN_SCROLLBAR
The thin scrollbar
FL_NICE_SCROLLBAR
The nice scrollbar
FL_PLAIN_SCROLLBAR
Similar to thin scrollbar, but not as fancy.

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.

Creating forms

   

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

Starts the definition of a form.  type is the type of the box that is used as a background. w and h give the width and height of the form. The function returns a pointer to the form created.

   

   void fl_end_form()

End the definition of a form. . Between these two calls, various objects, including group of objects, are added to the form.

     

   FL_OBJECT *fl_bgn_group()

Begin the definition of a group of objects inside the form. It returns a pointer to the group. Groups should never be nested. 

     

   FL_OBJECT * fl_end_group(void)

Ends the definition of a group.

Groups are useful for two reasons. First of all, it is possible to hide or deactivate groups of objects. This is often very handy to dynamically change the appearance of a form depending on the context or selected options. In addition, it can also be used as a shortcut to set some particular attributes of several objects. It is not uncommon that you want several objects to maintain their relative positioning upon form resizing. This requires to set the gravity for each object.     If these objects are placed inside a group, setting the gravity attributes of the group would suffice.

The second reason for using groups is for radio buttons. Radio buttons are considered related only if they belong to the same group. Using groups is the only way to place unrelated groups of radio buttons on a single form without interference from each other.

     

   void fl_addto_group(FL_OBJECT *group)

reopens a group for adding more objects to it. Any new objects added are appended at the end of the group.

   

   void fl_addto_form(FL_FORM *form)

Reopens a form for adding objects to it.

   

   void fl_delete_object(FL_OBJECT *obj)

Removes an object from the form it is in. 

   

   void fl_free_object(FL_OBJECT *obj)

 Frees the memory for an object. (Object should be deleted first.) An object after being freed should not be referenced. 

   

   void fl_free_form(FL_FORM *form)

Frees the memory for a form, together with all its objects. The form should not be visible.

Setting attributes

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

     

   void fl_set_object_color(FL_OBJECT *obj, int col1, int col2)

Sets the two colors that influence the appearance of the object.

attributes:     

   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)

and 

   

   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)

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

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, drawing color can be either white or black depending on the specified color.
orientation
The 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 auto-scaling off.
eps
Either 0 or 1.
drawbox
Set this to 1 if the box of the object is to be drawn.
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 shrunk.
paper_w
The paper width, in inches. The default is 8.5in.
paper_h
The paper height, in inches. The default is 11in.

To generate a POSTSCRIPT output of a form or forms, use the fd2ps program documented in Chapter 13.

Doing interaction

   

   long fl_show_form(FL_FORM *form,int place,int border,const char *title)

Displays a form on the screen. place controls the position and size of the form. border indicates whether a border (window manager's decoration) should be drawn around the form. In this case title is the name of the window 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)

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

Redraws an entire 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);

Signals

The application program can elect to handle the receipt of a signal by registering a callback function that gets called when the signal is raised and caught

   

    typedef void (*FL_SIGNAL_HANDLER)(int, void *);
    void fl_add_signal_callback(int signal, FL_SIGNAL_HANDLER sh, void *data);

Only one callback per signal is permitted.

By default, fl_add_signal_callback() will store the callback function and initiate mechanism for the OS to deliver the signal when it occurs. When the signal is received by the library, the main loop will invoke the registered callback function when it is appropriate to do so. The callback function can make use of all XForms's functions as well as Xlib functions as if there were re-entrant. Further, a signal callback so registered is persistent and will cease to function only when explicitly removed.

It is very simple to use this routine. For example, to prevent a program from exiting prematurely due to interrupts, code fragment similar to the following can be used:

   void clean_up(int signum, void *data)
   {
        /* clean up, of course */
   }

   /* and somewhere after fl_initialize */

   fl_add_signal_callback(SIGINT, clean_up, &mydata);

After this, whenever interrupt is detected, clean_up is called.

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

   

    void  fl_remove_signal_callback(int signal);

There are limitations with the default behavior outlined above. For example, on some platforms, there is no blocking of signals of any kind while handling a signal. In addition, use of fl_add_signal_callback() prevents the application program from using any, potentially more flexible, system signal handling routines on some platforms.

In light of these limitations, provisions are made so an application program may choose to take over the initial signal handling setup and receipt via various system dependent methods (sigaction(2) for example).

To change the default behavior of built-in signal facilities, the following routine should be called prior to any use of fl_add_signal_callback() with a true flag:

   

   void fl_app_signal_direct(int flag)

After this call, fl_add_signal_callback() will not initiate any actions to receive a signal. The application program should handle the receipt and blocking of a signal (via, signal(2), 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.

Idle callbacks and timeouts

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

To register an idle callback with the system, use the following routine

       

    typedef int (*FL_APPEVENT_CB)(XEvent *, void *);
    FL_APPEVENT_CB
    fl_set_idle_callback(FL_APPEVENT_CB callback, void *user_data)

where callback is the function that will get called whenever the main loop is idle.

The time interval between any two consecutive invocations of the idle callback can vary considerably depending on the interface activity and other factors. A range between 50 and 300 milli-second should be expected.

It is possible to change the the condition (intervals of inactivity) based on which the main loop determines the idleness of the interface. To this end, the following is available

       

   void fl_set_idle_delta(long msec)

where msec is the minimum interval of inactivity to be considered idle. However, it should be noted that under some conditions, an idle callback can be called sooner than the minimum interval.

If the timing of the idle callback is of concern, timeouts should be used. Timeouts are similar to idle callbacks but with the property that the user can specify a minimum time interval that must elapse before the callback is called. To register a timeout callback, the following routine can be used

     

   typedef void (*FL_TIMEOUT_CALLBACK)(int, void *)
   int fl_add_timeout(long msec,    
                      FL_TIMEOUT_CALLBACK callback, void *data)

The function returns the timeout ID. When the time interval specified by msec (in milli-second) is elapsed, the 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.

Some Useful Functions

Misc. Functions

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.

Resources for Forms Library

Managing resources is an important part of programming with X. Typical X programs use extensive resource database/management to customize their appearances. With the help of Form Designer, there is little or no need to specify any resources for the default appearance of an application written using the Forms Library. Because of this, complete resource support is somewhat a low-priority task and currently only minimal support is available. Nevertheless, more complete and useful resource management system specific to the Forms Library can be implemented using the services provided by the XForms.

Current Support

At the moment, all built-in XForms resources have a top level class name XForm and a resource name xform. Because of this incomplete specification, most of the current resources are ``global", in the sense that they affect all form windows. Eventually all resources will be fully resolved, e.g., to specify attribute foo of form formName, the resource name can be appName.formName.foo instead of (the current incomplete) appName.xform.foo.

The argument app_opt in fl_initialize() is a table of   structures listing your application's command line options. The structure is defined as follows

   

   typedef struct
   {
       char *option;
       char *specifier;
       XrmOptionKind argKind;
       void *value;
   } XrmOptionDescList, FL_CMD_OPT;

See XrmGetResource(3X11) for details.

After the initialization routine is called, all command line arguments, both XForms built-in and application specific ones, are removed from argc and argv and parsed into a standard XResources database. To read your application specific options, follow fl_initialize() with the following routine

   

  int fl_get_app_resources(FL_resource *resource, int nresources);

Here resource is a table containing application specific resources in the following format:

   typedef struct
   {
       char *res_name;    /* resource name without application name    */
       char *res_class;   /* resource class                            */
       FL_RTYPE type;     /* C type of the variable                    */
       void  *var         /* variable that will hold the value         */
       char *defval;      /* default value in string form              */
       int nbytes;        /* buffer size for string var.               */
   } FL_RESOURCE;

and the resource type FL_RTYPE type is one of the following

   FL_SHORT          for short   variable
   FL_BOOL           for boolean variable (int)
   FL_INT            for int     variable
   FL_LONG           for long    variable
   FL_FLOAT          for float   variable
   FL_STRING         for char [] variable

Note that the variable for FL_BOOL must be of type int. It differs from FL_INT only in the way the resources are converted, not in the way their values are stored. A boolean variable is considered to be true (1) if any one of True, true, Yes, yes, On, on, or 1 is specified as its value. For string variables, the length for the destination buffer must be specified.

fl_get_app_resources() simply looks up all entries specified in FL_resource structure in all databases after prefixing the resource name with the application name, which can be the new name introduced by the -name option.

Summarized below are the currently recognized Forms Library built-in resources:

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

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.

An example

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.

Going Further

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.

Dirty Tricks

  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.

Interaction

Form Event

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.

Object Events

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.

Other

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.

Trouble Shooting

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() only draws the form partially
This only happens if immediately following 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().

I updated the value of a slider/counter/label, but it does not change
This only happens if the update is followed by a blockage of execution or a long task without involving the main loop of Forms Library. You can force a screen update using XSync(fl_get_display(),0).

Reporting Bugs

  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.


next up previous contents index
Next: Index Up: XForms Online Manual Previous: Designing your own object

© 1996, 1997 Danny Uy,DropDead, Inc.