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

There is also a routine that can be used to obtain the library version at run time:

   

   int fl_library_version(int *version, int *revision)

The function returns a consolidated version information, computed as version x 1000 + revision. For example, for library version 1 revision 21 (1.21), the function returns a value of 1021 with version and revision (if not null) set to 1 and 21 respectively.

It is always a good idea to check if the header and the run time library are of the same version and take appropriate actions when they are not. This is especially important for version < 1.

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

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:

            

OptionsValue TypeMeaningDefault
-debug levelintprints debug information.0
-name appnamestringchanges application namenone
-syncnonerequests synchronous mode (debug)false
-display host:dpystringspecifies remote host$DISPLAY
-visual classstringTrueColor, PseudoColor...best
-depth depthintspecifies prefered visual depth.best
-vid idlongspecifies preferred visual ID 
-privatenoneforces private colormap.false
-sharednoneforces shared colormap.false
-stdcmapnoneforces standard colormap.false
-doublenoneenables double bufferingfalse
-bw widthintchanges border width3
-rgamma gammafloatspecifies red gamma1.0
-ggamma gammafloatspecifies green gamma1.0
-bgamma gammafloatspecifies blue gamma1.0

``best"  in the above table means the visual that has the most colors, which may or may not be the server default. There is a special command option -visual Default that sets both the visual and depth to the X server default. If a visual ID is requested, it overrides depth or visual if specified. Visual Id can also be requested programmatically (before fl_initialize) via the following function

   

   void fl_set_visualID(long id)

If border width is set to a negative number, all objects appear to be softer and some people might prefer bw -2. .

Depending on your application, XForms defaults may or may not be appropriate. E.g., on machines capable of 24bits visuals, Forms Library always selects the deeper 24bits visual. If your application only uses a limited number of colors, it would typically be faster if a visual other than 24bits is selected. 

There are a couple of ways to override the default settings.  You can provide an application specific resource database distributed with your program. The easiest way, however, is to set up your own program default programmatically without affecting the users' ability to override with command line options. For this, you can use the following routine before fl_initialize() :

                 

   void fl_set_defaults(unsigned long mask, FL_IOPT *flopt)

In addition to setting a preferred visual, this function can also be used to set other program defaults, such as label font size, unit of measure for form sizes etc.

See   Table A.1 for a list of the masks and the members of FL_IOPT. 

A special visual designation, FL_DefaultVisual and command line option equivalent -visual Default are provided to set the program default to the server's default visual class and depth. 

If you set up your resource specifications to use class names instead of instance names, users can then list instance resources under arbitrary name that is specified with the -name option.

Coordinate units     can be in pixels, points (1/72 inch), mm (milli-meters), cp (centi-point, i.e., 1/100 of a point) or cmm (centi-millimeter). The pre-defined designations (enums) for coordUnit are FL_COORD_PIXEL,     FL_COORD_POINT,     FL_COORD_MM,     FL_COORD_centiPOINT, and     FL_COORD_centiMM.     coordUnit can be changed anytime, but typically you would do this prior to creating a form, presumably to make the size of   the form screen resolution independent. The basic steps in doing this may look something like the following:

   

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

As you can see, convenience functions fl_set_coordunit() and fl_get_coordunit() are provided to change the unit of measure.   

  


   Structure               Mask Name            Meaning
   typedef struct {
      int debug;           FL_PDDebug           Debug level (0-5)
      int depth;           FL_PDDepth           Preferred visual depth
      int vclass;          FL_PDVisual          Preferred visual. TrueColor etc
      int doubleBuffer     FL_PDDouble          Simulate double buffering
      int buttonFontSize   FL_PDButtonFontSize  Default Button label fontsize
      int menuFontSize     FL_PDMenuFontSize    Menu label fontsize
      int choiceFontSize   FL_PDChoiceFontSize  Choice label and choice text fontsize
      int browserFontSize  FL_PDBrowserFontSize Browser label and text fontsize
      int inputFontSize    FL_PDInputFontSize   Input label and text fontsize
      int labelFontSize    FL_PDLabelFontSize   label fontsize for all other objects (box, pixmap etc.)
      int pupFontSize      FL_PDPupFontSize     Fontsize for pop-ups
      int privateColormap  FL_PDPrivateMap      Select private colormap if appropriate
      int sharedColormap   FL_PDSharedMap       Force shared colormap always
      int standardColormap FL_PDStandardMap     Force standard colormap
      int leftScrollBar    FL_PDLeftScrollBar   Placement of scrollbar in browser
      int ulThickness      FL_PDULThickness     Underline thickness
      int ulPropWidth      FL_PDULPropWidth     Underline width. 0 for const. width
      int coordUnit        FL_PDCoordUnit       Unit of measure: pixel, mm, point
      int borderWidth      FL_PDBorderWidth     Height of an object
   } FL_IOPT;
