Back to Contents


The Dynamic User Interface

Summary:

See also: Form Files, Windows and Forms, Interaction Model.


Graphical rendering

In Genero, the user interface is designed to provide a real graphical look and feel, compared to traditional Informix 4GL applications. However, graphical user interfaces and especially windows management is not compatible with the traditional 4GL user interface management, which was designed for character terminals. With the graphical interface of Genero, you can, for example, display windows as real movable and resizable windows, display labels with variable fonts, use toolbars and pull-down menus, or show error messages in a status bar. But this requires you to adapt the code and remove instructions like DISPLAY AT that make no sense in real GUI mode.


The Dynamic User Interface

The concept

The Dynamic User Interface (DUI) is a global concept for a new, open User Interface programming toolkit and deployment components, based on the usage of XML standards and built-in classes.

The purpose of the DUI is to support different kinds of display devices by using the same source code, introducing an abstract definition of the user interface that can be manipulated at runtime as a tree of user interface objects. This tree is called the Abstract User Interface.

The Runtime System is in charge of the Abstract User Interface tree and the Front End is in charge of making this abstract tree visible on the screen. The Front End gets a copy of that tree which is automatically synchronized by the runtime by using the Front End Protocol.

In development, application screens are defined by Form Specification Files. These files are used by the Form Compiler to produce the Runtime Form Files that can be deployed in production environments.

Architectural schema

The following schema describes the Dynamic User Interface concept, showing how the Abstract User Interface tree is shared by the Runtime System and the Front End:

When is the front-end synchronized?

The Abstract User Interface tree on the front-end is synchronized with the Runtime System AUI tree when a user interaction instruction takes the control. This means that the user will not see any display as long as the program is doing batch processing, until an interactive statement is reached.

For example, the following program shows nothing:

01 MAIN
02   DEFINE cnt INTEGER
03   OPEN WINDOW w WITH FORM "myform"
04   FOR cnt=1 TO 10
05     DISPLAY BY NAME cnt
06     SLEEP 1
07   END FOR
08 END MAIN

If you want to show something on the screen while the program is running in a batch procedure, you must force synchronization with the front-end, by calling the refresh() method of the Interface built-in class:

01 MAIN
02   DEFINE cnt INTEGER
03   OPEN WINDOW w WITH FORM "myform"
04   FOR cnt=1 TO 10
05     DISPLAY BY NAME cnt
06     CALL ui.Interface.refresh()   -- Sync the front-end!
07     SLEEP 1
08   END FOR
09 END MAIN 

Connecting to the front-end

Graphical and Text Mode

By default, a Genero BDL application executes in graphical mode (GUI). However, you can run the applications in dumb terminals by using the text-based display, called text mode (TUI). To run the application in TUI mode, set the FGLGUI environment variable to zero.

Defining the Target Front-End

In GUI mode, when the first interactive instruction like MENU or INPUT is executed, the runtime system establishes a tcp connection to the front-end. The front-end acts as a graphical server for the runtime system.

On the runtime system side, the front-end is identified by the FGLSERVER environment variable. This variable defines the hostname of the machine where the front-end resides, and the number of the front-end instance to be used.

The syntax for FGLSERVER is hostname[:servernum]:

$ FGLSERVER=fox:1
$ fglrun myprog

The servernum parameter is a whole number that defines the instance of the front-end. It is actually defining a tcp port number, starting from 6400. For example, if servernum equals 2, the tcp port number used is 6402 (6400+2). 

This is the standard/basic connection technique, but you can set up different types of configurations; for example, to have the front-end connect to an application server via ssh, to pass through firewalls over the internet. Refer to the front-end documentation for more details.

Front-End Identification

The front-end can open a terminal session on the application server to start a program from the user workstation. This is done by using a ssh, rlogin, or telnet terminal session. When the terminal session is open, the front-end sends a couple of shell commands to set environment variables like FGLSERVER before starting the Genero program to display the application on the front-end where the terminal session was initiated.

In this configuration, front-end identification takes place. The front-end identification prevents the display of application windows on a front-end that did not start the Genero application on the server. If the front-end was not identified, it would result in an important security problem, as anyone could run a fake application that could display on any front-end and ask for a password.

Warning (Security Issue): Front-end identification is achieved by setting two environment variables in the terminal session, which identify the front-end. The runtime system sends the first identifier back when connecting to the front-end, and the front-end sends the second id in the returning connection string. The Front-end checks the first id, and refuses the connection if that id does not correspond to the original id set in the terminal session. The runtime system checks the second id send by the front-end in the connection string, and refuses the connection if that id does not correspond to the environment variable set in the terminal session. There can be a security hole if users can overwrite the program or the shell script started by the front-end terminal session. It is then possible to change the front-end identification environment variables and FGLSERVER, in order to display the application on another workstation to read confidential data. As long as basic application users do not have read and write privileges on the program files, there is no risk. To make sure that program files on the server side are protected from basic users, create a special user on the server to manage the application program files, and give other users only read access to those files. As long as basic users cannot modify programs on the server side, there is no security issue.

