
Xforms4Perl - Call the Xforms GUI library API from Perl

use X11::Xforms;
For access to XEvent and XFontStruct structures returned by Xforms, use the following, co-delivered, packages. They are NOT, however, required to run Xforms unless you need such access.
use X11::XEvent;
use X11::XFontStruct;

This package, distributed under the name Xforms4Perl, provides an extension to Perl that opens up almost 100% of the Xforms GUI library API to Perl scripts, thus allowing those scripts to build and interact with Xforms graphical user interfaces. It also provides some value added features, such as automatic initialization of object classes, that are not present in the native Xforms library (see "Value Added Features" below).
For the most part the interface to Xforms from Perl is the same as that from C, after appropriate 'C-to-Perl' transforms are made to the C calling syntax (see "Programming Notes" below). Substantial documentation is available for this C interface which is, therefore, equally applicable to the Perl interface. This is available from:
ftp://einstein.phys.uwm.edu/pub/Xforms/doc
In addition, Xforms4Perl is delivered with a directory named doc (installation location depends on installation method) which contains, among other things, a file named Xforms.functions. This file lists all the functions exported by X11::Xforms along with protocol notes for those functions that have different protocols to their C cousins.
Xforms and Xforms4Perl both come with directories named DEMOS which contain a large number of sample applications. Again, the locations of these directories depend upon the method of installation.
The goal is that by reading the native Xforms documentation in conjunction with this man page, the file Xforms.functions and the sample applications, should allow a programmer to use this package with ease.

The Xforms functionality itself is encapsulated by a single Perl package named X11::Xforms. To access the functionality, place the following statement at the top of your Perl script:
use X11::Xforms;
Some of the more esoteric Xforms functions return X11 structures - particularly XEvent and XFontStruct structures. To facilitate maximum usability of such functions, two more packages are delivered with Xforms4Perl which allow access to these two structures. These are named X11::XEvent and X11::XFontStruct and have their own man pages.
Most X11::Xforms functions have the same protocols as their C counterparts, once the following standard transforms are applied:
fl_set_error_logfp(*LOGFILEHANDLE);
or like this:
$filehandle = *LOGFILEHANDLE; fl_set_error_logfp($filehandle);
For example, the Xforms function fl_get_mouse is called from C so:
window = fl_get_mouse(&x, &y, &keymask);
but from Perl so:
($window, $x, $y, $keymask) = fl_get_mouse();
Therefore, the Perl function protocol does not include the output arguments.
For example, the Xforms function fl_lines (which draws lines between multiple points) might be called from C like this:
FL_POINT points[] = { {0,0}, {10,0}, {10,10} }; fl_lines(points, 3, FL_BLACK);
The equivalent call from Perl could be coded so:
@points = (0, 0, 10, 0, 10, 10); fl_lines(@points, FL_BLACK);
which is effectively:
fl_lines(0, 0, 10, 0, 10, 10, FL_BLACK);
In such cases, the C functions usually include an integer argument that defines how many members there are in the array. Since the Perl equivalents can determine this themselves, count arguments are rarely part of the protocols of these Perl functions.
Applying these principles to the Xforms documentation will generally reveal the requirements for the Perl equivalents of the C functions described therein. However, certain functions have different protocols to their C equivalents, and others have specific extra requirements or other notes that apply to their usage.
Therefore, ALL Xforms functions supported by X11::Xforms are listed in the file Xforms.functions which can be found in the Xforms4Perl doc subdirectory. Functions which, after applying the above principles, have the same protocol as their C cousins, are simply listed. Those that have different protocols and/or special usage notes have extended entries that provide these extra details. Always refer to this file as the authoritative source for protocol and usage information.
X11::Xforms provides full support for most of the Xforms library callbacks.
A callback in X11::Xforms is simply a Perl subroutine that has been registered as 'interested' in some event by the calling of a registration function, such as fl_set_object_callback.
The call protocol for the C versions of registration functions requires the address of the desired callback function.
The call protocol for their C counterparts requires either a string containing the name of the callback subroutine, or a scalar value containing a reference to the subroutine.
For example, fl_set_object_callback might be called like this from C:
old_cb = fl_set_object_callback(obj, &cb_func, 0);
whereas from Perl, the equivalent call can be made like this:
$old_cb = fl_set_object_callback($obj, "cb_func", 0);
or like this:
$old_cb = fl_set_object_callback($obj, \&cb_func, 0);
Where the C function that registers the callback returns a pointer to the previous callback, as in this example, the Perl equivalent returns a reference to the previous Perl callback subroutine. That reference can be used in a later callback registration function to re-register the original callback subroutine.
When the callback registered by this example is invoked, the arguments passed to it can be obtained using the statement:
my($obj, $value) = @_;
In general X11::Xforms callback subroutines are invoked with equivalent arguments to their C counterparts, passed as scalar values in the same order. The main exceptions to this rule are the fl_set_xyplot_symbol and fl_set_error_handler callback routines. These have slightly different argument lists due to their 'variable' nature in C. See the doc/Xforms.functions file for more details.
Some Xforms callback registration routines accept user data as an extra argument which is, in turn, passed to the callback routine when it is invoked. The same principal can be used with X11::Xforms - a Perl scalar can be passed to the registration routine, and will be passed to the callback when it is invoked.
Where the C function accepts a user data value, the Perl function will also accept a value - thus, when the callback is invoked, the value of the scalar passed to the registration routine will be presented to the callback.
Where the C function accepts a pointer to a user-defined data area, the Perl function still accepts a Perl scalar. However, when this kind of callback is invoked, it is the original scalar itself which is presented to the callback, NOT a copy of it. Therefore, if the value of the scalar has changed between registration and invocation, the new value will be seen by the callback, NOT the value at registration. This is in line with pointer usage in C - if the storage the pointer references is modified between registration and invocation, the callback sees the modified value.