Table A.1: FL_IOPT structure

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

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

   

   void fl_set_border_width(int border_width)

which is equivalent to

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

Typically this function, if used, should appear before fl_initialize() so the user has the option to override the default via command line options.

Prior to version V0.80, the origin of XForms's coordinate system was   at the lower-left corner of the form. The new Form Designer will convert the form definition file to the new coordinate system, i.e., origin at the upper-left, so no manual intervention is required. To help those who lost the .fd files or otherwise can't use the new fdesign, a compatibility function is provided

   

   void fl_flip_yorigin(void)

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

For proportional font, substituting tabs with spaces is not always appropriate because this most likely will fail to align text properly. Instead, a tab is treated as an absolute measure of distance, in pixels, and a tab stop will always end at multiples of this distance. Application program can adjust this distance by setting the tab stops using the following routine

     

   void fl_set_tabstop(const char *s)

where s is a string whose width in pixels is to be used as the tab length. The font used to calculate the width is the same font that is used to render the string in which the tab is embedded. The default is s = "aaaaaaaa", i.e., eight \verb'a'+s;

Before we proceed further, some comments about double buffering are in order. Since Xlib does not support double buffering, Forms Library simulates this functionality with pixmap bit-blting. In practice, the effect is hardly distinguishable from double buffering and performance is on par with multi-buffering extensions (It is slower than drawing into a window directly on most workstations however). Bear in mind that pixmap can be resource hungry, so use this option with discretion.

In addition to using double buffering throughout an application, it is also possible to use double buffering on a per-form or per-object basis by using the following routines:

          

   void fl_set_form_dblbuffer(FL_FORM *form, int yes)

   void fl_set_object_dblbuffer(FL_OBJECT *obj, int yes)

Currently double buffering requests for objects having a non-square box are ignored.

Normally the Forms Library reports errors. This can be avoided using the routine

 

   void fl_show_errors(int show)

show indicates whether to show (1) or not show (0) the errors.

The fonts used in all forms can be changed using the routine  

   

   void fl_set_font_name(int numb,const char *name)

where numb is a number between 0 and (FL_MAXFONTS-1).

See section 3.11.3 for details. A redraw of all forms is required to actually see the change for visible forms.

Since the dimension of an object is typically given in pixels, depending on the server resolution and the font used, this can lead to unsatisfactory user interfaces. For example, a button designed to (just) contain a label in a 10pt font on a 75 DPI monitor will have the label overflow the button on a 100DPI monitor. This comes about because a character in a 10pt font with 75DPI resolution may have 10 pixels while the same character in the same 10 pt font with 100DPI resolution may have 14 pixels. Thus when designing the interfaces, leave a few pixels extra for the object. Or use a resolution independent unit, such as point, or centi-point etc. 

Using a resolution independent unit  for the object size should solve the font problems theoretically. In practice, this approach may still prove to be vulnerable. The reason is the discreteness of both the font resolution and the monitor/server resolutions. The standard X fonts only come in two discrete resolutions, 75 DPI and 100 DPI. Due to the variations in monitor resolutions, the same theoretically same sized font, say a 10pt font, can vary in sizes (pixels) up to 30% depending on the server (rendering a font on a 80DPI monitor will cause error in sizes regardless if 75 or 100DPI font is used.) This has not even taken into account the fact that a surprising number of systems have wrong font paths (e.g., a 90DPI monitor using 75DPI fonts etc). 

With the theoretical and practical problems associated with X fonts, it is not practical for XForms to hard-code default font resolution and it is not practical to use the resolution information obtained from the server either as information obtained from the server regarding monitor resolution is highly unreliable. Thus, XForms does not insist on using fonts with specific resolutions and instead it leaves the freedom to select the default fonts of appropriate resolutions to the system administrators. 

Given all these uncertainties regarding fonts, as a workaround, XForms provides a function that can be used to adjust the object size dynamically according to the actual fonts loaded:

     

   double fl_adjust_form_size(FL_FORM *form, int xm, int vm)

