The user runs the DS9 executable from the command line either as simply
bash> ds9and then using the menus to select files to display.
They can alternatively specify an image file to display on the command line
bash> ds9 image.fits
Of course there are a plethora of command line options and configuration file choices that can do more sophisticated things, but usually users do one of the above two things.
What happens now in the code?
The main() Tcl/TK program is in ds9/unix/tkAppInit.c. It is compiled with symbols TK_LOCAL_APPINIT=SAOAppInit and TK_LOCAL_MAIN_HOOK=SAOLocalMainHook which override the default TK interface with our home grown ones, so that the first subroutine to run is SAOLocalMainHook~ and this is followed by a call to Tk:
Tk_Main( argv, argc, SAOAppInit);
The first routine, SAOLocalMainHook, defines the startup script as libary/ds9.tcl (the version in the ds9.zip section of the executable, accessed via the zipfs virtual file system). It also tells TCL/TK to look for TCL and TK in zipfs:/mntpt/tcl8.6 and zipfs:/mntpt/tk8.6.
Next, SAOAppInit initializes zipfs using TclZipfs_Init. It then starts Tcl_Init and Tk_init, and initializes all the various subsystems (TKblt, Tktable, Tls, Tksao, Tkhtml1, Tclxpa, Tclfitsy, Tkmpeg, Tksvg, Tkagif, Tclxml, Tclxmlrpc, Tkimg, Zlibtcl, Jpegtcl, Tkimgjpeg, Tifftcl, Tkimgtiff, Tkimgwindow, and Signal_Ext.).
(Note that one of the routines called here is Tksao_Init, found in tksao/saotk.C, which creates DS9 frames, colorbars, panner, magnifier, etc.)
Then, Tk_main~begins its event loop, taking commands from the ds9.tcl startup script.
ds9.tcl defines frams and menus, starts up the XPA and SAMP interprocess communication, loads preferences, and creates the main image frame. Finally it calls `wm deiconify $ds9(top)' to raise the main window, and you are up and running with interactive DS9 driven by the TK event loop.
Note that if your machine is not connected to the internet, XPA startup and thus DS9 startup will hang, unless you have set the environment variable XPA_METHOD to "local".
On an X11 machine that is disconnected from the internet you may get the following error message
_X11TransSocketINETConnect: Can't get address for foo.bar.edu couldn't connect to display "foo.bar.edu:0.0"
This means that DS9 is unable to determine a valid X11 Display server. You can fix this by doing the following:
$ xhost + $ set DISPLAY=:0.0 $ export DISPLAY $ ds9
[Fig4]Process flow in pixel rendering
This figure illustrates the logical data flow necessary to render pixel values from a FITS image.
For each pixel (i,j) in the frame, DS9 will use the WCS to compute the celestial coordinates for that location. DS9 will then convert that celestial location to the closest pixel location in the FITS image. The pixel value at that location then has to be scaled to the range of colors in the user selected color map. The scaling depends on the type of data being imaged. X-ray images are usually logarithmically scaled whereas Optical images may use linear scaling. The user chooses the scaling. After scaling, the closest index in the color map is chosen. The color map provides a lookup table from scalar pixel value to a red, green, blue color tuple. This value is stored in the display frame buffer. Once all pixel values in the frame have been mapped, the display is updated from the frame buffer.
I want to illustrate the flow of the code when a user takes a mouse action, and how that ends up causing astronomy related routines to be called, and then passing that back to cause the image to be updated. This is just one example.
We assume we are in edit region mode.
In ds9/library/frame.tcl, routine BindEventsFrame, there is a line
$ds9(canvas) bind $which\ [list Button1Frame $which %x %y]
This tells DS9 to associate a Button1 press with the command Button1Frame on the current frame ($which) at the current pixel location (%x %y).
Further down in the same file we find `proc Button1Frame' which implements this command. It looks at which mode you are in with a switch statement. We find the entry "pointer - region" (in this language, the - is an "or": if the mode is 'pointer' OR if the mode is 'region', do this..)
This then calls MarkerButton which is defined in ds9/library/marker.tcl. This looks to see if we are already in a marker, which we aren't yet, so it falls through to the line
MarkerCreate $which $x $y
This looks at the current selected shape type which is 'circle' and calls
MarkerCreateShape $which $x $y
MarkerCreateShape then defines a string called 'cmd', starting with
set cmd "$which marker create $marker(shape) $x $y"and appending parameters to the string depending on the shape type, as well as other properties. Later it does
set imarker(id) [eval $cmd]which saves this command string for execution.
When the command is executed, the parser in tksao/frame/lex.L sees the strings 'marker' and 'create' and returns the tokens MARKER_ and CREATE_.
Then the parser tksao/frame/parser.Y maps MARKER_ and CREATE_. to 'marker :' in the same file and then 'markerCreate :'. This tests the shape type somehow and selects CIRCLE_. The CIRCLE_ option in the markerCreate parser entry calls the C++ routine createCircleCmd:
{fr->createCircleCmd(fr->mapToRef(Vector($2,$3),Coord::CANVAS), $4, currentColor,currentDash,currentWidth,currentFont, currentText,currentProps,NULL,taglist,cblist);}
This routine is found in tksao/frame/frmarker.C; it instantiates a Circle object with 'new Circle' and passes this to the createMarker routine, found in the same file at the line
Marker* Base::createMarker(Marker* m)
this calls `update' to update the pixmap and return a pixel value of some kind.
Somewhere in 'update', a call is made to draw the circle which reaches tksao/frame/circle.C and the routine Circle::Circle, which calls BaseEllipse, defined in tksao/frame/baseellipse.c. This in turn calls marker.C:BaseMarker and thus marker.C, which returns the marker object with its values initialized.
circle.C contans the routine Circle:renderXArcDraw which, like some other routines in this file, makes direct X calls, in this case XDrawArc.
Base::updateBase, Base::updatePixmap draws the pixmaps etc.
tksao/frame/base.C Base:updatePixmap is an important routine; Note the fall throughs in the switch statement. DS9 sets various flags as it goes of things that need to be updated.
If you only need to update the pixmap that's easier, (updateMagnifier and updatePM) but you might need to call BASE as well which also calls updateBase, updatePanner; and in the worse case of case MATRIX you first need to update all the coordinate matrices (computationally expensive) and then do the BASE and PIXMAP updates as well.
The updatePM routine will make an XCopyArea call for the pixmap update. The actual flushing of the X buffer to the screen is done by the Tcl/TK event loop itself.