Xforms defines and uses various global variables. Certain of these fields can be read (only) by calling a function of the same name as the field.
For example, to read the height of the screen from the fl_scrh field, code:
$scrh = fl_scrh();
The following fields can be accessed in this way:
fl_current_form
fl_display
fl_root
fl_screen
fl_scrh
fl_scrw
fl_textgc
fl_ul_magic_char
fl_vmode
fl_vroot

The FD_CMDLOG, FD_FSELECTOR, FL_EditKeymap, FL_FORM, FL_IOPT and FL_OBJECT data structures have been defined as Perl objects (within the X11::Xforms package). Therefore, the values of most fields in each structure can be directly read. In addition, all fields within the FL_IOPT structure, and many of the FL_FORM and FL_OBJECT structures, can be updated too.
The syntax to read a field is:
$value = $struct_ref->field_name;
and to write a writable field is
$oldval = $struct_ref->field_name(new_value);
where '$struct_ref' is the 'blessed' Perl object returned by such functions as fl_get_fselector_fdstruct, fl_get_command_log_fdstruct, fl_[create/add]_[object_type] and fl_bgn_form. In fact the return value of any function that, in Xforms itself, returns one of the above structures, can be used as the '$struct_ref' part of a field access.
The available fields in each structure, together with an indication of whether each field is read-only (ro) or read-write (rw), are as follows:
All fields are available read-only. However, since the fields themselves contain FL_FORM or FL_OBJECT structures, the fields within those structures can be accessed as below.
All fields are available read-only. However, since the fields themselves contain FL_FORM or FL_OBJECT structures, the fields within those structures can be accessed as below.
compress_mask rw deactivated rw evmask rw fdui rw first ro focusobj ro frozen rw h rw has_auto rw hotx rw hoty rw icon_mask rw icon_pixmap rw label rw last ro prop rw top rw u_cdata rw u_ldata rw u_vdata rw use_pixmap rw visible rw vmode rw w rw window ro wm_border rw x rw y rw
Be warned that the u_cdata field is treated exactly as defined - as a character string - and not as a void pointer. Therefore when writing its value from Perl, be sure to provide a valid character string.
active rw
align rw
argument rw
automatic rw
belowmouse rw
boxtype rw
bw rw
child ro
click_timeout rw
clip rw
col1 rw
col2 rw
double_buffer rw
focus rw
form ro
h rw
input rw
label rw
lcol rw
lsize rw
lstyle rw
nc ro
next ro
nwgravity rw
objclass rw
parent ro
prev ro
pushed rw
radio rw
redraw rw
resize rw
segravity rw
type rw
u_cdata rw
u_ldata rw
u_vdata rw
use_pixmap rw
visible rw
w rw
wantkey rw
window ro
(virtual field equivalent to $obj->form->window)
x rw
y rw
Be warned that the u_cdata field is treated exactly as defined - as a character string - and not as a void pointer. Therefore when writing its value from Perl, be sure to provide a valid character string.
All fields in this structure are available as read- write fields. In addition, there is an extra method provided that returns a reference to a blank FL_IOPT object:
$iopt = X11::Xforms::FLOpt->new;
Alternatively, a populated FL_IOPT object can be obtained using the fl_get_defaults function.
This structure is used with the fl_set_input_editkeymap function. All fields in this structure are available as read-write fields. In addition, there is an extra 'method' provided that returns a reference to a blank FL_EditKeymap object:
$keymap = X11::Xforms::FLEditKeymap->new;
The idea here is to use the 'new' method to create the object, use the $ref->field syntax to set the edit key mapping requirements, and then pass the object to the fl_set_input_editkeymap function.
See the XFgrep.pl and X4Pinit.pl DEMOs for examples of how to use this (especially useful for making Linux Delete and Backspace keys behave themselves!).
Note that just because a field is read-write does not mean that you SHOULD write to it. Refer to the Xforms documentation for details of the use of each field, and if and when a field should be written to.