This function works by computing the size (in pixels) of every object on the form that has an inside label and comparing it to the size of the object, scaling factors are computed if any object's label does not fit. The maximum scaling factor found are used to scale the form so every object label fits inside the object. It will never shrink a form. The function returns the overall scaling factor.

In scaling the form, the aspect ratio of the form is kept and all object gravity specifications are ignored. Since this function is meant to compensate for font size and server display resolution variations, scaling is limited to 125% per invocation. The best place to use this function is right after the creation of the forms. If the forms are properly designed, on the machine they are designed, this function should be a no-op. Form Designer has a special flag -compensate and resource compensate to request the emission of this function automatically for every form created. It is likely that this will become the default once the usefulness of it is established.

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

     

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

where hm and vm are, respectively, the horizontal and vertical margins to leave on each side of the object. This function works by computing the object label size and comparing it to the object size. If the label does not fit inside the object with the given margin, the entire form the object is on is scaled so the object label fits. In scaling the form, all gravity specification is ignored but the aspect ratio of the form (thus of objects) is kept. This function will not shrink a form. You can use this function on as many objects as you choose. Of course the object has to have a label inside the object for this function to work.

In some situations Forms Library may modify some of the server defaults. All modified defaults are restored as early as possible by the main loop and in general when an application exits, all server defaults are restored. The only exception is that when exiting from a callback that is activated by shortcuts. Thus it is recommended that the cleanup routine fl_finish() be called prior to exiting an application or register it via atexit(3)

   

   void fl_finish(void)

In addition to restoring all server defaults, fl_finish() will also shut down the connection.

Creating forms

   

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

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

   

   void fl_end_form()

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

     

   FL_OBJECT *fl_bgn_group()

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

     

   FL_OBJECT * fl_end_group(void)

Ends the definition of a group.

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

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

     

   void fl_addto_group(FL_OBJECT *group)

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

   

   void fl_addto_form(FL_FORM *form)

Reopens a form for adding objects to it.

   

   void fl_delete_object(FL_OBJECT *obj)

Removes an object from the form it is in. 

   

   void fl_free_object(FL_OBJECT *obj)

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

   

   void fl_free_form(FL_FORM *form)

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

Doing interaction

   

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

Displays a form on the screen. place controls the position and size of the form. border indicates whether a border (window manager's decoration) should be drawn around the form. In this case title is the name of the window. The routine returns the window identifier of the form. For resource and identification purposes, the form name is taken to be the title with space removed and the first character lower-cased. E.g., if a form has a title Foo Bar the form name is derived as fooBar.

There are variations on the border requests: 

FL_FULLBORDERfull border with title showing.
FL_TRANSIENTborder possibly with less decoration.
FL_NOBORDERno border at all.

Multiple forms can be displayed at the same moment.

Note that FL_NOBORDER might have adverse effect on keyboard focus  and is not very friendly to other applications (it is close to impossible to move a form that has no border).  Thus use this feature with discretion. The only situation where FL_NOBORDER is appropriate is for automated demonstration suites or when the application program must obtain an input or a mouse click from the user, and even then all other forms should be deactivated while a borderless form is active. For almost all situations where the application must demand an action from the user, FL_TRANSIENT is preferred. Also note you can't iconify a form that has no border and under most window managers, FL_TRANSIENT form can't be iconified either. 

On additional property (under almost all window managers) of a transient window is that it will stay on top of the main form , which the application program can designate using

         

   void fl_set_app_mainform(FL_FORM *form)

By default, the main form is set automatically by the library to the first full-bordered form shown.

To obtain the current main form, use the following routine      

   FL_FORM *fl_get_app_mainform(void)

In some situations, either because the concept of an application main form does not apply (for example, an application might have multiple full-bordered windows), or under some (buggy) window managers, the designation of a main form may cause stacking order problems. To workaround these, the following routine can be used to disable the designation of a main form (before any full-bordered form is shown)

     

   void fl_set_app_nomainform(int flag)

with a true flag

All visible forms will have the following properties set

   WM_CLASS
   WM_CLIENT_MACHINE
   WM_NAME

In addition, the first full border form will have the WM_COMMAND  property set and is by default the application main form.          

The application program can raise a form to the top of the screen so no other forms obscure it by using the following routine

       

    void fl_raise_form(FL_FORM *form)

Similar routine exists that lowers a form to the bottom of the stack

     

    void fl_lower_form(FL_FORM *form)

When placing a form on the screen using place FL_PLACE_GEOMETRY the position and size can be set using the routines 

   

   void fl_set_form_position(FL_FORM *form, FL_Coord x, FL_Coord y)

       

   void fl_set_form_size(FL_FORM *form, FL_Coord w, FL_Coord h)

   void fl_scale_form(FL_FORM *form, double xsc, double ysc)
   

Where the last routine scales with a factor with respect to the current size. These routines can also be used when the form is visible.

If interactive resizing is to be allowed, (e.g., form shown using FL_PLACE_FREE), it can be useful to limit the range the size of a form can take. To this end, the following functions are available  

       

   void fl_set_form_minsize(FL_FORM *form, FL_Coord minw, FL_Coord minh);

   void fl_set_form_maxsize(FL_FORM *form, FL_Coord maxw, FL_Coord maxh);

Although these two routines can be used before or after a form becomes visible, not all window managers honor such requests once the window is visible. Also note that these constraints routines only applies to the next fl_show_form().

To set or change the icon shown when a form is iconified, use the following routine

   

    void fl_set_form_icon(FL_FORM *form, Pixmap icon, Pixmap mask)

where icon can be any valid Pixmap ID. (See Sections 14.5 and 14.6 for some of the routines that can be used to create Pixmaps) Note that the previous icon if not freed or modified in anyway.

If for any reason, you would like to change the form title after it is shown, the following call can be used (this will also change the icon title)

   

   void fl_set_form_title(FL_FORM *form, const char *name)

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. 

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.

                              

   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)

   

   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)

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)

