19.2 Concurrency and User Interface Environments

Graphical user interface environments are usually event-driven in the sense that actions in the program are executed as a response to user input events. To handle this, a separate implementation of systemenv exists for the user interface library guienv:

Please note, that programs should only use one of the systemenv, xsystemenv, and guienvsystemenv fragments.

Suppose that we like to extend the texteditor above with a clock that should be updated every second. A clock can easily be made using the basic systemenv:

Program 27: Clock.bet

ORIGIN '~beta/basiclib/systemenv';
INCLUDE '~beta/sysutils/time';
-- program: descriptor --
systemEnv
(# 
   updateClock: @|System
     (# 
     do cycle
        (#
        do 1 -> sleep; 
           systemtime -> formattime -> putline;
        #);
     #);
do updateClock[] -> fork; 
#)

Here we simply print out the current system time on the screen. Notice, that we have included a new library called time in '~beta/sysutils/time'. This library contains facilities for getting the date and time, time usage, and for formatting times for nice printing. Running the program shown above gives the following result:

Tue Aug 23 11:48:35 1994
Tue Aug 23 11:48:36 1994
Tue Aug 23 11:48:37 1994
Tue Aug 23 11:48:38 1994
Tue Aug 23 11:48:39 1994
Tue Aug 23 11:48:40 1994
Tue Aug 23 11:48:41 1994
Tue Aug 23 11:48:42 1994
Tue Aug 23 11:48:43 1994
Tue Aug 23 11:48:44 1994
Tue Aug 23 11:48:45 1994
Tue Aug 23 11:48:46 1994
Tue Aug 23 11:48:47 1994
Tue Aug 23 11:48:48 1994
Tue Aug 23 11:48:49 1994

Now we want to integrate this clock in our GUIEnv texteditor program, so we can always see the time in the low left corner of the window. We need to use the '~beta/guienv/guienvsystemenv':

ORIGIN  '~beta/guienv/guienvsystemenv';
INCLUDE '~beta/guienv/fields'
        '~beta/guienv/stddialogs'
        '~beta/basiclib/file'
        '~beta/sysutils/time'
-- program: descriptor --
systemenv
(# 
   setWindowEnv:: (* tell systemenv that myguienv is the
                   * the graphical user interface
                   *)
     (# do myguienv[] -> theWindowEnv[] #);
   
   updateClock: @|System
     (# 
     do cycle
        (#
        do 1 -> sleep; 
           systemtime -> formattime -> ... ;
                            (* put time into the clock *)
        #);
     #);
                
   myguienv: @guienv (* inherit from guienv *)
     (# (* guienv code as before *)
     #);

do (* fork updateClock as a separate system *)
   updateClock[] -> fork;
#)

We need to specify to systemenv what graphical user interface system we are using. This is done by extending the virtual setWindowEnv like the following:

setWindowEnv::(# do myguienv[] -> theWindowEnv[] #);

In order to do that, we have changed the guienv into a static object called myguienv. myguienv will automatically be started by systemenv.

Finally, we need to create a user interface element that can show the time. We use a staticText, that we position below the TextEditor field:

clock: @staticText
  (# open::
       (# w,h: @integer;
       do systemtime -> formattime -> label;
          theWindow.size -> (w,h);
          (5,h-16) -> position; (50,15) -> size;
          True -> BindBottom; False -> BindTop;
       #);
  #);

The complete program is:

Program 28: ClockTextEditor.bet

ORIGIN '~beta/guienv/guienvsystemenv';
INCLUDE '~beta/guienv/fields'
        '~beta/guienv/stddialogs'
        '~beta/basiclib/file'
        '~beta/sysutils/time';
-- program: Descriptor --
systemEnv
(#
   setWindowEnv::<  (#  do myguienv[]->theWindowEnv[] #);
   updateClock: @|System
     (# 
     do
        cycle
        (# theText: @StyledText; 
        do 1->sleep;
           systemtime->formattime-> myguienv.theWindow.clock.label;
        #);
     #);
   myguienv: @guienv (* inherit from guienv *)
     (# theWindow: @window (* make a window *)
          (# menubarType:: (* extend the menubar *) 
               (# fileMenu: @menu (* make a file menu *)
                    (# textFile: @file;
                       openItem: @menuitem (* make an open item *)
                         (# eventHandler::
                            (* extend the virtual that is called *) 
                              (# onSelect:: 
                                 (* this menu item is selected *) 
                                   (# theText: @StyledText; 
                                   do theWindow[]->
                                        fileSelectionDialog->
                                        textFile.name;
                                      textFile.openRead;
                                      textFile.scan
                                        (# while::(#do true->value#);
                                        do ch->theText.put
                                        #);
                                      theText[]->
                                      theTextEditor.contents.
                                                    contents;
                                      textFile.close;
                              #)#);
                            open::  (#  do 'Open'->name #);
                         #);
                       saveItem: @menuitem (* make a save item *)
                         (# eventHandler::
                            (* extend the virtual that is called *) 
                              (# onSelect:: 
                                 (* this menu item is selected *) 
                                   (# theText: @Text; 
                                   do
                                      textFile.openWrite;
                                      theTextEditor.contents.
                                                    contents->
                                        textFile.puttext;
                                      textFile.close;
                                   #)
                              #);
                            open:: (# do 'Save'->name #);
                         #);
                       quitItem: @menuitem (* make a quit item *)
                         (# eventHandler:: 
                              (# onSelect:: (#  do Terminate #) #);
                            open:: (#  do 'Quit'->name #);
                         #);
                       open:: 
                       (* extend the open virtual of filemenu 
                        * to open the items *)
                         (# 
                         do 'File'->name;
                            openItem.open;
                            openItem[]->append;
                            saveItem.open;
                            saveItem[]->append;
                            quitItem.open;
                            quitItem[]->append;
                         #)
                    #);
                  open::
                  (* extend the open virtual of the menubar
                   * to open the filemenu *)
                   (# do fileMenu.open; fileMenu[]->append #);
               #);
             thetextEditor: @textEditor (* our text editor *)
               (#
                  open::
                  (* extend the open virtual to set the size 
                   * and the placement *)
                  (# w,h: @integer; 
                    do theWindow.size->(w,h);
                       (w,h-20)->Size;
                       True->bindBottom;
                       True->bindRight
                    #);
               #);
             clock: @staticText
               (# open:: 
                    (# w,h: @integer; 
                    do systemtime->formattime->label;
                       theWindow.size->(w,h);
                       (5,h-16)->position;
                       (300,15)->size;
                       True->BindBottom;
                       False->BindTop;
                    #);
               #);
             open::
             (* extend the window open virtual
              * to open the textEditor *) 
               (#  do thetextEditor.open; clock.open;  #);
          #);
     do theWindow.open; 
        (* open the window when the application start up *) 
     #)
do updateClock[]->fork; 
#)

The following figure shows a snapshot of the program running on Motif:

19.3 Changes from the Original Design

The abstractions defined here are based on the ones described in chapter 12 of the BETA book. The implementation is identical to the design in the BETA book, except for the following changes:

conc(# do S1[]->start; S2[]->start; S3[]->start #)
alt (# do S1[]->start; S2[]->start; S3[]->start #)

This implementation of systemenv includes some new facilities, not described in the BETA book:

In order to implement real concurrency, an interrupt mechanism must be implemented. This is currently not done. A component/system will thus keep the control until it makes an explicit or implicit SUSPEND. An implicit SUSPEND is made when a component must wait for a semaphore, or executes the pause and sleep patterns.

The systemenv libraries are thoroughly described in the manual [MIA 94-25]


Libraries Tutorial
© 1994-2002 Mjølner Informatics
[Modified: Monday November 12th 2001 at 20:37]