X11::Xforms provides two powerful extra features over and above those delivered with the native Xforms library. They exist separately but are designed to be used together.
TRY THIS: Once you have installed X11::Xforms, run the demos. Then copy the X4Pinit.pl demo script to your home directory, renaming it to .X4Pinit.pl, and re-run the demos: THAT is what these facilities are all about!!
Xforms does not provide a very easy way to apply system wide defaults to object attributes, such as color and font. If you don't want what is provided as the library default you have to set every object manually.
The Class Initialization Callback feature solves this problem for Perl scripts.
This new feature centers around a new function named fl_set_class_callback which allows the Perl script to register a callback subroutine for an individual Xforms object class, such as FL_BUTTON.
After registration, the callback will be invoked whenever an object of that class is created via the standard fl_[create/add]_[object_type] functions. The subroutine is called after the object is created but before control is returned to the creating script.
As an example, this is how a class callback routine might be registered for the FL_BUTTON class:
fl_set_class_callback(FL_BUTTON, "my_button_initializer");
the routine my_button_initializer might have been coded as follows:
sub my_button_initializer {
my($new_button) = @_;
fl_set_object_color($new_button, FL_BLUE, FL_PINK); }
This particular implementation will cause all buttons created by fl_create_button or fl_add_button to take on Blue/Pink color characteristics without having to code the fl_set_object_color call after each button creation.
Just about anything can take place within a class callback - including calls to create other forms and display other dialogs - though care must be taken not cause a recursive loop within the callback!
See the Xforms.functions file for protocol and usage notes on fl_set_class_callback.
The X11::Xforms package has been implemented such that, if a Perl script named .X4Pinit.pl is found in the current user's home directory then it is "require"d into the package.
This script is intended to contain code that provides for the general initialization of X11::Xforms Perl applications. It is expected to contain at least two subroutines:
This subroutine is automatically called by the package when the exported fl_initialize subroutine is called from the application script. It is invoked immediately before the Xforms fl_initialize function is called. It is intended to perform any global initialization that you require in all Perl scripts using X11::Xforms that must occur before executing Xforms fl_initialize, such as calls to fl_set_defaults.
Note that care must be taken to ONLY perform Xforms activities that are allowed before fl_initialize is invoked. Failure to stick to this rule could mean a segmentation fault!
Again, this subroutine is automatically called by the package when the exported fl_initialize subroutine is called from the application script. However, in this case, it is invoked immediately after Xforms fl_initialize has returned control to the X11::Xforms package and before the package returns control to the calling script. It is intended to perform other global initializations that must wait until after invoking the Xforms fl_initialize function, such as calls to fl_set_class_callback (see "The Class Initialization Callback" above).
Since at this point Xforms has been fully initialized, any Xforms activity can take place inside the fl_post_init subroutine.
Again, the motivation behind this feature is the lack of facilities within Xforms itself for providing system-wide defaults. The use of X resources is the only means provided and then only very few resources actually modify the look and feel of Xforms applications.
Putting these two facilities together provides a very powerful way to customize the look-and-feel of ALL X11::Xforms interfaces without having to individually customize each object in every script. It allows for the implementation of a standard look-and-feel for such interfaces.
An example script named X4Pinit.pl is delivered in the DEMOS subdirectory - it makes all objects take on a particular color scheme that I use with the new UNIX desktop, KDE. Note especially the more complex aspects of changing FL_BROWSER attributes, and the initialization of goodies such as file selector and command log. The sample also initializes the key map to provide 'correct' Delete and Backspace handling under Linux, switches the default scrollbar to the FL_PLAIN_SCROLLBAR style, and demonstrates how to change the defaults color themselves with calls to fl_set_icm_color. To do these things without a Global Initialization Script would be very time and space consuming.