For non-form windows, i.e., those created with fl_winopen() or similar routines by the application program, the following means of interaction are provided (note that these do not work on form windows, for which a different set of functions exist. See Section C for details)

   

   void fl_set_event_callback(void (*callback)(void *xevent, void *data))

Sets  up a callback routine for all user events.    

It is possible to set up callback functions on a per window/event basis using the following routines 

   

   typedef int (*FL_APPEVENT_CB)(XEvent *xev, void *user_data);

   FL_APPEVENT_CB fl_add_event_callback(Window win, int xevent_type, 
                              FL_APPEVENT_CB callback, void *user_data);

   void fl_remove_event_callback(Window win, int xevent_type)

These functions manipulate  event callback functions for the window specified and will be called when xevent_type is pending for the window. If xevent_type is zero, it signifies a callback for all event for window win. Note that Forms Library does not solicit any event for the caller, i.e., Forms Library assumes the caller opens the window and solicits all events before calling these routines. To let Forms Library handle event solicitation, the following function may be used

   

   void fl_activate_event_callback(Window win);

The following routine can be used to sound the keyboard bell (if capable),

     

   void fl_ringbell(int percent)

where percent can range from -100 to 100 with 0 being the default volume setting of the keyboard. A value of 100 indicates maximum volume and a value of -100 indicates minimum volume (off). Note that not all keyboards support volume variations.

There is another routine that might come in handy

 

   void fl_gettime(unsigned long *sec, unsigned long *usec)

Upon function return, sec and usec are set to the current time, expressed in seconds and microseconds since 00:00 GMT January, 1970. This function is most useful for computing time differences.

Signals

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

   

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

Only one callback per signal is permitted.

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

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

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

   /* and somewhere after fl_initialize */

   fl_add_signal_callback(SIGINT, clean_up, &mydata);

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

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

   

    void  fl_remove_signal_callback(int signal);

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

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

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

   

   void fl_app_signal_direct(int flag)

After this call, fl_add_signal_callback will not initiate any actions to receive a signal. The application program should handle the receipt and blocking of a signal (via, signal(2), sigaction2, sigprocmask2 etc.) When the signal is received by the application program, it should call the following routine to inform the main loop of the delivery of the signal signum

   void fl_signal_caught(int signum);

This routine is the only one in the library that can be safely called from within a direct application signal handler. If multiple invocation of fl_signal_caught occurs before the main loop is able to call the registered callback, the callback is called only once.

Idle callbacks and timeouts

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

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

       

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

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

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

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

       

   void fl_set_idle_delta(long msec)

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

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

     

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

