488 lines
18 KiB
Plaintext
488 lines
18 KiB
Plaintext
Written by: Simon Prior
|
|
Date: 25/08/97
|
|
|
|
GUI
|
|
----
|
|
|
|
The purpose of this program is to be the first XVT/Geant4 GUI prototype.
|
|
|
|
Basic idea: Construct a prototype GUI which interacts with Geant 4.
|
|
|
|
Future use: After initial investigation into how XVT can interact etc with
|
|
Geant, seeing what features I can use/exploit, it should be
|
|
possible for future XVT GUI developers to build on the work
|
|
done adding functionality and design ideas thus constructing one
|
|
possible GUI for use with Geant 4. It should be different in
|
|
design/features offered from other implementations so as to
|
|
promote the use of XVT with Geant4 which will cost money (as XVT is
|
|
not free) rather than the use of say TCL which is free.
|
|
|
|
Discoveries and implementation specifics :
|
|
|
|
For this part I shall go through the files which I have edited and
|
|
explain each part - the idea as well as implementation details.
|
|
|
|
I will give an abstract view to show my overall idea and then a
|
|
detailed one which will highlight implementation specifics.
|
|
|
|
The two files that do all the work regarding connection to Geant
|
|
and handling of all user input are "g4xvtwin.h" and "g4xvtwin.cxx"
|
|
- the 'window' files. These are both well commented.
|
|
|
|
Some of the other files have been added to (mainly for the floating
|
|
dockable palettes - see my Geant4 web page or palette documentation
|
|
in the 'palettes' directory).
|
|
|
|
I shall go through both files with a fine toothed comb and explain
|
|
as much as possible. (each method will be looked at carefully - if
|
|
need be).
|
|
|
|
==============================================================================
|
|
|
|
Abstract view of the prototype:
|
|
-------------------------------
|
|
|
|
OK, start the XVT GUI, GUI then spawns the Geant benchmark program. The user
|
|
interacts with the GUI via appropriate widgets selecting and executing
|
|
commands, these are sent to Geant which does the processing, Geant then
|
|
relays any information back to the user via the GUI.
|
|
|
|
==============================================================================
|
|
|
|
More Detailed view:
|
|
-------------------
|
|
|
|
My main idea(s) for this interface:
|
|
|
|
Basically, the application starts (by executing the XVT GUI
|
|
executable file).
|
|
|
|
This handles all the initialisation required for the IPC mechanism,
|
|
it is in charge of creating the named pipes and opens them at the
|
|
XVT end with the appropriate permissions on them.
|
|
|
|
Then it handles the startup of the Geant 'xvt.benchmark' file.
|
|
|
|
It basically forks off a process and execs the xvt.benchmark file.
|
|
|
|
See the xvt.benchmark documentation for the ideas behind that and a
|
|
detailed description of what happens when it is executed.
|
|
|
|
==============================================================================
|
|
|
|
I will now cover some of the major parts and ideas of the interface before
|
|
analysing the individual methods:
|
|
|
|
==============================================================================
|
|
|
|
The named pipes:
|
|
----------------
|
|
|
|
This was the chosen IPC method after reviewing several IPC mechanisms (See
|
|
the IPC section on my Geant4 web page). It works like the twoWay
|
|
program - incorporating a timer in the XVT end to read the pipe, a suitable
|
|
way of testing the pipe before reading it (blocking issues) etc - see the
|
|
early work in the IPC section or the program code for details.
|
|
|
|
The data Structures:
|
|
--------------------
|
|
|
|
Now, this was a new idea. I had to get all the command information from Geant
|
|
and transfer it via the pipes and then use it to build a suitable dynamic
|
|
widget at the XVT end. Therefore, the idea behind it all is simple, build a
|
|
data structure at the Geant end and fill it with command information, then when
|
|
requested by XVT, send all the information down the pipe. At the XVT end, parse
|
|
this information into a data structure at this end and then build the widget
|
|
etc using this data structures contained information.
|
|
|
|
The new data structures I defined were G4CommandData and G4ParameterData. (See
|
|
the header file "g4xvtwin.h" for implementation specifics.
|
|
|
|
Some important issues were encountered. It became clear that a certain
|
|
'protocol' had to be defined so that I could recognise command information etc
|
|
- this will be explained when documenting the individual method in detail.
|
|
|
|
The Palettes:
|
|
-------------
|
|
|
|
These were a new provided widget with XVT version 4.5 and were exactly what I
|
|
required. (I was working to emulate their behaviour before the release came
|
|
out). The best feature of them is that they are dynamic and can be created at
|
|
run time etc - thus giving the flexibility needed for Geant.
|
|
|
|
As they are like an artists palette the first point is that you make a
|
|
selection and it stays selected - this suited my idea well as I had the idea
|
|
to have all the command information in one palette - i.e. select a command from
|
|
this palette, then have a button which you press to 'Execute' the selected
|
|
command. I have since added a 'Help' button which you can also press - this
|
|
gives a small message about the selected command.
|
|
|
|
- This is my idea for command entry to date:
|
|
|
|
1.. Select command.
|
|
2.. If help is required click help button for information.
|
|
3.. If you are sure, press Execute which will dispatch the command to Geant.
|
|
|
|
Thus it gives a level of security so that selecting a command doesn't
|
|
necessarily mean it gets executed - until you EXPLICITLY say so.
|
|
|
|
Command Retrieval:
|
|
------------------
|
|
|
|
The idea behind this is quite clever. OK, firstly, on the geant side of
|
|
things. This reads all the commands from the Geant command tree using 'get'
|
|
methods from the Command tree class. All of the commands are read into a type
|
|
I have defined - called G4CommandData - this basically holds all the
|
|
information on a command and its parameters. (see data structures section
|
|
mentioned earlier)
|
|
|
|
Now back to the GUI end. After this has initialised itself and listed all the
|
|
available commands the user can click on a button to retrieve all the available
|
|
commands from Geant. When this happens a command is sent from the GUI down the
|
|
named pipes to Geant. When Geant receives this command it parses the command
|
|
array at that end and writes all the information down the named pipe to XVT.
|
|
|
|
XVT also has the same data structure declared and basically reads all the
|
|
information from the pipe into its own structure.
|
|
|
|
After this is done the floating command palette is constructed using the
|
|
information contained in the data structure at the XVT end.
|
|
|
|
I have defined a protocol so that XVT recognises when the commands are coming
|
|
down the pipe.
|
|
|
|
As the timer ticks and calls the DoTimer method this checks to see if there is
|
|
anything present in the pipe - if so reads it and decides what to do with it.
|
|
|
|
When it receives the string "comTree" it knows that the commands are coming.
|
|
|
|
I basically bypass the timer for a while and then call some methods to deal
|
|
with the incoming data. The first string that comes through is an integer
|
|
which tells me exactly how many command entries there are - then a loop can
|
|
be entered to fill the array at the XVT end with that number of entries.
|
|
|
|
All the appropriate casting and type changes are handled correctly. (i.e.
|
|
converting from string to integer).
|
|
|
|
You have to be careful when reading the pipe that you check there is something
|
|
present before actually reading it - especially in this case when order of
|
|
information is critical - thats why I defined a method (getString) to handle
|
|
correct reading of the named pipe. (it waits until thers is something present
|
|
before reading and returning the string).
|
|
|
|
==============================================================================
|
|
|
|
Now I shall look at the header file g4xvtwin.h and then I shall look at
|
|
the implementation file g4xvtwin.cxx in detail to explain what the methods
|
|
do etc.
|
|
|
|
==============================================================================
|
|
|
|
g4xvtwin.h:
|
|
-----------
|
|
|
|
First thing to note in this file is the #defines which define XvtToGeant and
|
|
GeantToXvt. These are names I will use in my code for the named pipes which
|
|
I set up for communication between the XVT executable and the Geant4 executable.
|
|
|
|
The next #define simply defines the file mode (i.e. appropriate UNIX
|
|
permissions) to open the named pipes with.
|
|
|
|
After this come several #includes which include various functions I will
|
|
use in the code.
|
|
|
|
After this I define 2 new types called 'G4parameterData' and 'G4commandData'.
|
|
These are structures to hold information about commands.
|
|
|
|
After this are the usual method declarations and data member definitions
|
|
etc. - These are commented.
|
|
|
|
******************************************************************************
|
|
*************************** IMPORTANT ***************************************
|
|
*** ***
|
|
*** The declaration of 'G4commandData commandArray[200];' in the header ***
|
|
*** file basically declares how many commands can be stored in the array ***
|
|
*** and then used to create the command palette. ***
|
|
*** IF during future use the GUI coredumps when creating the command ***
|
|
*** palette it is most likely that there are greater that 200 commands ***
|
|
*** - especially as commands are being added all the time. All you need ***
|
|
*** to do is increase this value and everything will work fine again. ***
|
|
*** ***
|
|
******************************************************************************
|
|
|
|
==============================================================================
|
|
|
|
g4xvtwin.cxx:
|
|
-------------
|
|
|
|
I shall cover the methods which I have written or added code to - the ones
|
|
automatically generated are self explanatory and have good commenting (see
|
|
file for more details).
|
|
|
|
The Constructor:
|
|
----------------
|
|
|
|
Initialisation occurs here by calling several initialiser functions - see their
|
|
own documentation later on (next).
|
|
|
|
initIndex:
|
|
----------
|
|
|
|
This initialises the command base array indexing variables - very simple.
|
|
|
|
initStatusBar:
|
|
--------------
|
|
|
|
This sets up the status bars fields with some initial values.
|
|
|
|
initTimer:
|
|
----------
|
|
|
|
Starts the XVT timer (on every time interval (which the coder can alter) it
|
|
activates the DoTimer method).
|
|
|
|
initIPC:
|
|
--------
|
|
|
|
This sets the value of the pipe reading variable (i.e. how many bytes are
|
|
read in a single read operation and then calls createNamedPipes and startSlave.
|
|
|
|
initFrame:
|
|
----------
|
|
|
|
Creates an attachment frame and allows attachment to all sides.
|
|
|
|
createNamedPipes:
|
|
-----------------
|
|
|
|
This method creates the named pipes required in the application.
|
|
|
|
It first creates the pipes and then opens them.
|
|
|
|
The XvtToGeant pipe with write permission only,
|
|
the GeantToXvt with read permission only.
|
|
|
|
The program uses the errorHandler method to report errors because the
|
|
program should terminate if IPC setup fails.
|
|
|
|
destroyNamedPipes:
|
|
------------------
|
|
|
|
This method closes and unlinks all the open named pipes.
|
|
|
|
startSlave:
|
|
-----------
|
|
|
|
This method forks and exec's the other process (xvt.benchmark - the Geant
|
|
executable).
|
|
|
|
This method also uses the errorHandler to report errors because if the
|
|
fork or Exec fail the program should terminate.
|
|
|
|
The fork and exec are UNIX specific - for more details on their use see a UNIX
|
|
manual or man pages.
|
|
|
|
DoTimer:
|
|
--------
|
|
|
|
Every time the timer ticks this method checks to see if the file descriptor
|
|
can be read without blocking (i.e. there is something in the pipe), if
|
|
there is it grabs the data from the pipe, if you are not in the process of
|
|
reading all the commands from Geant it then checks if the string is equal to
|
|
"comTree" which indicates all the commands are coming from Geant and
|
|
different action should be taken. If it isn't comTree then it simply
|
|
displays the string in the Main log area.
|
|
|
|
The different action to take is to call some other methods to do the reading of
|
|
commands and building of the command palette. (discussed later.)
|
|
|
|
Refer to code for the implementation specifics.
|
|
|
|
errorHandler:
|
|
-------------
|
|
|
|
A general purpose error handler. It can be called by any method. A string
|
|
is passed so that this method can post a dialog box to the user stating
|
|
where the program fault occurs then quit the GUI.
|
|
|
|
The key point is that this method should be called when processing should no
|
|
longer continue i.e. the GUI should be killed.
|
|
|
|
writeData:
|
|
----------
|
|
|
|
Writes the passed string to the Command log window and the XvtToGeant
|
|
pipe - i.e. will send the string to Geant (commands!) for processing.
|
|
|
|
initCommandPalette:
|
|
-------------------
|
|
|
|
Allocate storage space for a tool palette.
|
|
|
|
destroyCommandPalette:
|
|
----------------------
|
|
|
|
Free up storage space allocated for the command palette.
|
|
|
|
buildCommandPalettes:
|
|
---------------------
|
|
|
|
This method builds the palettes of commands available to the user.
|
|
|
|
This basically parses the commandArray that was received from Geant and
|
|
builds up the command palette 'on-the-fly' from this information.
|
|
|
|
It checks the flag of the command in the array to see whether it is
|
|
a 'directory', a command or a cascade. (this is denoted by the flag being a
|
|
0, 1 or 2 and this is set at the Geant end when it reads in the commands).
|
|
|
|
Once it has this information it can decide how to handle it.. If it is a
|
|
'directory' - i.e. a category of command it must have its own sub-palette
|
|
so this can be constructed. If it is a command it must be a button in the
|
|
current sub-palette and if it is a cascade it must be a sub-palette of the
|
|
current palette - see code for implementation specifics.
|
|
|
|
destroyDragSource:
|
|
------------------
|
|
|
|
This method destroys the space allocated for the drag source.
|
|
|
|
setStatus:
|
|
----------
|
|
|
|
This method places the passed string into the status field of the status
|
|
bar.
|
|
|
|
resetStatus:
|
|
------------
|
|
|
|
This method completely blanks the status field of the status bar.
|
|
|
|
retrieveCommand:
|
|
----------------
|
|
|
|
This method checks the command palette to see which button has been pressed
|
|
then it will scan the command array to find the command that corresponds to
|
|
the users selection and returns the command string to be sent to Geant.
|
|
|
|
It also tests to see if the command that is selected for execution requires a
|
|
parameter and if so calls 'getParameters' to obtain this from the user.
|
|
|
|
initTextWindows:
|
|
----------------
|
|
|
|
This method simply puts a title in the Text windows to start things off.
|
|
|
|
fillLocalArray:
|
|
---------------
|
|
|
|
This method fills the command data structure at the XVT end with data that is
|
|
being received from the Geant end. It uses the method 'getString' to grab the
|
|
strings from the pipe without error.
|
|
|
|
showHelp:
|
|
---------
|
|
|
|
This method is called when the user clicks on the 'help' button.
|
|
|
|
It looks which is the current selected tool and retrieves the guidance for
|
|
that tool - then puts this in the text widget and a pop up window.
|
|
|
|
getParameters:
|
|
--------------
|
|
|
|
This method retrieves parameters from the user via dialog boxes. - called by
|
|
retrieveCommand.
|
|
|
|
getTextCommand:
|
|
---------------
|
|
|
|
This method retrieves parameters from the user via dialog boxes. This method
|
|
is very similar to 'getParameters' however this one is called if the user
|
|
wishes to type a command in instead of using the command palette widget.
|
|
|
|
executeCommand:
|
|
---------------
|
|
|
|
When the user clicks on the execute button this method is called.
|
|
|
|
It retrieves the command (with parameters if necessary) and writes it
|
|
down the named pipe to Geant to deal with.
|
|
|
|
getString:
|
|
----------
|
|
|
|
This method grabs the string that is located in the pipe and returns it
|
|
to the caller - provided there is something present in the pipe.
|
|
|
|
activateButtons:
|
|
----------------
|
|
|
|
This method enables the 'exec' buttons on the toolbar. It is called just
|
|
after the user has retrieved the commands and built the widget.
|
|
|
|
It first enables the buttons and then refreshes the screen by redrawing
|
|
them.
|
|
|
|
I have tried to limit the mistakes a user could make and this is a very good
|
|
way of doing just that - by disabling buttons/widgets etc that could cause
|
|
problems if pressed/clicked on at the wrong time.
|
|
|
|
==============================================================================
|
|
|
|
NOTE: Any code not mentioned here is self explanatory and well commented.
|
|
|
|
==============================================================================
|
|
|
|
Now I a couple of XVT specific discoveries to mention:
|
|
|
|
DISCOVERY 1:
|
|
|
|
There is some sort of problem with Dialog boxes and floating dockable palettes.
|
|
|
|
I had a palette which contained a button, when this button was pressed it
|
|
called one of the pre-defined dialogs, this however caused a lock up concerning
|
|
the mouse - I couldn't get control back, the dialog seemed to keep it.
|
|
What happened exactly was when you clicked the button down it didn't pop up
|
|
again thus it wasn't receiving the mouse up event. When you did click the
|
|
mouse again however it spawned the dialog - again and again, it sort of
|
|
entered a loop repeatedly spawning the dialog. - Technical support said that
|
|
the dialog must have been inadvertently destroying the mouse handlers.
|
|
|
|
DISCOVERY 2:
|
|
|
|
You cannot have a toolbar with buttons in and a CAttachmentFrame which
|
|
encomapasses the whole window because if you do, the CAttachmentFrame
|
|
obscures all of the mouse events from reaching the toolbar - thus none
|
|
of the buttons react.
|
|
|
|
A solution to this problem is to have a CAttachmentFrame that doesn't
|
|
cover the entire window, just a part of it (this can be acheived with
|
|
a certain constructor - see code) - thus the events can then
|
|
get to the toolbar.
|
|
|
|
DISCOVERY 3:
|
|
|
|
For some reason you cannot pass a WINDOW variable between a view and a
|
|
document - when I tried it the program kept core dumping on this.
|
|
|
|
DISCOVERY 4:
|
|
|
|
The Select() system call has been dropped. The reason is that it was failing
|
|
for some reason which I couldn't work out. It kept returning TRUE all the
|
|
time when I used it to see if the named pipe was ready for reading and this
|
|
was not always the case.
|
|
|
|
The solution I came up with was to use a function from the ioctl library.
|
|
The function I used is the following:
|
|
|
|
int nbytes;
|
|
ioctl(fd_XvtToGeant, FIONREAD, &nbytes);
|
|
|
|
This is much better than select because I only have a single file descriptor
|
|
to test and using this is far shorter and easier to code/understand than the
|
|
select stuff.
|
|
|
|
==============================================================================
|
|
S.Prior - August '97
|