Controlling Front-End Connection

If the front-end host machine is down or if its firewall drops connections for the port used by Genero, the program will stop with an error after a given timeout.

The connection timeout can be specified with the following FGLPROFILE entry:

gui.connection.timeout = seconds

The default timeout is 30 seconds.

Front-End Connection Lost

When the runtime system waits for a user action, but the end user does not do anything, the client sends a 'ping' event every 5 minutes to keep the tcp connection alive. This situation can happen if the user leaves the workstation for a while without closing the application.

If the client is not stopped properly (when killed by a system reboot, for example), the tcp connection is lost and the runtime system does not receive any more 'ping' events from the client. In this case, the runtime system waits for a specified time before it stops with fatal error -8062.

By default, the runtime system waits for 600 seconds (10 minutes).

You can configure this timeout with an FGLPROFILE entry:

gui.protocol.pingTimeout = 800

Warning: If you set this timeout to a value lower than the ping delay of the front-end, the program will stop with a fatal error after that timeout, even if the tcp connection is still alive. For example, with a front-end having a ping delay of 5 minutes, the minimum value for this parameter should be about 330 seconds (5 minutes + 30 seconds to make sure the client ping arrives).

Front-End Errors

When the Front End receives an invalid order, it stops the application. The Runtime System then stops and displays the following message:

Program stopped at 'xxx.4gl', line number yy.
FORMS statement error number -6313.
The UserInterface has been destroyed: <message>.

The following error messages can occur:

Message Description
Application was terminated by user The front-end has been stopped or the user has clicked on the "Terminate application" button.
Unexpected interface version sent by the runtime system The runtime system and the front-end versions are not fully compatible.

The container 'container_name' already exists

The same WCI container has been started twice.

The container  'container_name' was destroyed The parent WCI container has been stopped while some children are still running
The container 'container_name' doesn't exist The WCI parent of the current child doesn't exist.
Invalid AUI Tree: Multiple Start Menu nodes The AUI Tree contains two Start Menu Nodes - should not happen.

The Abstract User Interface

The Abstract User Interface (AUI) is a DOM tree describing the objects of the User Interface of a Program at a given time. A copy of the AUI tree is held by both the Front End and the Runtime System. AUI Tree synchronization is automatically done by the Runtime System using the Front End Protocol. The programs can manipulate the AUI tree by using built-in classes and XML utilities.

What does the Abstract User Interface tree contain?

The Abstract User Interface defines a tree of objects organized by parent/child relationship. The different kinds of user interface objects are defined by attributes. The AUI tree can be serialized as text according to the XML standard notation.

The following example shows a part of an AUI tree defining a Toolbar serialized with the XML notation:

<ToolBar>
  <ToolBarItem name="f5" text="List" image="list" />
  <ToolBarSeparator/>
  <ToolBarItem name="Query" text="Query" image="search" />
  <ToolBarItem name="Add" text="Append" image="add" />
  ...
</ToolBar>

Manipulating the Abstract User Interface tree

The objects of the Abstract User Interface tree can be queried and modified at runtime with built-in classes like ui.Form, provided to manipulate form elements.

01 DEFINE w ui.Window
02 DEFINE f ui.Form
03 LET w = ui.Window.getCurrent()
04 LET f = w.getForm()
05 CALL f.setElementHidden("groupbox1",1)

In very special cases, you can also directly access the nodes of the AUI tree by using DOM API classes like DomDocument and DomNode. To get the user interface nodes at runtime, the language provides different kinds of API functions or methods, according to the context. For example, to get the root of the Abstract User Interface tree, call the ui.Interface.getRootNode() method. You can also get the current form node with ui.Form.getNode() or search for an element by name with the ui.Form.findNode() method.


XML Node Types and Attribute Names

By tradition BDL uses uppercase keywords, such as LABEL in form files, and the examples in this documentation reflect that convention. The BDL language itself is not case-sensitive. However, XML is case-sensitive, and by convention node types use uppercase/lowercase combinations to indicate word boundaries. In BDL, therefore, the nodes and attributes of an Abstract User Interface tree are handled as follows:

Warning: If you reference Nodes or Attributes in your BDL code, you must always respect the naming conventions.


Actions in the Abstract User Interface tree

The Abstract User Interface identifies all possible actions that can be received by the current interactive instruction with a list of Action nodes. The list of possible actions are held by a Dialog node. An Action node is identified by the 'name' attribute and defines common properties such as the accelerator key, default image, and default text.

Interactive elements are bound to Action nodes by the 'name' attribute. For example, a Toolbar item (button) with the name 'cancel' is bound to the Action node having the name 'cancel', which in turn defines the accelerator key, the default text, and the default image for the button.

When an interactive element is used (such as a form field input, toolbar button click, or menu option selection), an ActionEvent node is sent to the runtime system. The name of the ActionEvent node identifies what Action occurred and the 'idRef' attribute indicates the source element of the action.

See also Front End Events for more details.