The function returns the timeout ID. When the time interval specified by msec (in milli-second) is elapsed, the callback function is called. After the callback returns, the timeout is removed. Although timeout offers some control over the timing, due to performance and cpu load compromises, the resolution at best is only   0.05 seconds, and can occasionally be in the 0.05-0.15 seconds range.

To remove a timeout before it triggers, use the following routine

     

   void fl_remove_timeout(int ID)

where ID is the timeout ID returned by fl_add_timeout().

See also Section 19.1 for the usage of FL_TIMER object.

Resources for Forms Library

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

Current Support

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

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

   

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

See XrmGetResource(3X11) for details.

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

   

  int fl_get_app_resources(FL_resource *resource, int nresources);

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

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

and the resource type FL_RTYPE type is one of the following

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

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

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

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

Resource NameClassTypeDefault
rgammaGammafloat1.0
ggammaGammafloat1.0
bgammaGammafloat1.0
visualVisualstringbest
depthDepthintbest
doubleBufferDoubleBufferboolfalse
privateColormapPrivateColormapboolfalse
standardColormapStandardColormapboolfalse
sharedColormapSharedColormapboolfalse
pupFontSizePupFontSizeint12pt
buttonFontSizeFontSizeint10pt
sliderFontSizeFontSizeint10pt
inputFontSizeFontSizeint10pt
browserFontSizeFontSizeint10pt
menuFontSizeFontSizeint10pt
choiceFontSizeFontSizeint10pt
ulPropWidthULPropWidthbooltrue
ulThichnessULThicknessint1
leftScrollBarLeftScrollBarboolfalse
coordUnitCoordUnitstringpixel
borderWidthBorderWidthint3

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 appliation name) and should not contain wildcard of any kind. The resource will be converted according to the type and result stored in type. nbytes is used only if the resource type is FL_STRING. The function returns the string representation of the resource value. If type is passed a value FL_NONE, the resource is not converted and the pointer val is not referenced.

There is also a routine that allows the application program to set resources programatically

   

   void fl_set_resource(const char *string, const char *value)

where string and value are a resource-value pair. The string can be a fully qualified resource name (minus the application name) or a resource class.

Routines fl_set_resource and fl_get_resource can be used to store and retrieve arbitary strings and values and may be useful to pass data around.

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 similiar to the following can be used, assuming the form is named ``myform"

    struct fsize { int width, height; } myformsize;

    FL_resource res[] =
    {
       {"myform.width", "XForm.width", FL_INT, &(myform.width),   "150"},
       {"myform.height","XForm.height", FL_INT, &(myform.height), "150"},
    };
 
    fl_initialize(&argc, argv, app_class, 0, 0);
    fl_get_app_resources(res,2);

   /* create the forms */
    myform = fl_bgn_form (myformsize.width, myformsize.height,.....);

Or (more realistically) you create the form first using fdesign and then scale it before it is shown:

   fl_initialize(&argc, argv, app_class, 0, 0);
   fl_get_app_resources(res,2);
   /*create_all_forms here */
   fl_set_form_size(myform, mysformsize.width, myformsize.height);
   fl_show_form(myform, ...);

Eventully form geometry and other things might be done via XForms internal routines, it is recommended that you name your form to be the form title with all spaces removed and first letter lower-cased, i.e., if a form is shown with a label Foo Bar, the name of the form should be fooBar.

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 procesing for a particular form, you can also do so for an object. Unlike in raw callbacks, you can not select individual events.

The mechnism provided is via the registration of a pre-handler for an object. The pre-handler will be called before the built-in object handler. By electing to handle some of the events, a pre-handler can, in effect, replace part of the built-in handler.

Chapter 27.1 has already discussed the API in detail, here we just repeat the discussion for completeness as any use of preemptive handler is considered ``dirty tricks".

To register a pre-handler, use the following routine

     

    typedef int (*FL_HANDLEPTR)(FL_OBJECT *ob, int event,
                                FL_Coord mx, FL_Coord my,
                                int key, void *raw_event);

    void fl_set_object_prehandler(FL_OBJECT *, FL_HANDLEPTR prehandler);

Where event is the generic event in the Forms Library, that is, FL_DRAW, FL_ENTER etc. Parameter mx, my are the mouse position and key is the key pressed. The last parameter raw_event is the (cast) XEvent that caused the invocation of the pre-handler.