Both Xforms and Xforms4Perl are delivered with directories of sample applications. In both cases the directory is named DEMOS and is placed below the distribution master directories. Many of the Xforms4Perl examples are directly plagerized from Xforms. Both sets of samples are useful for getting to grips with using Xforms and/or X11::Xforms, with the Xforms4Perl samples being additionally useful for understanding the transforms that are necessary to apply the Xforms documentation to Perl.
Of special note are the ProcExp.pl and XFtool.pl scripts. The first is a filesystem explorer complete with tree view, list view and splitter bar and demonstrates the development of a sophisticated application with Perl, Xforms and Xforms4Perl. The second is a 'boring' toolbar - but, again, is a sophisticated full-function application written entirely in Perl with Xforms4Perl.
Note that some of the X11::Xforms samples are designed specifically for Linux platforms and, therefore, may not run as delivered in non-Linux environments.
Note also that some of the scripts rely on facilities that were introduced with Xforms version 0.88 and, therefore will gracefully die when using Xforms version 0.86.
Note also also (!) that two of the scripts, X4Pinit.pl and psf.pl, are not intended to be run standalone. The former is a sample Global Initialization Script, the latter is an implementation of a tree-based 'ps' command for non-Linux systems.

Just about all errors encountered directly by the package are fatal! However those encountered by the Xforms library itself will behave as documented in the Xforms documentation.
X11::Xforms errors fall into two categories: Failure to call an X11::Xforms subroutine correctly, and internal errors. Hence the reason that they are all fatal! The first category encompasses programming errors, the second either bugs in X11::Xforms or Xforms, or system limitations.
The first category also encompasses attempts to use functions from Xforms versions that are not compatible with the current version of X11::Xforms.
In all cases the calling Perl script will DIE with an appropriate message.

These facilities of the Xforms library have not been implemented in X11::Xforms for various reasons, explained below. Ideas and/or suggestions and/or advice on overcoming the remaining problems are welcome:
Since this doesn't get compiled into the XForms distribution it is not included in the package.
Due to the way the package handles callbacks (by registering a generic routine and saving off the Perl callback in an easy to find location) it is essential that the callback itself provide some means of finding where the Perl callback routine address is held. fl_add_symbol and fl_draw_symbol do not.
Similar problems.
Primarily for use with past versions of Xforms - none of which are supported by Xforms4Perl anyway.
esoteric and probably not applicable to Perl, since hashes achieve the same.
No use in Perl
Well, ok, its there - but you will need to do some hefty stuff to build the XSetWindowAttributes structure and send its address to me!
Similar - or I got lazy. If you REALLY want this then tell me and I'll put it in the next release!
This is easily supported by base Perl.
Relies on XVisualInfo structure which I have not provided access to (yet!)
C-array reliant for which there is little need in Perl
Maybe later

Usage support for the Xforms4Perl packages is available on the Xforms m ailing list (see the above ftp site for details), the comp.lang.perl.modules newsgroup, and by e-mail from martin@nitram.demon.co.uk.

The current version of this package (0.8.4) is designed to operate with the 0.88 public release of Xforms. It can also be compiled against the 0.86 public release, for backward compatibility, although some constant values may be wrong for 0.86. The package was developed using Perl 5.003 and 5.004. It is, however, believed to also operate with Perl 5.002. It has been successfully tested on a large variety of Unix-like systems.

For more information, see:
Xforms documentation
doc/Xforms.functions
doc/Xforms.constants

Martin Bartlett <martin@nitram.demon.co.uk>