The Front End Protocol

The Front End Protocol (FEP) is an internal protocol used by the Runtime System to synchronize the Abstract User Interface representation on the Front End side. This protocol defines a simple set of operations to edit the Abstract User Interface tree. This protocol is based on a command processing principle (send command, receive answer) and can be serialized to be transported over any network protocol, like HTTP for example.

Both the Abstract User Interface and the Front End Protocol are public to allow third parties to develop their own Front Ends. This enables applications to be deployed on very specific Workstations.

Refer to Front End Protocol for more details about the operations supported by this communication protocol.


Special Features

This section describes special features regarding the user interface domain:

Character Conversion Table

Definition

By default, the runtime system expects that the operating system running the programs uses the same character set as the operating system running the front-end. If the character sets are different, you can set an FGLPROFILE configuration parameter to enable character set mapping between the client and the runtime system, when using a single-byte character set runtime system.

Warning: This feature is provided for backward compatibility. With the new protocol, front-ends are able to identify the character set used by the runtime system and automatically make the codeset conversion.

The following FGLPROFILE entry defines the character table conversion file:

gui.chartable = "relative-file-path"

The $FGLDIR/etc directory is searched for this file. The runtime system automatically adds the ".ct" file extension.

Default value : NULL (no conversion).

Example:

gui.chartable = "iso/ansinogr"

The runtime system loads the character table from: $FGLDIR/etc/iso/ansinogr.ct

Warnings:

  1. The runtime system automatically adds the ".ct" file extension.
  2. Character set conversion does not occur when using TUI mode (FGLGUI=0).

Automatic front-end startup

Definition

The runtime system tries to open a connection to the graphical front-end according to the FGLSERVER environment variable. This requires having the front-end already started and listening to the TCP port defined according to FGLSERVER.

In some configurations, such as X11 workstations or METAFRAME/Citrix Winframe or Microsoft Windows Terminal Server, each user may want to start his own front-end to have a dedicated process. This can be done by starting the front-end automatically when the Genero program executes, according to the DISPLAY (X11) or SESSIONNAME/CLIENTNAME (WTSE) environment variables.

Usage:

By default the runtime system always tries to connect to a front-end according to FGLSERVER. If this variable is not set, it tries to connect to the "localhost:0" GUI server. If this still does not work, automatic front-end startup takes place, if the gui.server.autostart.cmd FGLPROFILE entry is set.

Warning: If the gui.server.autostart.cmd entry is not defined, automatic front-end startup does not occur.

To enable automatic front-end startup, you configure gui.server.autostart.* entries in FGLPROFILE.

The 'cmd' entry can be used to define what command should be executed to start the front-end:

gui.server.autostart.cmd = "gdc -p %d -q -M"

Here, %d will be replaced by the TCP port the front-end must listen to.

By default the runtime system waits for two seconds before it tries to connect to the front-end. You can change this delay with the 'wait' entry:

gui.server.autostart.wait = 5   -- wait five seconds

The runtime system tries to connect to the front-end ten times. You can change this with the 'repeat' entry:

gui.server.autostart.repeat = 3 -- repeat three times

The following FGLPROFILE entries can be used to define workstation id to front-end id mapping:

gui.server.autostart.wsmap.max = 3
gui.server.autostart.wsmap.1.names = "fox:1.0,fox.sxb.4js.com:1.0"
gui.server.autostart.wsmap.2.names = "wolf:1.0,wolf.sxb.4js.com:1.0"
gui.server.autostart.wsmap.3.names = "wolf:2.0,wolf.sxb.4js.com:2.0"

The first 'wsmap.max' entry defines the maximum number of front-end identifiers to look for. The 'wsmap.N.names' entries define a mapping for each GUI server, where N is the front-end identifier. The value of those entries defines a comma-separated list of workstation names to match.

On X11 configurations, a workstation is identified by the DISPLAY environment variable. In the above example, "fox:1.0" identifies a workstation that will make the runtime start a front-end with the number 1.

On Windows Terminal Server, the CLIENTNAME environment variable identifies the workstation. If no corresponding front-end id can be found in the 'wsmap' entries, the front-end number defaults to the id of the session defined by the SESSIONNAME environment variable, plus one. The value of this variable has the form "protocol#id"; for example, "RDP-Tcp#4" would automatically define a front-end id of 5 (4+1).

Tips:

  1. If the front-end processes are started on the same machine as the runtime system, you do not need to set the FGLSERVER environment variable. This will then default to 'localhost:id', where id will be detected according to the 'wsmap' workstation mapping entries.

  2. If the front-end is executed on a middle-tier machine that is different from the application server, MIDHOST for example, you can set FGLSERVER to "MIDHOST" without a GUI server id. The workstation mapping will automatically find the id according to 'wsmap' settings.

  3. Some clients, such as the Genero Desktop Client (GDC), raise the control panel to the top of the window stack when you try to restart it. In this case the program window might be hidden by the GDC control panel. To avoid this problem, you can use the -M option to start the GDC in minimized mode.