Notice that the pre-handler has the same function prototype as the built-in handler. Actually they are called with the same exact parameters by the event dispatcher. The prehandler should return 0 if the processing by the built-in handler shoud continue. A return value of FL_PREEMPT  will prevent the dispatcher from calling the built-in handler.

See demo program preemptive.c for an example.

Similar mechnism exists for registering a post-handler, i.e., a handler invoked after the built-in handler finishes. Whenever possible a post-handler should be used instead of a pre-handler.

Windowing Support

Some of these routines are used internally by the Forms Library as an attempt to localize window system dependencies and may be of some general use. Be warned that these routines may subject to frequent changes, both in their API and/or functionality.

You can create and show a window with the following routines

       

   Window fl_wincreate(const char *name)
   Window fl_winshow(Window win);

where parameter win in fl_winshow is the window ID returned by fl_wincreate. Between the creation and showing of the window, other attributes of the window can be set. Note a window so opened is always a top level window and uses all the Forms Library'f defaults (visual, depth etc.)

It is sometimes more convenient to create and show a window directly

   

   Window fl_winopen(const char *name)

This will open a (top-level) window with a title name. A window so opened can be drawn into as soon as the function returns, i.e., fl_winopen() waits until the window is ready to be drawn into.

The newly opened window will have the following default attributes

event_mask
ExposureMask, KeyPressMask, KeyReleaseMask, ButtonPressMask, ButtonReleaseMask, OwnerGrabButtonMask, ButtonMotionMask, PointerMotionMask, PointerMotionHintMask, StructureNotifyMask

backing_store
fl_cntl.backingStore

class
InputOutput

visual
same as Forms Library's default.
colormap
same as Forms Library's default.

By default, the newly opened window will have a size of 320 by 200 pixels and has no other constraints. You can modify the default or constraints using the following routines prior to calling fl_winopen():

       

   void fl_initial_winsize(FL_Coord w, FL_Coord h)
   void fl_winsize(FL_Coord w, FL_Coord h)

These two routines set the preferred window size. w and h are the width and height of the window in pixels. fl_winsize() in addition will make the window non-resizable (You can still resize the window programmatically) by setting the minimum and maximum window size to the requested size via WMHints. The effect of a window having this property is that it can't be interactively resized (provided the window manager cooperates).

It is sometimes desirable to have a window that is resizable but only within a useful range. To set such a constraint, use the following functions:

       

    void fl_winminsize(Window window, FL_Coord minw, FL_Coord minh)
    void fl_winmaxsize(Window window, FL_Corrd maxw, FL_Coord maxh)

These two routines can also be used after a window becomes visible. For windows to be created/opened, use 0 for the window parameter. For example, if we want to open a window of 640 by 480 pixels, and have it remain resizeable but within a permitted range, code similar to the following can be used:

    fl_initial_winsize(640,480);
    fl_winminsize(0, 100,100);
    fl_winmaxsize(0, 1024,768)
    win = fl_winopen("MyWin");

In addition to window size preference, you can also set preferred position of a window to be opened:

   

   void fl_winposition(FL_Coord x, FL_Coord y)

where x and y are the coordinates of the upper-left corner of the window relative to the root window.

Or you can set the geometry in one function call

       

   void fl_initial_wingeometry(FL_Coord x, FL_Coord y, 
                               FL_Coord w, FL_Coord h)

   void fl_wingeometry(FL_Coord x, FL_Coord y, 
                       FL_Coord w, FL_Coord h)

Again, the fl_wingeometry will deny later interactive resizing.

There are other routines that can be used to change other aspects of the window to be created

   

   fl_winaspect(Window win, FL_Coord x, FL_Coord y)

This will set the aspect ratio of the window in later interactive resizing.

To change the window title (and its associated icon title), use the following routine

   

   void fl_wintitle(Window win, const char *title)

To install an icon for the window, use the following routine

   

    void fl_winicon(Window win, Pixmap icon, Pixmap mask)

You can suppress the window manager's decoration or make the window a transient one by using the following routines

       

   void fl_noborder(void)
   void fl_transient(void)

You can also set the background of the window to a certain color using the following call

   

   void fl_winbackground(Window win, unsigned long pixel)

It is possible to set the change size of a window to some discrete steps:

   

   void fl_winstepsize(Window win, int xunit, int yunit)

where xunit and yunit are the amount of changes per unit in the x- and y- directions respectively. Note that this only applies to interactive resizing.

To change constraints (size and aspect ratio) on an active window, you can use the following routine

   

   void fl_reset_winconstraints(Window win)

The following routines are available to get information about an active window win:

           

   void fl_get_winsize(Window win, FL_Coord *w, FL_Coord *h)
   void fl_get_winorigin(Window win, FL_Coord *x, FL_Coord *y)
   void fl_get_wingeometry(Window win, FL_Coord *x, FL_Coord *y, 
                           FL_Coord *w, FL_Coord *h)

All units are in pixels. Origin of a window is measured from the upper left corner of the root window.

To change the size of window programmatically, the following routine is available:

   

   int fl_winresize(Window win, FL_Coord neww, FL_Coord newh)

In addition to resizing the window, this routine will keep the original constraints. For example, if a window was not permitted to be interactively resized, after the resize, it remains unresizeable. Resizing is done by keeping the origin constant relative to the root window.

To move a window without resizing it, use the following call

   

   void fl_winmove(Window win, FL_Coord newx, FL_Coord newy)

To move and resize a window, use the following routine

   

   void fl_winreshape(Window win, FL_Coord newx, FL_Coord newy,
                       FL_Coord neww, FL_Coord newh)

To make a window invisible, use the following routine

   

   void fl_winhide(Window win)

A hidden window can be shown again later using fl_winshow.

To hide and destroy a window, use the following calls

   

   void fl_winclose(Window win)

There will be no events generated from fl_winclose, i.e., the function waits and eats all events for window win. In addition, this routine also removes all callbacks associated with the closed window.

The following routine can be used to check if a window is valid or not

   

   int fl_winisvalid(Window win)

Note that excessive use of this function may negatively impact performance.

XForms also provides a convenience function to change the cursor shapes

     

   void fl_set_cursor(Window win, int name)

where win must be a valid window identifier and name is one of the symbolic cursor names (shapes) defined by standard X or the integer value returned by fl_create_bitmap_cursor()

or one of the Forms Library's pre-defined symbolic names.

The symbolic cursor names (all starts with XC_) are defined in <X11/cursorfont.h>. For example, to set a watch-shaped cursor for form form, the following call may be made

   fl_set_cursor(form->window,  XC_watch);

The Forms Library defined a special symbolic constants, FL_INVISIBLE_CURSOR  

that can be used to hide the cursor for window win:

   fl_set_cursor(win, FL_INVISIBLE_CURSOR);

Depending on the structure of the application program, an XFlush(fl_get_display()) may be required following fl_set_cursor().

To reset the cursor to the XForms's default (an arrow pointing northwest), use the following routine

     

   void fl_reset_cursor(Window win)

To change the color of a cursor, use the following routine

     

   void fl_set_cursor_color(int name, FL_COLOR fg, FL_COLOR bg)

where fg and bg are the foreground and background color of the cursor respectively. If the cursor is being displayed, the color change is visible immediately.

It is possible to use cursors other than those defined by the standard cursor font by creating a bitmap cursor

   

   int fl_create_bitmap_cursor(const char *source, const char *mask, 
                               int w, int h, int hotx, int hoty)

where source and mask are two (x)bitmaps. The mask defines the shape of the cursor. The pixels set to 1 in the mask defines which source pixels are displayed. If mask is null, all bits in source are displayed. hotx and hoty are the hotspot of the cursor (relative to the source's origin). The function returns the cursor ID which can be used in fl_set_cursor() and fl_set_cursor_color() etc.

See demo cursor.c for an example use of the cursor routines.

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

Popup menu associated with Choice object is truncated
This is a known problem with private colormap and unfortunately there is no (easy) fix. To work around this,       make sure to run your program in default visual with a shared colormap either using command line -visual Default, or selecting the default visual and colormap programmatically using fl_set_defaults().

Reporting Bugs

  When you (think you) encountered a bug in the XForms please report it by sending a mail message to zhao@bragg.phys.uwm.edu. In this mail please indicate the version of the library, the type of machine and OS version you are running this on. Some sample code that exhibits the erratic behavior would help greatly. The name of the window manager, and an output of xdpyinfo or any other relevant information (demo program similar to your code works/fails etc) would also help. Forms Library version can be obtained by holding the <Meta> key and pressing the middle mouse button somewhere in one of the forms, or by running fdesign with -flversion flag.  Give a short description of the problem and if possible. Don't expect an immediate answer but we will do our best.


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

© 1996 1997 Danny Uy,DropDead, Inc.