diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /unix/sun | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'unix/sun')
-rw-r--r-- | unix/sun/Gterm.hlp | 198 | ||||
-rw-r--r-- | unix/sun/Imtool.hlp | 420 | ||||
-rw-r--r-- | unix/sun/Makefile | 67 | ||||
-rw-r--r-- | unix/sun/README | 5 | ||||
-rw-r--r-- | unix/sun/arrow.c | 66 | ||||
-rw-r--r-- | unix/sun/fifo.c | 759 | ||||
-rw-r--r-- | unix/sun/gterm.c | 1984 | ||||
-rw-r--r-- | unix/sun/gterm.esc | 46 | ||||
-rw-r--r-- | unix/sun/gterm.h | 18 | ||||
-rw-r--r-- | unix/sun/gterm.icon | 34 | ||||
-rw-r--r-- | unix/sun/gterm.icon.OLD | 34 | ||||
-rw-r--r-- | unix/sun/gterm.man | 784 | ||||
-rw-r--r-- | unix/sun/gtermio.c | 1224 | ||||
-rw-r--r-- | unix/sun/halley.lut | 257 | ||||
-rw-r--r-- | unix/sun/heat.lut | 257 | ||||
-rw-r--r-- | unix/sun/imtool.c | 4488 | ||||
-rw-r--r-- | unix/sun/imtool.cross | 4 | ||||
-rw-r--r-- | unix/sun/imtool.cursor | 4 | ||||
-rw-r--r-- | unix/sun/imtool.h | 13 | ||||
-rw-r--r-- | unix/sun/imtool.icon | 66 | ||||
-rw-r--r-- | unix/sun/imtool.icon.NEW | 34 | ||||
-rw-r--r-- | unix/sun/imtool.man | 713 | ||||
-rw-r--r-- | unix/sun/imtool.square | 4 | ||||
-rw-r--r-- | unix/sun/imtoolrc | 48 | ||||
-rwxr-xr-x | unix/sun/mksuntool.csh | 39 | ||||
-rw-r--r-- | unix/sun/mouse.c | 47 | ||||
-rw-r--r-- | unix/sun/notify_read.c | 85 | ||||
-rw-r--r-- | unix/sun/screendump.c | 549 | ||||
-rw-r--r-- | unix/sun/ss1.patch | 31 |
29 files changed, 12278 insertions, 0 deletions
diff --git a/unix/sun/Gterm.hlp b/unix/sun/Gterm.hlp new file mode 100644 index 00000000..d97b4407 --- /dev/null +++ b/unix/sun/Gterm.hlp @@ -0,0 +1,198 @@ +.help gterm Dec86 "Vector Graphics for the Sun Workstation" +.sp 2 +.ce +\fBVector Graphics for IRAF on the Sun Workstation\fR +.ce +Doug Tody +.ce +December, 1986 +.ce +(design document) +.sp 3 +.NH +Graphics Terminal Model + + The window based, native vector graphics facility for Sun/IRAF will be +implemented as a purely data driven interface based on the concept of an +intelligent virtual graphics terminal. The virtual graphics terminal will +be implemented in software as a process running under a window system such +as Sunview or X. + +A virtual terminal interface will allow the Sun workstation to be used as an +ordinary graphics terminal to access IRAF or other software on either the +local or a foreign host via any data stream interface, e.g., rlogin, telnet, +or a modem connection. For example, one will be able to use telnet running +in a GTERM window to login on a VMS machine, then run IRAF on the VMS machine +in the normal fashion. Conversely, since the IRAF software on the Sun node +will always think that it is talking to a conventional data driven graphics +terminal, the Sun/IRAF software may in fact be run from a conventional +graphics terminal, via either a direct or remote login. Finally, a pure data +stream TTY interface where all details of the windowing system are isolated +into a server process makes it possible for a single version of IRAF to support +multiple window systems on the same host. + +The graphics terminal to be implemented by GTERM shall consist of independent +text and graphics frames. These will be implemented as separate windows +(frames) under SunView, allowing them to be moved, resized, exposed, hidden, +open, closed, etc., independently of each other. Note however that since both +frames are connected to the controlling process via a single terminal i/o +connection, the controlling process (e.g., the CL) can only read from or +write to one frame at a time. + +In normal use, the user will work for a time in the text frame, issuing +commands to run tasks which do not require interactive graphics facilities. +When a graphics program is run the graphics frame will be opened or exposed +and the plot drawn. If the graphics program is interactive, i.e., uses +cursor input, the cursor will be moved to the center of the window and the +crosshairs turned on to indicate that cursor input is required. A sequence +of keystroke or mouse button triggered cursor reads will follow, and +eventually graphics mode will be exited by transmission of the close +workstation sequence to GTERM by GIO running in the applications program. + +When graphics mode is exited GTERM terminal i/o is redirected to the text +frame and the cursor is restored to its former position in the text frame, +automatically restoring interactive control to the text frame. The graphics +frame may or may not be closed or hidden, depending upon the GTERM defaults +set up by the user. If the graphics frame is to be closed or hidden this +should probably require interactive confirmation by the user, else the plot +might disappear immediately after being drawn. Since control naturally +toggles back and forth between the text and graphics frames and since screen +space is always limited and a large, high resolution graph is generally +desired, it is expected that the graphics frame will normally be displayed +only while in graphics mode. + +.NH +GTERM Graphics Language + + The tektronix graphics language is a simple and efficient standard language +for graphics terminal i/o which will work about as well as anything in our +application. In particular, the vector encoding scheme is simple, compact and +efficient, and well suited to use with a variety of terminal drivers and +modems (since binary data is avoided). The best approach to implementing the +GTERM graphics language would seem to be to take the tektronix language as a +starting point and add additional functionality by extending the language +with new control sequences. Some of the extensions defined here a taken from +the Retrographics vt640 and the Pericom. Others more specific to window based +applications will be added in the future in an upwards compatible fashion. + + +.ks +.nf + GS open workstation if not already open + open/expose graphics frame (icon -> full window) + direct terminal i/o to graphics frame + save cursor (mouse) position + issue GS dark vector command (see below) + CAN close workstation + restore control to text frame (restore cursor) + close/hide graphics frame (full window -> icon) + keystroke required to trigger close-window? + + + GS (workstation already opened) + enter vector drawing mode, dark vector + FS enter point plot mode + US,CR enter alpha mode + text is drawn in graphics frame + defaults to transparent text, erase permitted + ESC CR enter text mode + lines of text are drawn on status line in + nontransparent (overwrite) mode + + ESC SUB enter crosshair mode + ESC FF clear screen, initialize drawing modes + ESC/f [x,y] set crosshair position + GS [x,y] US sets alpha cursor position + + ESC[0123] set character size (normal,2x,3x,4x) + ESC[`abcd] set line drawing style (normal,dotted,dotdash,sd,ld) + ESC/[012]d set drawing mode (set, clear, toggle) + ESC/[0123]w set polyline linewidth (normal,2x,3x,4x) + + Standard screen resolution is 1024 by 780. + In graphics mode, chars are interpreted as [x,y] coordinate pairs. + In alpha mode, chars are interpreted as characters to be drawn. +.fi +.ke + + +A number of extensions to this basic language are being considered for future +implementation. Support for color, multiple text fonts, general polymarkers, +area fill, and possibly cell array are contemplated, as well as simple +extensions for window control and pop-down menus. Support for the standard +textronix features which have been omitted (vector point elimination, +incremental point mode, status enquiry) is possible. The interface is easily +extensible hence there is no need to attempt to define or support such features +in the initial interface. + +.NH +Implementation Notes + + The GTERM virtual terminal consists of two independent frames, the text +frame and the graphics frame. Selection of the frame to which output is to +be delivered is done at the lowest possible level, i.e., when the read system +call is issued by the terminal to accept terminal output from the pty +(pseudo-terminal driver) stream for the terminal. This is done by linking in +a custom version of the notify_read() primitive, the low level read primitive +for notifer based programs. Output is initially to the text frame. Output +is redirected to the graphics frame when GS is seen in the output stream, +and later restored to the text frame when CAN is seen. Input is controlled +independently by the two frames at a high level, hence does not have to be +switched. + +All terminal operations are event driven. Graphics data is deposited into a +circular input buffer by an event driven read routine, which can issue +<ctrl/s>/<ctrl/q> to the terminal driver to control the rate at which input +is accumulated. A separate drawing routine running off an interval timer +is used to process data appearing in the input buffer. The drawing code is +always in one of three modes: vector drawing mode, alpha mode (randomly +addressable character drawing), or text mode (textual output to the status +line). + +.SH +Appendix: Tektronix Graphics Language (Retrographics vt640) + +.ks +.nf + *GS enter graphics mode; dark vector + *FS enter point plot mode + RS enter incremental point mode + *US,CR enter alpha mode, graphics plane, tek font + CAN disable graphics mode, restore output to terminal plane + + ESC"0g alias for enter transparent mode + ESC"4g alias for enter crosshair mode + ESC"5g enter light pen mode + + *ESC SUB enter crosshair mode + *ESC FF clear screen, initialize drawing modes + *ESC ENQ return cursor position, other status + + ESC[0123] set character size (normal,2x,3x,4x) + ESC[`abcd] set line drawing style (normal,dotted,dotdash,sd,ld) + ESC/[012]d set drawing mode (set, clear, toggle) + + ESC/f set crosshair position + *GS [x,y] US sets alpha cursor position + + Vector coordinate encoding (max 10 bits = 1024 points res.): + + high y P01XXXXX + low y P11XXXXX + high x P01XXXXX + low x P10XXXXX + + Cursor return structure: + + key PXXXXXXX + high x P01XXXXX + low x P01XXXXX + high y P01XXXXX + low y P01XXXXX + trailer <cr> + + Standard 4010/4012 screen resolution is 1024 by 780. + In graphics mode, chars are interpreted as [x,y] coordinate pairs. + In alpha mode, chars are interpreted as characters to be drawn. +.fi +.ke diff --git a/unix/sun/Imtool.hlp b/unix/sun/Imtool.hlp new file mode 100644 index 00000000..39d42dbe --- /dev/null +++ b/unix/sun/Imtool.hlp @@ -0,0 +1,420 @@ +.help imtool Jan87 "Image Display on the Sun Workstation" +.sp 3 +.ce +\fBImage Display on the Sun Workstation\fR +.ce +Design Specification (prototype display) +.ce +Doug Tody +.ce +January 1987 + +.NH +Introduction + + This document describes the prototype Sunview based SUN/IRAF image display. +The standard Sun-3 color workstation provides an 1152 by 900 by 8 bit frame +buffer (some models are larger) with an associated 256 entry color table and +an RGB display. A keyboard and a three button mouse are provided for +interactive control and command entry. + +In typical interactive use the user will have a number of windows open on the +screen, e.g., a GTERM virtual graphics terminal with text and graphics windows, +the image display window, a small console window, and several icons. +Due to limitations on the amount of screen space available and due to speed +limitations when refreshing a full 8 bit deep window, it is desirable to limit +the size of the image display window to a fraction of the screen space most +of the time. + +Due to the complexity of the task of designing a fully functional, device +independent image display interface, and the need to get at least a basic +image display capability functioning for SUN/IRAF as soon as possible, +a prototype display will be implemented first in January 1987 followed by +the full interface later in the year. Although the prototype will not provide +full functionality or system and device independence, the basic features are +expected to be provided im much the same form that they will take in the final +interface. + +.NH +User Interfaces + + The prototype image display will use the existing TV/DISPLAY program to +load images into the image display. None of the other tasks in the TV package +will be supported and the entire contents of the TV package will disappear +later this year. Display interaction and cursor readback will be via the +same cursor mode interface currently used for the graphics terminal interface. +Additional display-level interaction will be available under mouse control, +e.g., to support display dependent functions not otherwise supported in cursor +mode, such as greyscale windowing, filtering (resampling), region of interest +control, and the like. + +.NH +Display Features +.NH 2 +Image and Graphics Planes + + The display size is a setup configuration parameter but is fixed while the +display is in use. Typical display sizes might be 512, 800, 1024, or 2048 +pixels square, or some rectangular size. Sufficient physical memory should be +available so that the internal frame buffers may be locked into memory. + +The image display will be 7 bits deep with 1 bit of graphics +overlay, leaving half of the color table entries for use by other +graphics windows. The image may be windowed without affecting the +color table entries of the other windows on the screen. If 7 bits +of greyscale proves to be a serious limitation something on the order +of 7.9 bits is possible by playing tricks with the software (clever +use of the color table). This latter feature will not be available +in the initial prototype. + +The prototype display will provide N image frames, all of which must be the +same size, each with its own independent lookup table and viewport. +The frame size and number of frames are arbitrary and will be a setup option. +Blinking, split screen, true color representation, and other operations +involving simultaneous display of multiple frames will not be implemented +n the prototype display. + +The full display will support N image frames, each with an associated 1 bit +graphics overlay, with all frame-graphics pairs the same size, and with +support for multiple screen operations such as blink and split screen. +Independent lookup tables will not be possible in split screen mode, +but this may not be a serious problem given the autoscaling algorithm in +the DISPLAY task, and the possibility of normalization of multiple image +frames to use a common lookup table (by modifying the loaded pixel values), +once the lookup table has been independently adjusted for each frame. + +.NH 2 +Pseudocolor and True Color + + Pseudocolor will probably not be supported in the initial prototype, +although it may be added to the prototype before the final interface is written. +True color can probably be provided in the final interface by maintaining an +independent lookup table for each of the three frames (RGB) in software, +generating the compound output in software, and displaying the result in +hardware using a software generated linear pseudocolor lookup table. Once the +true color image is generated all of the zoom, pan, etc. functions will work +with their usual speed. Since true color display is used infrequently (and +fully buffered memory to memory operations are fairly fast anyhow) this +technique should prove quite adequate. + +.NH 2 +The Display Window + + The user views the displayed image through a window which may be resized and +moved about on the screen at any time, under interactive control of the mouse. +Resizing the window changes only the size of the subraster of the fixed-size +image frame to be displayed. Moving the window under Sunview does not change +the window into the image, merely the position of the image display window on +the screen. + +Zoom and pan is implemented in software. Zoom is implemented by pixel +replication and dezoom by pixel subsampling, operating simultaneously on both +the greyscale and graphics planes. Each operation results in a reload of the +portion of the image displayed in the image window from data stored in the +fixed size internal frame buffer. Zoom, dezoom, and roam are controlled +interactively using either the normal cursor mode keystrokes (ZXYEP,1-9M,0), +the mouse, or both. + +Once the region of interest has been adjusted on the display via the full pixel +sampling techniques, a "resample" operation may be performed to recompute the +contents of the displayed subraster using block averaging and/or bilinear +interpolation techniques. A possible variation on this is to compute several +block averaged versions of the full image at various dezoom factors, e.g., +2, 4, and 8 times dezoom, and read from these rather than the full frame when +dezoom is selected. For example, if the frame size is 2048 square, the display +would simultaneously store 2048, 1024, 512, and 256 square block-averaged +versions of the frame and dynamically select the version to be used depending +upon the dezoom factor. The percentage of additional memory required to hold +the dezoomed frames is only about 40% greater than the fully sampled frame. +Timing tests need to be performed to see if this is worthwhile. + +.NH 2 +Region of Interest + + Due to screen space limitations the image window will rarely exceed about +512 square pixels in size, hence one will normally view either a dezoomed +version of the image or a subraster of the full frame (full screen display +will of course be an option). One possible way to live with dezoom without +suffering loss of resolution is to use an icon, e.g., 64 pixels square, +to always display the region under the cursor at full resolution or better. +The display would consist of, for example, a 512 square main window displaying +the dezoomed image, and an independently movable 64 square by 8 bit icon +displaying an enlarged version of the image cursor, crosshairs, graphics +overlay, and all. + +Alternatively, the cursor could be positioned on the full window and then a +mouse button pressed to display the cursor at full resolution (or better), +at the position of the cursor, with the display returning to normal when the +mouse button is released. Yet another possibility is for the cursor to act +as a magnifier which is moved about over the dezoomed image. Most probably +all these choices will be provided as options, since they are all variations +on the same thing. + +.NH 2 +Windowing + + The lookup tables will be readable and writable under software control for +sophisticated applications such as interactive entry of a piecewise linear +transfer function. Most commonly, however, greyscale windowing will be +performed by the image display under control of the mouse. The most attractive +way to do this is probably to display a histogram of the image in the graphics +plane, overlaid by the current transfer function, which typically looks like +this: + +.ks +.nf + /------------ + / + / + ---------/ +.fi +.ke + +Moving the cursor to the left will lower the threshold (move the displayed +curve to the left), and moving the cursor up will increase the contrast +(increase the slope of the transfer function). Ideally window mode would +be entered by pressing a mouse button (or some combination of a mouse button +and a control or shift key), windowing performed with the mouse button held +down, and window mode exited when the mouse button is released. + +.NH 2 +Reading the Cursor + + The image display cursor may be any 64 pixel square object with a shape +which is suitable for centering on two dimensional objects. The default cursor +will be a pair of 64 pixel long crosshairs with a gap in the middle. When a +cursor read is in progress the cursor will blink rapidly, e.g., at 4-8 Hz, +signaling to the user that the program is waiting for a cursor read (this is +like turning on the full crosshairs on the GTERM graphics screen). The cursor +may be moved either with the mouse or with the HJKL keys in cursor mode. +A cursor read will be terminated by typing a key on the keyboard, or by +pressing a mouse button which has been aliased to a key (as in GTERM). + +All cursor input will be via the standard IRAF cursor mode cursor input +facility. The result of an image cursor read will be a line of text identical +to that returned for a graphics cursor read, i.e., containing the cursor +position in world coordinates (image pixel coordinates in this case), the +WCS number, the key typed, and so on. Semi-automatic readout of the image +cursor coordinates may be obtained via the "C" function in cursor mode, +perhaps aliased to a mouse button. + +.NH 2 +Hardcopy Output + + While there will be no snap/crtpict support initially, it will be possible +to get pseudo-greyscale output hardcopy on the laserwriter via menu selection, +as in GTERM, by taking advantage of the greyscale rendering capabilities of +Postscript and the 300 dpi resolution of the laserwriter. It also should be +possible to use :.snap or "=" to get hardcopy output in cursor mode. + +.NH +Features Not Supported + + The prototype display will provide as IRAF callable functions only image +frame buffer i/o, screen clear, viewport control (zoom/pan), and read and write +cursor position. Greyscale windowing, hardcopy output, and window resize and +move will be handled directly by the image display and Sunview, under mouse +control. Initially there will be no access to the graphics overlay, and only +monochrome display will be supported (pseudocolor may be added to the prototype +at some point). Full functionality will follow when the GIO imaging extensions +and IDI interface specification have been completed. + +.NH +Implementation + + The following subsystems need to be added or modified to implement the +prototype SUN/IRAF Sunview image display. +.ls +.ls [1] +The software image display program (new code). This will be implemented as +a Sunview tool (process), to be linked into the "basetools" executable (where +GTERM lives). The image display process (or processes if there are multiple +displays) will communicate with other processes via sockets and/or shared +memory. A special file entry will be required in /dev for each display +pseudo-device. The Sunview server process will normally be set up when the +user's .suntools file is interpreted, but will not be displayed until the +display is first loaded. Commands and data will be passed between the server +process and the client (e.g.,some IRAF process) via the conventional socket +based IPC mechanism and an application defined RPC mechanism. Shared memory +will be used to eliminate pixel i/o to the image frame buffers when the server +resides on the same machine as the client. +.le +.ls [2] +The low level code in the DISPLAY program must be modified to talk with the +display server. For the prototype, this is probably best done using the FIO +based display interface rather than GIO, since the current display program +is written to use FIO. The display task will directly read and write the +display server frame buffer using the Sys V shared memory facilities. The +final interface will do the same (or use a socket if the server is on a remote +machine), but will use the more flexible GIO interface. The DISPLAY task +must also be modified to compute the WCS and output it to the cursor mode +code via GIO, in order for cursor readback to function. +.le +.ls [3] +Cursor mode must be modified to support cursor input from imaging devices. +The principle modification seems to be the addition of a set device viewport +instruction, to be used to pass zoom and pan instructions on to the device +kernel rather than implementing them directly in the cursor mode software as +is done for the STDGRAPH devices. The open / close workstation, activate / +deactivate workstation, clear screen, set cursor, and get cursor functions +are also needed, but need not be different than the equivalent STDGRAPH +functions. +.le +.le + +Cursor mode requires implementation of some portion of a GIO device interface +for the image display. Probably this will be implemented using an inline +kernel, at least for the prototype display. Both the GIO kernel and the +DISPLAY task will communicate directly with the display server via IPC. + +.NH 2 +Display Control Interface + + Applications programs such as the DISPLAY task or the CL cursor mode code +will access the display via IPC carrying a GKI command and data stream. Most +of the GKI instructions used are already provided by the current GIO/GKI +interface. These are summarized below for reference. + + +.ks +.nf + GKI_EOF = BOI 0 L +* GKI_OPENWS = BOI 1 L M N D +* GKI_CLOSEWS = BOI 2 L N D +* GKI_REACTIVATEWS = BOI 3 L +* GKI_DEACTIVATEWS = BOI 4 L +* GKI_MFTITLE = BOI 5 L N T +* GKI_CLEARWS = BOI 6 L + GKI_CANCEL = BOI 7 L + GKI_FLUSH = BOI 8 L + GKI_POLYLINE = BOI 9 L N P + GKI_POLYMARKER = BOI 10 L N P + GKI_TEXT = BOI 11 L P N T + GKI_FILLAREA = BOI 12 L N P +* GKI_PUTCELLARRAY = BOI 13 L LL UR NC NL P +* GKI_SETCURSOR = BOI 14 L CN POS + GKI_PLSET = BOI 15 L LT LW CI + GKI_PMSET = BOI 16 L MT MW CI + GKI_TXSET = BOI 17 L UP SZ SP P HJ VJ F Q CI + GKI_FASET = BOI 18 L FS CI +* GKI_GETCURSOR = BOI 19 L CN + GKI_CURSORVALUE = BOI 19 L CN POS KEY +* GKI_GETCELLARRAY = BOI 20 L LL UR NC NL + GKI_CELLARRAY = BOI 20 L NP P + GKI_ESCAPE = BOI 25 L FN N DC + GKI_SETWCS = BOI 26 L N WCS + GKI_GETWCS = BOI 27 L N +.fi +.ke + + +Those instructions which are required in the prototype interface are marked +with an asterisk. In addition we need a number of new instructions to +perform various common image display control functions. This is the topic +of the GIO imaging extensions project, which we do not wish to attempt to +seriously address in the prototype display. The new GKI instructions outlined +in the remainder of this section are intended only to permit the implementation +of the prototype SUN image display, and will be replaced by a full and much +more carefully defined set of instructions when the full interface is designed. + +A new instruction is needed to set the device viewport, i.e., the portion of +the frame buffer to be displayed in the display window. The set viewport +instructions are used to implement zoom and pan at the cursor level. + + +.ks +.nf + GKI_SETVIEWPORT = BOI 28 L XC YC ZX ZY + GKI_GETVIEWPORT = BOI 29 L XC YC ZX ZY + GKI_VIEWPORT = BOI 29 L XC YC ZX ZY +.fi +.ke + + +The device viewport is specified by the [x,y] center of the displayed area in +frame buffer pixel coordinates (1-indexed), and the zoom or dezoom factor in +each axis. This representation is used, rather than specifying the corner +points of the intended viewport, so that the viewport may be specified +independently of the size of the actual device window used, and to avoid +questions about what happens near the edge of the frame. + +Instructions are also needed to set and inquire the index of the frame +currently being displayed, and the index of the reference frame for the i/o +and control functions; these need not be the same frame. + + +.ks +.nf + GKI_SETFRAME = BOI 30 L RF DF + GKI_GETFRAME = BOI 31 L + GKI_FRAME = BOI 31 L RF DF +.fi +.ke + + +Here, RF is the index of the reference frame, i.e., the frame to be operated +upon or referenced in all set, get, and pixel i/o operations, and DF is the +index of the frame currently being displayed or to be displayed. The frames +are numbered 1, 2, ..., N; 0 indicates that the reference frame or display +frame is not to be changed. + +The concept of the display frame is important in cursor reads. In a cursor +read or write operation, a CN (cursor number) index of 0 indicates that the +cursor of the display frame is to be referenced; the index of the frame +actually referenced will be returned in the CN field of the cursor value +structure. If a nonzero CN is given the cursor of the indicated frame is +referenced, whether or not the indicated reference frame is currently +displayed. + +Lastly, we need an inquiry function to determine the size and depth of the +image frame buffer, and the number of image planes. It is assumed that the +frame buffer size, etc., will be set up in advance by the user, either using +the mouse and the display setup panel, or via command line arguments in the +.suntools file when the display server is initially spawned. + + +.ks +.nf + GKI_GETFRAMESIZE = BOI 32 L + GKI_FRAMESIZE = BOI 32 L NP NX NY NZ +.fi +.ke + + +Here, NP is the number of image planes, NX and NY are the size in pixels of +each image plane, and NZ is the number of displayable greylevels, e.g., 256. +Note that NZ need not be a power of two as the entire colortable may not be +available. + +The image display will be a standard GIO (inline or sub) kernel down to the +level where some action occurs, after decoding the i/o instruction to be +executed. At that point a device dependent C subroutine will be called which +will pass the command on to the display server, which will always reside in a +separate process (it has to, due to the peculiar notifier based nature of the +Sunview environment). + +.NH 2 +Display Internals + + The primary functions of the display server are [1] to maintain a frame +buffer, and respond to requests to display portions of the frame buffer in the +display window at some zoom or dezoom factor, and [2] to read and execute +commands from a client process. + +Case [1] includes both refresh of the primary window, which occurs whenever a +new image is loaded, the device viewport changes, or the window is resized or +uncovered, and refresh of the region of interest (cursor) window, which occurs +whenever any of the above events occurs or whenever the cursor is moved. +In fact it appears that both operations are really the same thing, except that +the cursor window always hides the main window, has a narrower border and no +label, and is refreshed more often than the main window. The refresh operation +sets up a mapping between the frame buffer and a window and then either does +a series of pixrect operations to refresh the window (which may be partially +or fully covered), or carries out a resampling operation on a region of the +frame buffer, writing the zoomed or dezoomed data to the display window. + +The commands to be executed in case [2] are the GKI functions described in the +previous section. In the prototype display the primary commands are open / +close workstation, set viewport, set cursor position, and read cursor. +The set viewport function merely sets up a transformation and calls the +window refresh code described in the previous paragraph. diff --git a/unix/sun/Makefile b/unix/sun/Makefile new file mode 100644 index 00000000..029b957e --- /dev/null +++ b/unix/sun/Makefile @@ -0,0 +1,67 @@ +# Make the Sunview GTERM graphics terminal server, IMTOOL image display server. + +SRCS= arrow.c mouse.c notify_read.c screendump.c +OBJS= arrow.o mouse.o notify_read.o screendump.o +LIBS= -lsuntool -lsunwindow -lpixrect -lm +SUNOBJS= imtool.o gterm.o gtermio.o screendump.o arrow.o mouse.o notify_read.o + +# Set the following to "-f68881" on a Sun-3, to "" on a Sun-4 or 386i. +#FLOAT= -f68881 +FLOAT= + +# Make the custom suntools executable only on versions of SunOS prior to 4.0. +default: + sh -c 'if [ "`grep Release.4 /etc/motd`" != ""\ + -o `mach` = "i386" ]; then\ + make gterm.e; make imtool.e;\ + else\ + make suntools.e;\ + fi' + +# Make a custom SUNTOOLS with GTERM, IMTOOL, linked in. +suntools.e: gterm.c imtool.c gtermio.o $(OBJS) + chmod +x mksuntool.csh; mksuntool.csh + cc -c -O $(FLOAT) gterm.c imtool.c + mv -f gterm.o imtool.o suntool + cp gtermio.o $(OBJS) suntool + (cd ./suntool; make basetools MOREOBJS="$(SUNOBJS)" CPUFLAG="" ;\ + mv -f suntools ../suntools.e) + +# Make the GTERM test executable. +gterm.e: gterm.o gtermio.o $(OBJS) + cc $(FLOAT) gterm.o gtermio.o $(OBJS) $(LIBS) -o gterm.e + +# Make the IMTOOL test executable. +imtool.e: imtool.o $(OBJS) + cc $(FLOAT) imtool.o $(OBJS) $(LIBS) -o imtool.e + +# Install the executables in iraf$local, which is where the INSTALL script +# expects to find it. + +install: + strip *.e; mv -f *.e $$iraf/unix/bin.`mach` + +clean: + rm -f *.[aoe] + rm -rf suntool + +gterm.o: gterm.c gterm.h gterm.icon + cc -c -O -DSTANDALONE $(FLOAT) gterm.c + +imtool.o: imtool.c imtool.h imtool.icon imtool.cursor + cc -c -O -DSTANDALONE $(FLOAT) imtool.c + +gtermio.o: gtermio.c gterm.h gterm.esc + cc -c -O $(FLOAT) gtermio.c + +arrow.o: arrow.c + cc -c -O $(FLOAT) arrow.c + +mouse.o: mouse.c + cc -c -O $(FLOAT) mouse.c + +notify_read.o: notify_read.c + cc -c -O $(FLOAT) notify_read.c + +screendump.o: screendump.c + cc -c -O $(FLOAT) screendump.c diff --git a/unix/sun/README b/unix/sun/README new file mode 100644 index 00000000..4196b336 --- /dev/null +++ b/unix/sun/README @@ -0,0 +1,5 @@ +GTERM -- Graphics terminal emulator. +IMTOOL -- Image display server. + +See gterm.man, imtool.man for detailed documentation. +This software is installed by the $iraf/unix/hlib/install script. diff --git a/unix/sun/arrow.c b/unix/sun/arrow.c new file mode 100644 index 00000000..1cc55aad --- /dev/null +++ b/unix/sun/arrow.c @@ -0,0 +1,66 @@ +/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + */ + +#include <sys/types.h> +#include <sundev/kbio.h> +#include <sundev/kbd.h> + +/* + * ARROW.C -- Code to enable and disable the arrow key function-key mappings + * (R8,10,12,14). + */ + +#define NKEYS 4 +static unsigned char station[NKEYS] = { 0x45, 0x5b, 0x5d, 0x71 }; +static unsigned char entry[NKEYS] = { RF(8), RF(10), RF(12), RF(14) }; +static struct kiockey o_key[NKEYS]; + + +/* DISABLE_ARROW_KEYS -- Save the arrow key keyboard translation table + * entries, and then disable the mapping of the function keys to the ANSI + * arrow key sequences. This is necessary to read the function key as + * an event rather than an escape sequence in a Sunview event handler. + */ +disable_arrow_keys() +{ + register int fd, i; + struct kiockey key; + int status = 0; + + if ((fd = open ("/dev/kbd", 2)) == -1) + return (-1); + + for (i=0; i < NKEYS; i++) { + o_key[i].kio_station = station[i]; + if ((status = ioctl (fd, KIOCGETKEY, &o_key[i])) != 0) + break; + key = o_key[i]; + key.kio_entry = entry[i]; + if ((status = ioctl (fd, KIOCSETKEY, &key)) != 0) + break; + } + + close (fd); + return (status); +} + + +/* ENABLE_ARROW_KEYS -- Restore the saved arrow key keyboard translation table + * entries. + */ +enable_arrow_keys() +{ + register int fd, i; + struct kiockey key; + int status = 0; + + if ((fd = open ("/dev/kbd", 2)) == -1) + return (-1); + + for (i=0; i < NKEYS; i++) + if ((status = ioctl (fd, KIOCSETKEY, &o_key[i])) != 0) + break; + + close (fd); + return (status); +} diff --git a/unix/sun/fifo.c b/unix/sun/fifo.c new file mode 100644 index 00000000..65471a77 --- /dev/null +++ b/unix/sun/fifo.c @@ -0,0 +1,759 @@ +/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <signal.h> +#include <ctype.h> +#include <stdio.h> + +#define SUNOS4 + +/* + * FIFO.C -- Test fifo i/o. This is a server process much like IMTOOL, + * except that all the process does is respond to datastream requests + * to read and write an internal 512 sq frame buffer maintained as an + * array in memory (only one frame buffer is supported). A log is kept + * to the stderr of all datastream requests. + * + * Used to debug fifo i/o - NOT USED IN THE ONLINE PROGRAMS. + * + * To make: cc fifo.c -o fifo.e + * + * Usage: fifo.e >& spool run server, logging output to spool + * fifo.e -i run interactively + * + * In interactive mode, cursor value strings may be typed in on the fifo.e + * stdin in response to cursor read requests from the client. Otherwise, + * a constant cursor value "1.0 1.0 101 q" is returned. + */ + +#define I_DEVNAME "/dev/imt1o" +#define O_DEVNAME "/dev/imt1i" +#define OLD_DEVNAME "/dev/imt1" +#define IO_TIMEOUT 30 +#define SZ_FIFOBUF 4000 +#define SZ_WCSBUF 320 /* WCS text buffer size */ +#define MAX_FRAMES 1 +#define SZ_FNAME 256 + +#define MEMORY 01 /* frame buffer i/o */ +#define LUT 02 /* lut i/o */ +#define FEEDBACK 05 /* used for frame clears */ +#define IMCURSOR 020 /* logical image cursor */ +#define WCS 021 /* used to set WCS */ + +#define SZ_IMCURVAL 160 +#define PACKED 0040000 +#define COMMAND 0100000 +#define IIS_READ 0100000 +#define IMC_SAMPLE 0040000 +#define IMT_FBCONFIG 077 + +struct iism70 { + short tid; + short thingct; + short subunit; + short checksum; + short x, y, z; + short t; +}; + +#ifndef abs +#define abs(a) (((a)<0)?(-a):(a)) +#endif + +#ifndef min +#define min(a,b) ((a)<(b)?(a):(b)) +#endif +#ifndef max +#define max(a,b) ((a)<(b)?(b):(a)) +#endif + +static int interactive=0; +static int background=0; +static int datain, dataout=0; +static char framebuf[512*512]; +static int frame=1, reference_frame=1, display_frame=1; +static int fb_config_index=1, fb_nframes=1; +static int Fb_width = 512, Fb_height = 512; +static char wcsbuf[MAX_FRAMES][SZ_WCSBUF]; + + +/* FIFO -- Text fifo i/o. + */ +main (argc, argv) +int argc; +char **argv; +{ + fd_set fds; + + if (argc > 1) + if (strcmp (argv[1], "-i") == 0) + interactive++; /* type in cursor values */ + + /* Open the output fifo. We have to open it ourselves first as a + * client to get around the fifo open-no-client error. + */ + if ((datain = open (O_DEVNAME, O_RDONLY|O_NDELAY)) != -1) { + if ((dataout = open (O_DEVNAME, O_WRONLY|O_NDELAY)) != -1) + fcntl (dataout, F_SETFL, O_WRONLY); + close (datain); + } + + /* Open the input stream, a FIFO pseudodevice file used by + * applications to send us commands and data. + */ + if ((datain = open (I_DEVNAME, O_RDONLY|O_NDELAY)) == -1) { + if ((datain = open (OLD_DEVNAME, O_RDONLY|O_NDELAY)) == -1) + fprintf (stderr, "Warning: cannot open %s\n", I_DEVNAME); + } else { + /* Clear O_NDELAY for reading. */ + fcntl (datain, F_SETFL, O_RDONLY); + } + + FD_ZERO (&fds); FD_SET (datain, &fds); + while (select (FD_SETSIZE, &fds, NULL, NULL, NULL) > 0) { + ev_cmdinput(); + fflush (stdout); + fflush (stderr); + FD_ZERO (&fds); FD_SET (datain, &fds); + } + + close (datain); + exit (0); +} + + +/* EV_CMDINPUT -- Called when command or data input has arrived via the + * pseudodevice input stream from some applications process. + */ +ev_cmdinput() +{ + register unsigned char *cp; + register int sum, i; + register short *p; + int ndatabytes, nbytes, n, ntrys=0; + static int errmsg=0, bswap=0; + struct iism70 iis; + char buf[SZ_FIFOBUF]; + int fb_index; + + /* Get the IIS header. */ + if (read (datain, (char *)&iis, sizeof(iis)) < sizeof(iis)) { + fprintf (stderr, "imtool: command input read error\n"); + fflush (stderr); + return (0); + } else if (bswap) + bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); + + /* Verify the checksum. If it fails swap the bytes and try again. + */ + for (;;) { + for (i=0, sum=0, p=(short *)&iis; i < 8; i++) + sum += *p++; + if ((sum & 0177777) == 0177777) + break; + + if (ntrys++) { + if (!errmsg++) { + fprintf (stderr, "imtool: bad data header checksum\n"); + fflush (stderr); + if (bswap) + bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); + fprintf (stderr, "noswap:"); + for (i=0, p=(short *)&iis; i < 8; i++) + fprintf (stderr, " %6o", p[i]); + fprintf (stderr, "\n"); + + bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); + fprintf (stderr, " swap:"); + for (i=0, p=(short *)&iis; i < 8; i++) + fprintf (stderr, " %6o", p[i]); + fprintf (stderr, "\n"); + fflush (stderr); + } + break; + + } else { + bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); + bswap = !bswap; + } + } + + ndatabytes = -iis.thingct; + if (!(iis.tid & PACKED)) + ndatabytes *= 2; + + /* Log command. */ + fprintf (stderr, + "subunit=%06o tid=%06o nbytes=%7d x=%06o y=%06o z=%06o\n", + iis.subunit & 077, + iis.tid, + ndatabytes, + iis.x & 0177777, + iis.y & 0177777, + iis.z & 0177777); + fflush (stderr); + + switch (iis.subunit & 077) { + case FEEDBACK: + /* The feedback unit is used only to clear a frame. + */ + set_reference_frame (decode_frameno (iis.z & 07777)); + /* erase (rf_p); */ + fprintf (stderr, "erase frame %d\n", reference_frame); + break; + + case LUT: + /* Data mode writes to the frame lookup tables are not implemented. + * A command mode write to the LUT subunit is used to connect + * image memories up to the RGB channels, i.e., to select the frame + * to be displayed. We ignore any attempt to assign multiple + * frames to multiple color channels, and just do a simple frame + * select. + */ + if (iis.subunit & COMMAND) { + int frame, z, n; + short x[14]; + + if (read (datain, (char *)x, ndatabytes) == ndatabytes) { + if (bswap) + bswap2 ((char *)x, (char *)x, ndatabytes); + + z = x[0]; + if (!z) z = 1; + for (n=0; !(z & 1); z >>= 1) + n++; + + frame = max (1, n + 1); + if (frame > fb_nframes) { + if (frame < MAX_FRAMES) { + /* set_fbconfig (fb_config_index, frame); */ + fprintf (stderr, "set_fbconfig (%d, %d)\n", + fb_config_index, frame); + } else { + fprintf (stderr, "imtool warning: "); + fprintf (stderr, + "attempt to display nonexistent frame %d\n", frame); + frame = fb_nframes - 1; + } + } + + /* set_frame (frame); */ + fprintf (stderr, "set_frame (%d)\n", frame); + return (0); + } + } + + case MEMORY: + /* Load data into the frame buffer. Data is assumed to be byte + * packed. + */ + if (iis.tid & IIS_READ) { + /* Read from the display. + */ + unsigned char *fb, *ip; + int nbytes, nleft, n, x, y; + long starttime; + + /* Get the frame to be read from. */ + set_reference_frame (decode_frameno (iis.z & 07777)); + + fb = (unsigned char *)framebuf; + nbytes = ndatabytes; + x = iis.x & 01777; + y = iis.y & 01777; + + ip = max (fb, min (fb + Fb_width * Fb_height - nbytes, + fb + y * Fb_width + x)); + if (ip != fb + y * Fb_width + x) { + fprintf (stderr, + "imtool: attempted read out of bounds on framebuf\n"); + fprintf (stderr, + "read %d bytes at [%d,%d]\n", nbytes, x, y); + } + + /* Log i/o command. */ + fprintf (stderr, "read %d bytes at x=%d, y=%d\n", + nbytes, x, y); + + /* Return the data from the frame buffer. */ + starttime = time(0); + for (nleft = nbytes; nleft > 0; nleft -= n) { + n = (nleft < SZ_FIFOBUF) ? nleft : SZ_FIFOBUF; + if ((n = write (dataout, ip, n)) <= 0) { + if (n < 0 || (time(0) - starttime > IO_TIMEOUT)) { + fprintf (stderr, "IMTOOL: timeout on write\n"); + break; + } + } else + ip += n; + } + + return (0); + + } else { + /* Write to the display. + */ + unsigned char *fb, *op; + int nbytes, nleft, n, x, y; + long starttime; + + /* Get the frame to be written into (encoded with a bit for + * each frame, 01 is frame 1, 02 is frame 2, 04 is frame 3, + * and so on). + */ + set_reference_frame (decode_frameno (iis.z & 07777)); + + /* Get a pointer into the frame buffer where the data will + * be put. + */ + fb = (unsigned char *)framebuf; + nbytes = ndatabytes; + x = iis.x & 07777; + y = iis.y & 07777; + + op = max (fb, min (fb + Fb_width * Fb_height - nbytes, + fb + y * Fb_width + x)); + if (op != fb + y * Fb_width + x) { + fprintf (stderr, + "imtool: attempted write out of bounds on framebuf\n"); + fprintf (stderr, + "write %d bytes to [%d,%d]\n", nbytes, x, y); + } + + /* Log i/o command. */ + fprintf (stderr, "write %d bytes at x=%d, y=%d\n", + nbytes, x, y); + + /* Read the data into the frame buffer. + */ + starttime = time(0); + for (nleft = nbytes; nleft > 0; nleft -= n) { + n = (nleft < SZ_FIFOBUF) ? nleft : SZ_FIFOBUF; + if ((n = read (datain, op, n)) <= 0) { + if (n < 0 || (time(0) - starttime > IO_TIMEOUT)) + break; + } else { + /* Set any zeroed pixels to the background color, + * if a special background color is specified. + */ + if (background) + for (cp=op, i=n; --i >= 0; cp++) + if (!*cp) + *cp = background; + op += n; + } + } + + /* Refresh the display, if the current display frame is the + * same as the reference frame. + if (rf_p == df_p) { + BRect fb_r, pw_r; + + fb_r.r_left = x * zoom; + fb_r.r_top = y * zoom; + fb_r.r_width = min (nbytes * zoom, fb_width); + fb_r.r_height = ((nbytes*zoom*zoom + fb_width-1)/fb_width); + + Bpw_get_region_rect (gio_pw, &pw_rect); + Bpw_lock (gio_pw, &pw_rect); + + pw_rect.r_left = df_p->fb_xoff; + pw_rect.r_top = df_p->fb_yoff; + + if (maprect (&fb_rect, &fb_r, &pw_rect, &pw_r)) + if (maprect (&pw_rect, &pw_r, &fb_rect, &fb_r)) { + ds_write (gio_pw, + pw_r.r_left, pw_r.r_top, + pw_r.r_width, pw_r.r_height, + PIX_SRC | PIX_COLOR(NGREY-1), + df_p->fb_pr, fb_r.r_left, fb_r.r_top); + + if (pw_r.r_top + pw_r.r_height >= pw_rect.r_height + - cb_height) + put_colorbar(); + } + + Bpw_unlock (gio_pw); + } + */ + + return (0); + } + break; + + case WCS: + /* Read or write the WCS for a frame. The frame number to + * which the WCS applies is passed in Z and the frame buffer + * configuration in T. The client changes the frame buffer + * configuration in a WCS set. The WCS text follows the header + * as byte packed ASCII data. + */ + if (iis.tid & IIS_READ) { + /* Return the WCS for the referenced frame. + */ + register char *op; + register int n; + char emsg[SZ_WCSBUF]; + char *text; + int frame; + + for (op=emsg, n=SZ_WCSBUF; --n >=0; ) + *op++ = 0; + + frame = decode_frameno (iis.z & 07777); + if (frame > fb_nframes) + strcpy (text=emsg, "[NOSUCHFRAME]\n"); + else { + set_reference_frame (frame); + text = wcsbuf[reference_frame-1]; + } + + fprintf (stderr, "query wcs:\n"); + write (2, text, SZ_WCSBUF); + + write (dataout, text, SZ_WCSBUF); + + } else { + /* Set the WCS for the referenced frame. + */ + char buf[1024]; + int fb_config, frame; + + frame = decode_frameno (iis.z & 07777); + if (frame > fb_nframes) + if (frame < MAX_FRAMES) { + /* set_fbconfig (fb_config_index, frame); */ + fprintf (stderr, "set_fbconfig (%d, %d)\n", + fb_config_index, frame); + } + + set_reference_frame (frame); + if ((fb_config = iis.t & 077) != fb_config_index) { + /* set_fbconfig (fb_config_index, frame); */ + fprintf (stderr, "set_fbconfig (%d, %d)\n", + fb_config_index, frame); + } + + /* Read in and set up the WCS. */ + if (read (datain, buf, ndatabytes) == ndatabytes) + strncpy (wcsbuf[reference_frame-1], buf, SZ_WCSBUF); + + fprintf (stderr, "set wcs:\n"); + write (2, buf, SZ_WCSBUF); + + /* + strcpy (rf_p->fb_ctran.format, W_DEFFORMAT); + rf_p->fb_ctran.imtitle[0] = '\0'; + rf_p->fb_ctran.valid = 0; + rf_p->fb_imageno++; + rf_p->fb_objno = 1; + + wcs_update (rf_p); + if (rf_p == df_p) + window_set (gio_frame, FRAME_LABEL, framelabel(), 0); + */ + } + + return (0); + break; + + case IMCURSOR: + /* Read or write the logical image cursor. This is an extension + * added to provide a high level cursor read facility; this is + * not the same as a low level access to the IIS cursor subunit. + * Cursor reads may be either nonblocking (immediate) or blocking, + * using the keyboard or mouse to terminate the read, and + * coordinates may be returned in either image (world) or frame + * buffer pixel coordinates. + */ + if (iis.tid & IIS_READ) { + /* Read the logical image cursor. In the case of a blocking + * read all we do is initiate a cursor read; completion occurs + * when the user hits a key or button. + */ + fprintf (stderr, "read cursor position\n"); + if (iis.tid & IMC_SAMPLE) { + /* Sample the cursor position. */ + /* + register struct ctran *ct; + int wcs = iis.z; + int sx, sy; + float wx, wy; + + wx = sx = last_x + pw_rect.r_left; + wy = sy = last_y + pw_rect.r_top; + + if (wcs) { + ct = wcs_update (df_p); + if (ct->valid) { + if (abs(ct->a) > .001) + wx = ct->a * sx + ct->c * sy + ct->tx; + if (abs(ct->d) > .001) + wy = ct->b * sx + ct->d * sy + ct->ty; + } + } + */ + + int wcs = iis.z, key = 'q'; + float wx=1.0, wy=1.0; + + /* Return the cursor value on the output datastream encoded + * in a fixed size ascii buffer. + */ + gio_retcursorval (wx, wy, display_frame*100+wcs, key, ""); + + } else { + /* Initiate a user triggered cursor read. */ + /* gio_readcursor (iis.z); */ + int wcs = iis.z, key = 'q'; + float wx=1.0, wy=1.0; + gio_retcursorval (wx, wy, display_frame*100+wcs, key, ""); + } + + } else { + /* Write (set) the logical image cursor position. */ + /* + fprintf (stderr, "write cursor position\n"); + register struct ctran *ct; + int sx = iis.x, sy = iis.y; + float wx = sx, wy = sy; + int wcs = iis.z; + + if (wcs) { + ct = wcs_update (df_p); + if (ct->valid) { + if (abs(ct->a) > .001) + sx = (wx - ct->tx) / ct->a; + if (abs(ct->d) > .001) + sy = (wy - ct->ty) / ct->d; + } + } + + gio_setcursorpos (sx - pw_rect.r_left, sy - pw_rect.r_top); + */ + } + + return (0); + break; + + default: + /* Ignore unsupported command input. + */ + break; + } + + /* Discard any data following the header. */ + if (!(iis.tid & IIS_READ)) + for (nbytes = ndatabytes; nbytes > 0; nbytes -= n) { + n = (nbytes < SZ_FIFOBUF) ? nbytes : SZ_FIFOBUF; + if ((n = read (datain, buf, n)) <= 0) + break; + } + + fflush (stderr); + return (0); +} + + +/* SET_REFERENCE_FRAME -- Set reference frame. If the frame referenced is + * greater than the current number of frames, attempt to increase the number + * of frames. + */ +static +set_reference_frame (n) +register int n; +{ + reference_frame = max (1, n); + if (reference_frame > fb_nframes) { + if (reference_frame < MAX_FRAMES) { + /* set_fbconfig (fb_config_index, reference_frame); */ + fprintf (stderr, "set_fbconfig %d %d\n", + fb_config_index, reference_frame); + } else { + fprintf (stderr, "imtool warning: "); + fprintf (stderr, + "attempt to reference nonexistent frame %d\n", + reference_frame); + reference_frame = fb_nframes; + } + } + + /* rf_p = frames + (reference_frame - 1); */ +} + + +/* DECODE_FRAMENO -- Decode encoded IIS register frame number. + */ +static +decode_frameno (z) +register int z; +{ + register int n; + + /* Get the frame number, encoded with a bit for each frame, 01 is + * frame 1, 02 is frame 2, 04 is frame 3, and so on. + */ + if (!z) z = 1; + for (n=0; !(z & 1); z >>= 1) + n++; + + return (max (1, n + 1)); +} + + +/* BSWAP2 - Move bytes from array "a" to array "b", swapping successive + * pairs of bytes. The two arrays may be the same but may not be offset + * and overlapping. + */ +static +bswap2 (a, b, nbytes) +char *a, *b; /* input array */ +int nbytes; /* number of bytes to swap */ +{ + register char *ip=a, *op=b, *otop; + register unsigned temp; + + /* Swap successive pairs of bytes. + */ + for (otop = op + (nbytes & ~1); op < otop; ) { + temp = *ip++; + *op++ = *ip++; + *op++ = temp; + } + + /* If there is an odd byte left, move it to the output array. + */ + if (nbytes & 1) + *op = *ip; +} + + +/* GIO_RETCURSORVAL -- Return the cursor value on the output datastream to + * the client which requested the cursor read. + */ +static +gio_retcursorval (wx, wy, wcs, key, strval) +float wx, wy; /* cursor coordinates */ +int wcs; /* encoded WCS value */ +int key; /* keystroke used as trigger */ +char *strval; /* optional string value */ +{ + register char *op; + register int n; + char curval[SZ_IMCURVAL]; + char keystr[20]; + + for (op=curval, n=SZ_IMCURVAL; --n >=0; ) + *op++ = 0; + + /* If running FIFO in interactive mode, allow the user to type + * in the cursor value on the standard input. + */ + if (interactive) { + fprintf (stderr, "enter cursor value string: "); + fflush (stderr); + if (fgets (curval, SZ_IMCURVAL, stdin) != NULL) + goto ret; + } + + /* Encode the cursor value. */ + if (key == EOF) + sprintf (curval, "EOF\n"); + else { + if (isprint (key) && !isspace(key)) { + keystr[0] = key; + keystr[1] = '\0'; + } else + sprintf (keystr, "\\%03o", key); + + sprintf (curval, "%10.3f %10.3f %d %s %s\n", + wx, wy, wcs, keystr, strval); + } +ret: + fprintf (stderr, "%s", curval); + + /* Send it to the client program. */ + write (dataout, curval, sizeof(curval)); +} + + +#define mask(s) (1<<((s)-1)) +#define setvec(vec, a) \ + vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0 + +static int ringring; + + +/* WMSEC -- Suspend task execution (sleep) for the specified number + * of milliseconds. + */ +wmsec (msec) +int msec; +{ + struct itimerval itv, oitv; + register struct itimerval *itp = &itv; + struct sigvec vec, ovec; +#ifdef SUNOS4 + void napmsx(); +#else + int napmsx(); +#endif + int omask; + + if (msec == 0) + return; + + timerclear (&itp->it_interval); + timerclear (&itp->it_value); + if (setitimer (ITIMER_REAL, itp, &oitv) < 0) + return; + + setvec (ovec, SIG_DFL); + omask = sigblock(0); + + itp->it_value.tv_usec = (msec * 1000) % 1000000; + itp->it_value.tv_sec = (msec * 1000) / 1000000; + + if (timerisset (&oitv.it_value)) { + if (timercmp(&oitv.it_value, &itp->it_value, >)) + oitv.it_value.tv_sec -= itp->it_value.tv_sec; + else { + itp->it_value = oitv.it_value; + /* This is a hack, but we must have time to + * return from the setitimer after the alarm + * or else it'll be restarted. And, anyway, + * sleep never did anything more than this before. + */ + oitv.it_value.tv_sec = 1; + oitv.it_value.tv_usec = 0; + } + } + + setvec (vec, napmsx); + (void) sigvec (SIGALRM, &vec, &ovec); + ringring = 0; + (void) setitimer (ITIMER_REAL, itp, (struct itimerval *)0); + + while (!ringring) + sigpause (omask &~ mask(SIGALRM)); + + (void) sigvec (SIGALRM, &ovec, (struct sigvec *)0); + (void) setitimer (ITIMER_REAL, &oitv, (struct itimerval *)0); +} + + +#ifdef SUNOS4 +static void +#else +static int +#endif +napmsx() +{ + ringring = 1; +} diff --git a/unix/sun/gterm.c b/unix/sun/gterm.c new file mode 100644 index 00000000..57c4eb43 --- /dev/null +++ b/unix/sun/gterm.c @@ -0,0 +1,1984 @@ +/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + */ + +#include <suntool/sunview.h> +#include <suntool/canvas.h> +#include <suntool/panel.h> +#include <suntool/tty.h> +#include <suntool/walkmenu.h> +#include <suntool/tool_struct.h> +#include <sunwindow/win_cursor.h> +#include <sgtty.h> +#include <stdio.h> +#include <ctype.h> +#include "gterm.h" + +/* + * GTERM -- Graphics terminal emulator. This code implements a virtual + * graphics terminal consisting of independent text and graphics frames. + * The text (tty) frame is a standard Sun TTY frame. The graphics (gio) + * frame is a tektronix 4012 with extensions, some of which are patterned + * after the Retrographics vt100, Pericom, etc., and others of which are or + * will be added to provide GKS like capabilities via a conventional data + * driven graphics terminal interface. The tty and gio frames are independent + * frames under Sunview, hence they may be resized, moved, opened or closed, + * hidden or exposed, etc., independently of each other. Both frames are + * active at all times, but since a single terminal i/o stream is used to + * drive both frames an applications program can communicate with only one + * frame at a time, just like a conventional graphics terminal. + * + * D.Tody, January 1987 (NOAO/IRAF project) + */ + +#define MAX_ARGS 50 /* max tty or gio cmdline args */ +#define DEF_TEKXRES 1024 /* default logical X resolution */ +#define DEF_TEKYRES 780 /* default logical Y resolution */ + +#define NO_ACTION 0 /* no action on open/close ws */ +#define SHOW_FRAME 1 /* show or unshow gio frame */ +#define UNSHOW_FRAME 1 /* show or unshow gio frame */ +#define EXPOSE_FRAME 2 /* expose or hide gio frame */ +#define HIDE_FRAME 2 /* expose or hide gio frame */ +#define CROSSHAIR_OFF 1 /* crosshair cursor off */ +#define CROSSHAIR_ON 2 /* turn crosshair cursor on */ +#define SZ_LOGBUF 1024 /* size of logfile buffer */ +#define SZ_GINMODETERM 10 /* ginmode string length */ +#define SZ_FNAME 128 + +#define R_TYPE 0 /* 0=postscript, 1=rasterfile */ +#define R_DISPOSE "lpr -s %s" /* dispose command */ +#define R_FILENAME "" /* output filename */ + +/* External variables. */ +extern int gio_graphicsenabled; /* set when in graphics mdoe */ +int cursor_show = -1; /* cursor state: on or off */ +Window gt_baseframe, gt_ttysw, gio_frame, gio_canvas; +FILE *gt_logfp = NULL; /* logfile file pointer */ + +/* Screendump stuff. */ +int r_type = R_TYPE; +char r_dispose[SZ_FNAME+1] = R_DISPOSE; +char r_filename[SZ_FNAME+1] = R_FILENAME; + +/* Both external and a user option. */ +int clip_graphics = 1; /* disable rasterop clipping */ + +/* User options. */ +static int graphics_enable; /* enable graphics plane */ +static int openws_action; /* default action on openws */ +static int closews_action; /* default action on closews */ +static int closews_pause; /* pause/confirm closews? */ +static int canvas_retained; /* retain the canvas pixwin? */ +static int reverse_video; /* normal or reverse video */ +static int color; /* color or monochrome graphics */ +static int win_xsize; /* standard size graphics frame */ +static int win_ysize; +static int win_xoff; /* standard offset from tty fr. */ +static int win_yoff; +static int ignore; /* ignore suspend/stop codes? */ +static char gin_modeterm[SZ_GINMODETERM+1]; +static char logfile[SZ_FNAME+1] = "gterm.out"; + +/* The following are used to save and later restore the option parameters. */ +static int s_clip_graphics = 1; +static int s_graphics_enable = GRAPHICS_ON; +static int s_openws_action = SHOW_FRAME; +static int s_closews_action= HIDE_FRAME; +static int s_closews_pause = 0; +static int s_canvas_retained = 1; +static int s_reverse_video = 0; +static int s_color = 1; +static int s_win_xsize = 800; +static int s_win_ysize = 630; +static int s_win_xoff = 100; +static int s_win_yoff = 19; +static int s_ignore = 0; +static char s_gin_modeterm[SZ_GINMODETERM] = "015"; + +/* Internal state variables. */ +static int cursor_type = -1; /* crosshair or small cursor */ +static int cursor_read_pending=0; /* waiting for cursor event */ +static int key_left = 0; /* key aliased to left msbutton */ +static int key_middle = 0; /* key aliased to mid msbutton */ +static int key_right = 0; /* key aliased to mid msbutton */ +static int last_key = 0; /* last cursor read key */ +static int last_x= -1,last_y= -1; /* last cursor read position */ +static int pause_mode = 0; /* waiting for closews event */ +static int cursor_used = 0; /* set if cursor is used */ +static int gio_frame_has_moved=0; /* set when user moves giowin */ +static int setup_xoff = 140; /* offset to setup panel */ +static int setup_yoff = 60; +static int tty_lastx, tty_lasty; /* cursor position in gt_ttysw */ +static int height_is_set = 0; /* tty w. height set on cmdline */ +static int tty_nlines = 0; /* number of lines in tty w. */ +static int shell = 0; /* we are running a shell */ +static char t_suspc, t_dsuspc, t_set=0; + +/* The following is a kludge and should be determined at runtime */ +static int pty_fd = 3; /* fd of tty pseudoterminal */ + +/* Graphics fonts. */ +static char fb_courier[] = "/usr/lib/fonts/fixedwidthfonts/cour.b.%d"; +static char fr_courier[] = "/usr/lib/fonts/fixedwidthfonts/cour.r.%d"; +static char fr_screen[] = "/usr/lib/fonts/fixedwidthfonts/screen.r.%d"; +static char fb_screen[] = "/usr/lib/fonts/fixedwidthfonts/screen.b.%d"; + +#define FULLSCREEN 5 +struct fonttab alpha_fonts[] = { + 10, 7, 12, 560, 420, NULL, fb_courier, "10:[560x420]", + 12, 8, 14, 640, 490, NULL, fb_courier, "12:[640x490]", + 14, 9, 16, 720, 560, NULL, fb_courier, "14:[720x560]", + 16, 10, 18, 800, 630, NULL, fb_courier, "16:[800x630]", + 18, 11, 19, 880, 665, NULL, fb_courier, "18:[880x665]", + 24, 14, 25, 1142, 890, NULL, fb_courier, "24:fullscreen", + /* Note nentries must match panel choice list */ + 0, 0, 0, 0, 0, NULL, NULL, NULL +}; + +struct fonttab text_fonts[] = { + 11, 7, 11, 560, 0, NULL, fr_screen, "screen.r.11", + 12, 8, 14, 640, 0, NULL, fb_screen, "screen.b.12", + 14, 9, 16, 720, 0, NULL, fb_screen, "screen.b.14", + 16, 10, 18, 800, 0, NULL, fb_courier, "courier.b.16", + 18, 11, 19, 880, 0, NULL, fb_courier, "courier.b.18", + 24, 14, 25, 1142, 0, NULL, fb_courier, "courier.b.24", + /* Note nentries must match panel choice list */ + 0, 0, 0, 0, 0, NULL, NULL, NULL +}; + +#define DEF_TEXTFONT 4 +static int alpha_font_index; +static int text_font_index = DEF_TEXTFONT; +static struct fonttab *alpha_font = NULL; +static struct fonttab *text_font = NULL; + +#define SWAP(a,b) {int temp; temp=a;a=b;b=temp;} +#define HEIGHTADJUST \ + (tool_headerheight((int)window_get(gt_baseframe, FRAME_SHOW_LABEL)) + \ + TOOL_BORDERWIDTH) + +static short iconimage[] = { +#include "gterm.icon" +}; +DEFINE_ICON_FROM_IMAGE (icon, iconimage); + +static int main_argc, tty_argc, gio_argc; +static char **main_argv, *tty_argv[MAX_ARGS], *gio_argv[MAX_ARGS]; +static unsigned char red[2] = { 0, 255 }; +static unsigned char green[2] = { 0, 255 }; +static unsigned char blue[2] = { 128, 0 }; + +static Menu_item logitem; +static struct rect screen; +static struct pixwin *pw; +static Panel setup_panel, pause_panel; +static Window setup_frame, pause_frame; +static Notify_value ev_gt_ttysw(); +static Notify_value ev_ttyframe(); +static Notify_value ev_gioframe(); +static Notify_value ev_gioinput(); +static Notify_func sig_tstp(); +static tty_adjustheight(); +extern char *getenv(); + + +/* GTERM_MAIN -- Create the graphics terminal window tree, i.e., the panel + * subwindow and tty subwindow, the gio subframe canvas in which graphics + * will be drawn, and the setup popup which is used to set the terminal + * options. Only the panel and tty (text) window is shown initially; this + * is functionally equivalent to a shelltool window with all the same command + * line arguments. Additional command line arguments are recognized for + * initialization of the graphics frame. + */ +#ifdef STANDALONE +main (argc, argv) +#else +gterm_main (argc, argv) +#endif +int argc; +char **argv; +{ + char *s; + + /* Set user settable options to their initial compiled in values. */ + restore_params(); + + main_argc = argc; + main_argv = argv; + parse_args (argc, argv, &tty_argc, tty_argv, &gio_argc, gio_argv); + + /* Screendump stuff. */ + if (s = getenv ("R_DISPOSE")) + strcpy (r_dispose, s); + if (s = getenv ("R_FILENAME")) + strcpy (r_filename, s); + if (s = getenv ("R_RASTERFILE")) { + strcpy (r_filename, s); + r_type = 1; + } + + /* Create the base frame for all the GTERM windows. */ + gt_baseframe = window_create (NULL, FRAME, + FRAME_ICON, &icon, + FRAME_LABEL, "gterm - NOAO/IRAF Sunview Graphics Terminal V1.2", + FRAME_ARGC_PTR_ARGV, &tty_argc, tty_argv, + FRAME_NO_CONFIRM, FALSE, + 0); + if (gt_baseframe == NULL) + _exit (1); + screen = *(struct rect *) window_get (gt_baseframe, WIN_SCREEN_RECT); + + create_tty_subwindow (tty_argc, tty_argv); + create_gio_popup (gio_argc, gio_argv); + create_frame_menu (gt_baseframe); + + /* Save initial options settings for later reset (in setup panel). */ + save_params(); + + notify_interpose_event_func (gt_baseframe, ev_ttyframe, NOTIFY_SAFE); + notify_interpose_event_func (gt_ttysw, ev_gt_ttysw, NOTIFY_SAFE); + notify_interpose_event_func (gio_frame, ev_gioframe, NOTIFY_SAFE); + notify_interpose_event_func (gio_canvas, ev_gioinput, NOTIFY_SAFE); + + notify_set_signal_func (gt_baseframe, sig_tstp, SIGTSTP, NOTIFY_SYNC); + +#ifdef TTY_TTY_FD + /* SunOS 3.4 provides just what we needed to fix the pty-fd kludge! */ + pty_fd = (int) window_get (ttysw, TTY_TTY_FD); +#endif + gio_setup (pty_fd, pw); + gio_hardreset (DEF_TEKXRES, DEF_TEKYRES, alpha_font, text_font); + + window_main_loop (gt_baseframe); + exit (0); +} + + +/* PARSE_ARGS -- Parse the argument list into the arguments for the tty + * frame and the arguments for the gio frame. This is very easy; the gio + * args, if any, are whatever follows the arg "-G" in the argument list. + * All args preceding the -G are considered to be tty args. + */ +static +parse_args (argc, argv, tty_argc, tty_argv, gio_argc, gio_argv) +int argc; +char *argv[]; +int *tty_argc, *gio_argc; +char *tty_argv[], *gio_argv[]; +{ + register char *argp, *last; + register int arg = 1; + + /* Copy the tty arguments. */ + tty_argv[0] = argv[0]; + for (*tty_argc=1; arg <= argc && (argp = argv[arg]) != NULL; arg++) + if (strcmp (argv[arg], "-G") != 0) { + tty_argv[(*tty_argc)++] = argp; + if ((strcmp(argp, "-Ws") == 0) || (strcmp(argp, "-size") == 0)) + height_is_set = 1; + else if ((strcmp(argp, "-Wh") == 0) || + (strcmp(argp, "-height") == 0)) { + height_is_set = 0; + tty_nlines = atoi (argv[arg+1]); + } + } else { + arg++; + break; + } + + gio_argv[0] = argv[0]; + last = ""; + + /* Copy the gio arguments. */ + for (*gio_argc=1; arg <= argc && (argp = argv[arg]) != NULL; arg++) { + + /* If an argument string is encountered which is not an argument + * to a GIO window switch, assume that it is the first word of the + * command to be executed in the text window, and move the + * remaining arguments to the tty_argv list. + */ + if (strncmp(last,"-Gopen",3) && strncmp(last,"-Gclose",3) && + isalpha(argp[0])) { + + for (; arg <= argc && (argp = argv[arg]) != NULL; arg++) + tty_argv[(*tty_argc)++] = argp; + break; + } + + gio_argv[(*gio_argc)++] = argp; + last = argp; + } + + tty_argv[(*tty_argc)] = NULL; + gio_argv[(*gio_argc)] = NULL; +} + + +/* CREATE_TTY_SUBWINDOW -- Create a standard TTY subwindow of the base frame. + * This code emulates the shelltool arguments. + */ +static +create_tty_subwindow (argc, argv) +int argc; +char *argv[]; +{ + static char *sh_argv[2]; + register char *argp; + register int arg; + char **tty_argv = argv; + char *tool_name = argv[0]; + char *init_cmd = NULL; + char *bold_name = NULL; + int become_console = 0; + + /* Get gt_ttysw related args. The standard frame arguments will + * already have been removed from the list when the base frame was + * created, leaving only the tty specific arguments and possibly the + * command to be run. + */ + sh_argv[0] = NULL; + sh_argv[1] = NULL; + + for (arg=1; arg < argc && (argp = argv[arg]); arg++) { + if (*argp != '-') + break; + else if (!strncmp (argp, "-ignore", 3)) { + ignore++; + continue; + } + + switch (*(argp+1)) { + case 'C': + become_console = 1; + break; + case '?': + tool_usage (tool_name); + print_usage (tool_name); + window_destroy (gt_baseframe); + exit (1); + case 'B': + if (argc > 1) + bold_name = argv[++arg]; + break; + case 'I': + if (argc > 1) + init_cmd = argv[++arg]; + break; + case 'T': + gio_enable (0); + break; + } + } + + /* Get path to command interpreter to be run. */ + if (argp == NULL || arg >= argc) { + shell++; + tty_argv = sh_argv; + if ((tty_argv[0] = getenv("SHELL")) == NULL) { + tty_argv[0] = "/bin/sh"; + if (ignore) + shell = 0; + } + } else { + tty_argv = &argv[arg]; + if (!strcmp(tty_argv,"csh") || !strcmp(tty_argv,"/bin/csh")) + shell++; + else if (!ignore) + shell++; + } + + gt_ttysw = window_create (gt_baseframe, TTY, + TTY_ARGV, tty_argv, + TTY_QUIT_ON_CHILD_DEATH, TRUE, + TTY_CONSOLE, become_console, + 0); + + window_set (gt_ttysw, + WIN_CONSUME_KBD_EVENTS, KEY_TOP(7), KEY_TOP(8), KEY_TOP(9), 0, + 0); + + if (bold_name) + window_set (gt_ttysw, TTY_BOLDSTYLE_NAME, bold_name, 0); + + /* Pass user supplied command, if given, to the shell. */ + if (init_cmd) { + int len = strlen (init_cmd); + + if (init_cmd[len-1] != '\n') { + init_cmd[len] = '\n'; + len++; + } + ttysw_input (gt_ttysw, init_cmd, len); + } + + window_fit_height (gt_ttysw); + window_fit_height (gt_baseframe); + + /* Only correct the height if the user did not give a pixel value + * for the height. + */ + if (!height_is_set) + tty_adjustheight (tty_nlines); +} + + +/* CREATE_GIO_POPUP -- Create a canvas popup to be used for graphics i/o. + * We use a separate subframe for this so that it may be moved and sized + * independently of the tty window; tty windows like to high and narrow + * (lots of lines) whereas graphs tend to be short and wide (good resolution + * in X). We also like a large graph window to get good resolution, but + * a separate window is desired so that the screen space can be freed up + * when we are not actually doing graphics, and so that the last graph can + * easily be recalled at any time. The standard graphics window should have + * a landscape aspect ratio (y/x=.77), like most terminals and laser printers. + */ +static +create_gio_popup (argc, argv) +int argc; +char **argv; +{ + static unsigned char mono[2]; + register char *argp; + register int arg; + char *frame_argv[64]; + int frame_argc; + char pathname[256]; + char mapname[64]; + int name; + + frame_argv[0] = argv[0]; + frame_argc = 1; + + /* Override the builtin defaults with the values given by the user + * on the command line, if any. + */ + for (arg=1; arg <= argc && (argp = argv[arg]) != NULL; arg++) { + /* Standard Sunview frame args. */ + if (!strcmp (argp, "-Wb") || !strncmp (argp, "-back", 5)) { + red[0] = atoi (argv[++arg]); + green[0] = atoi (argv[++arg]); + blue[0] = atoi (argv[++arg]); + } else if (!strcmp (argp, "-Wf") || !strncmp (argp, "-fore", 5)) { + red[1] = atoi (argv[++arg]); + green[1] = atoi (argv[++arg]); + blue[1] = atoi (argv[++arg]); + } else if (!strcmp (argp, "-Wp") || !strncmp (argp, "-pos", 4)) { + win_xoff = atoi (argv[++arg]) - + (int) window_get (gt_baseframe, WIN_X); + win_yoff = atoi (argv[++arg]) - + (int) window_get (gt_baseframe, WIN_Y); + } else if (!strcmp (argp, "-Ws") || !strncmp (argp, "-size", 5)) { + win_xsize = atoi (argv[++arg]) - (TOOL_BORDERWIDTH * 2); + win_ysize = atoi (argv[++arg]) - (TOOL_BORDERWIDTH * 2); + + /* Graphics options. */ + } else if (!strncmp (argp, "-Gopen", 3)) { + argp = argv[++arg]; + if (!strncmp (argp, "noaction", 1)) + openws_action = NO_ACTION; + else if (!strncmp (argp, "show", 1)) + openws_action = SHOW_FRAME; + else if (!strncmp (argp, "expose", 1)) + openws_action = EXPOSE_FRAME; + else { + fprintf (stderr, + "Warning: unknown argument `%s' to -Gopen\n", argp); + } + } else if (!strncmp (argp, "-Gclose", 3)) { + argp = argv[++arg]; + if (!strncmp (argp, "noaction", 1)) + closews_action = NO_ACTION; + else if (!strncmp (argp, "blank", 1)) + closews_action = UNSHOW_FRAME; + else if (!strncmp (argp, "hide", 1)) + closews_action = HIDE_FRAME; + else { + fprintf (stderr, + "Warning: unknown argument `%s' to -Gclose\n", argp); + } + } else if (!strncmp (argp, "-pause", 2)) { + closews_pause = 1; + } else if (!strncmp (argp, "-nopause", 4)) { + closews_pause = 0; + } else if (!strncmp (argp, "-retain", 4)) { + canvas_retained = 1; + } else if (!strncmp (argp, "-noretain", 6)) { + canvas_retained = 0; + } else if (!strncmp (argp, "-clip", 3)) { + clip_graphics = 1; + } else if (!strncmp (argp, "-noclip", 4)) { + clip_graphics = 0; + } else if (!strncmp (argp, "-color", 3)) { + color = 1; + } else if (!strncmp (argp, "-mono", 2)) { + color = 0; + } else if (!strncmp (argp, "-reverse", 4)) { + SWAP (red[0], red[1]); + SWAP (green[0], green[1]); + SWAP (blue[0], blue[1]); + reverse_video = 1; + } else if (!strncmp (argp, "-noreverse", 6)) { + reverse_video = 0; + } else if (!strncmp (argp, "-ginterm", 2)) { + if (argv[arg+1] && isdigit (argv[arg+1][0])) + strcpy (gin_modeterm, argv[++arg]); + if (argv[arg+1] && isdigit (argv[arg+1][0])) { + strcat (gin_modeterm, " "); + strcat (gin_modeterm, argv[++arg]); + } + gio_setginmodeterm (gin_modeterm); + } else if (!strncmp (argp, "-logfile", 2)) { + strcpy (logfile, argv[++arg]); + } else + frame_argv[frame_argc++] = argp; + } + + /* Open the tek-alpha and text mode graphics fonts. */ + if (gio_getbestfont (win_xsize, win_ysize) == -1) + exit (1); + + /* Open graphics window and canvas. Generate a default size + * landscape mode window and position it relative to the base frame. + */ + gio_frame = window_create (gt_baseframe, FRAME, + FRAME_ARGS, frame_argc, frame_argv, + FRAME_NO_CONFIRM, TRUE, + WIN_HEIGHT, win_ysize + (TOOL_BORDERWIDTH * 2), + WIN_WIDTH, win_xsize + (TOOL_BORDERWIDTH * 2), + WIN_X, win_xoff, + WIN_Y, win_yoff, + 0); + gio_canvas = window_create (gio_frame, CANVAS, + CANVAS_RETAINED, canvas_retained ? TRUE : FALSE, + 0); + + /* Set the initial "plus" type graphics cursor. This changes to + * a full crosshair cursor only when the cursor position is being + * read by the applications program. + */ + gio_setcursor (CURSOR_ON, CROSSHAIR_OFF); + + /* Set input event flags. */ + window_set (gio_canvas, + WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS, + WIN_MOUSE_BUTTONS, LOC_DRAG, WIN_UP_EVENTS, 0, + WIN_CONSUME_KBD_EVENTS, WIN_NO_EVENTS, WIN_ASCII_EVENTS, + WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, 0, + 0); + + /* Get canvas pixwin */ + pw = canvas_pixwin (gio_canvas); + if (pw->pw_pixrect->pr_depth == 1) + color = 0; + + /* Set up the default color map. */ + sprintf (mapname, "MONO%04d", getpid() % 10000); + pw_setcmsname (pw, mapname); + pw_putcolormap (pw, 0, 2, red, green, blue); + + if (!color) { + /* Monochrome graphics. */ + /* window_set (gio_canvas, CANVAS_FAST_MONO, TRUE, 0); */ + if (reverse_video) + pw_whiteonblack (pw, 0, 1); + else + pw_blackonwhite (pw, 0, 1); + } +} + + +static Panel_item pan_graphics_enable, pan_openws_action, pan_closews_action; +static Panel_item pan_closews_pause, pan_retain_graphics, pan_clip_graphics; +static Panel_item pan_graphics_screen, pan_graphics_video, pan_alpha_font; + +/* CREATE_SETUP_POPUP -- Create the popup menu used to set the terminal + * setup options. + */ +static +create_setup_popup() +{ + extern reset_proc(), clear_proc(), gclear_proc(); + extern setup_proc(), toggle_graphics(); + static panel_set_item(), set_ginmodeterm(), set_logfile(); + + setup_frame = window_create (gt_baseframe, FRAME, + FRAME_NO_CONFIRM, TRUE, + WIN_X, setup_xoff, + WIN_Y, setup_yoff, + 0); + setup_panel = window_create (setup_frame, PANEL, 0); + + panel_create_item (setup_panel, PANEL_MESSAGE, + PANEL_ITEM_X, ATTR_COL(11), + PANEL_ITEM_Y, ATTR_ROW(0), + PANEL_LABEL_STRING, "Graphics Terminal Setup Options", + 0); + + pan_graphics_enable = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(1), + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Graphics plane: ", + PANEL_CHOICE_STRINGS, "Disable", "Enable", + "Discard Graphics Data", 0, + PANEL_VALUE, graphics_enable, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_openws_action = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(2), + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Open workstation action: ", + PANEL_CHOICE_STRINGS, "No action", "Show graphics", + "Expose graphics", 0, + PANEL_VALUE, openws_action, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_closews_action = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(3), + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Close workstation action: ", + PANEL_CHOICE_STRINGS, "No action", "Blank graphics", + "Hide graphics", 0, + PANEL_VALUE, closews_action, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_closews_pause = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(4), + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Pause on close workstation: ", + PANEL_CHOICE_STRINGS, "No", "Yes", 0, + PANEL_VALUE, closews_pause, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_retain_graphics = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(5), + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Retain graphics frame: ", + PANEL_CHOICE_STRINGS, "No", "Yes", 0, + PANEL_VALUE, canvas_retained, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_clip_graphics = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(6), + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Clip graphics: ", + PANEL_CHOICE_STRINGS, "No", "Yes", 0, + PANEL_VALUE, clip_graphics, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + if (pw->pw_pixrect->pr_depth > 1) { + pan_graphics_screen = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(7), + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Graphics screen type: ", + PANEL_CHOICE_STRINGS, "Mono", "Color", 0, + PANEL_VALUE, color, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + } else { + pan_graphics_screen = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(7), + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Graphics screen type: ", + PANEL_CHOICE_STRINGS, "Mono only", 0, + PANEL_VALUE, color, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + } + + pan_graphics_video = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(8), + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Graphics video: ", + PANEL_CHOICE_STRINGS, "Normal", "Reverse", 0, + PANEL_VALUE, reverse_video, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_alpha_font = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(9), + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Graphics font and screen sizes:", + PANEL_CHOICE_STRINGS, alpha_fonts[0].label, + alpha_fonts[1].label, + alpha_fonts[2].label, + alpha_fonts[3].label, + alpha_fonts[4].label, + alpha_fonts[5].label, + 0, + PANEL_VALUE, alpha_font_index, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + panel_create_item (setup_panel, PANEL_TEXT, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(10) + 3, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Logfile name: ", + PANEL_VALUE, logfile, + PANEL_VALUE_STORED_LENGTH, SZ_FNAME, + PANEL_VALUE_DISPLAY_LENGTH, 20, + PANEL_NOTIFY_PROC, set_logfile, + 0); + + panel_create_item (setup_panel, PANEL_TEXT, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(11) + 3, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "GIN mode terminators (octal): ", + PANEL_VALUE, gin_modeterm, + PANEL_VALUE_STORED_LENGTH, SZ_GINMODETERM, + PANEL_VALUE_DISPLAY_LENGTH, SZ_GINMODETERM, + PANEL_NOTIFY_PROC, set_ginmodeterm, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(12) + 3, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Reset", 0,0), + PANEL_NOTIFY_PROC, reset_proc, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Clear", 0,0), + PANEL_NOTIFY_PROC, clear_proc, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Gclear", 0,0), + PANEL_NOTIFY_PROC, gclear_proc, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Show graphics", 0,0), + PANEL_NOTIFY_PROC, toggle_graphics, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Quit", 0,0), + PANEL_NOTIFY_PROC, setup_proc, + 0); + + window_fit (setup_panel); + window_fit (setup_frame); +} + + +/* PANEL_SET_ITEM -- Called when an item is seleted in the setup panel to + * set the associated global variable and possibly take some action. + */ +static +panel_set_item (item, value) +Panel_item item; +int value; +{ + if (item == pan_graphics_enable) { + gio_enable (graphics_enable = value); + } else if (item == pan_openws_action) { + openws_action = value; + } else if (item == pan_closews_action) { + closews_action = value; + } else if (item == pan_closews_pause) { + if (closews_pause != value) { + closews_pause = value; + show_pausepanel (0); + } + } else if (item == pan_clip_graphics) { + clip_graphics = value; + } else if (item == pan_graphics_screen) { + if (color != value) { + if (value) + pw_putcolormap (pw, 0, 2, red, green, blue); + else if (reverse_video) + pw_whiteonblack (pw, 0, 1); + else + pw_blackonwhite (pw, 0, 1); + color = value; + } + } else if (item == pan_graphics_video) { + if (reverse_video != value) { + if (pw->pw_pixrect->pr_depth > 1) { + unsigned char r[2], g[2], b[2]; + + pw_getcolormap (pw, 0, 2, r, g, b); + SWAP (r[0], r[1]); + SWAP (g[0], g[1]); + SWAP (b[0], b[1]); + pw_putcolormap (pw, 0, 2, r, g, b); + if (color) + pw_getcolormap (pw, 0, 2, red, green, blue); + } else if (value) { + pw_whiteonblack (pw, 0, 1); + } else + pw_blackonwhite (pw, 0, 1); + + reverse_video = value; + } + } else if (item == pan_retain_graphics) { + if (canvas_retained != value) { + canvas_retained = value; + notify_remove_event_func (gio_canvas, + ev_gioinput, NOTIFY_SAFE); + window_destroy (gio_frame); + parse_args (main_argc, main_argv, + &tty_argc, tty_argv, &gio_argc, gio_argv); + create_gio_popup (gio_argc, gio_argv); + notify_interpose_event_func (gio_canvas, + ev_gioinput, NOTIFY_SAFE); + gio_setup (pty_fd, pw); + gio_reset (DEF_TEKXRES, DEF_TEKYRES, alpha_font, text_font); + } + } else if (item == pan_alpha_font) { + if (alpha_font_index != value) { + struct fonttab *ft = &alpha_fonts[value]; + int xorigin, yorigin, xoffset, yoffset; + int g_xsize, g_ysize, g_xorig, g_yorig; + + /* Determine whether the offset of the subframe from the base + * frame needs to be modified to keep the frame on the screen. + */ + xorigin = (int) window_get (gt_baseframe, WIN_X); + yorigin = (int) window_get (gt_baseframe, WIN_Y); + xoffset = win_xoff; + yoffset = win_yoff; + + g_xsize = ft->win_xsize + (TOOL_BORDERWIDTH * 2); + g_ysize = ft->win_ysize + (TOOL_BORDERWIDTH * 2); + g_xorig = xorigin + xoffset; /* screen relative */ + g_yorig = yorigin + yoffset; /* screen relative */ + + if (g_xorig + g_xsize >= screen.r_width) + xoffset -= (g_xorig + g_xsize - screen.r_width); + if (g_yorig + g_ysize >= screen.r_height) + yoffset -= (g_yorig + g_ysize - screen.r_height); + + /* Resize and/or move the gio frame. The gio_frame event + * handler will detect the resize and select a new font. + */ + window_set (gio_frame, WIN_SHOW, FALSE, + WIN_WIDTH, g_xsize, WIN_HEIGHT, g_ysize, 0); + + /* Cannot set a negative subframe offset, so move base frame + * to screen origin temporarily if the gio frame won't fit at + * the lower right. Note that win_[xy]off are not permanently + * changed, so restoring the original size should return the + * window to its original position. + */ + if (gio_frame_has_moved = (xoffset < 0 || yoffset < 0)) { + window_set (gt_baseframe, WIN_X, 0, WIN_Y, 0, 0); + window_set (gio_frame, + WIN_X, xorigin + xoffset, WIN_Y, yorigin + yoffset, 0); + window_set (gt_baseframe, WIN_X,xorigin, WIN_Y,yorigin, 0); + } else + window_set (gio_frame, WIN_X, xoffset, WIN_Y, yoffset, 0); + + window_set (gio_frame, WIN_SHOW, TRUE, 0); + + /* If the setup panel is on, move it to the top. */ + if ((int) window_get (setup_frame, WIN_SHOW) == TRUE) + window_set (setup_frame, WIN_SHOW, TRUE, 0); + } + } +} + + +/* TOGGLE_FULLSCREEN -- Toggle between a full screen graph and a regular size + * graph. + */ +static +toggle_fullscreen() +{ + static save_index = -1; + + if (alpha_font_index == FULLSCREEN && save_index >= 0) + panel_set_item (pan_alpha_font, save_index); + else { + save_index = alpha_font_index; + panel_set_item (pan_alpha_font, FULLSCREEN); + } +} + + +/* SET_GINMODETERM -- Set the GIN mode terminators. + */ +static Panel_setting +set_ginmodeterm (item, event) +Panel_item item; +Event *event; +{ + strcpy (gin_modeterm, + (char *)panel_get_value (item)); + gio_setginmodeterm (gin_modeterm); + + return (panel_text_notify (item,event)); +} + + +/* SET_LOGFILE -- Set the filename of the logfile. + */ +static Panel_setting +set_logfile (item, event) +Panel_item item; +Event *event; +{ + if (gt_logfp) { + fclose (gt_logfp); + gt_logfp = NULL; + menu_set (logitem, MENU_STRING, "Logging on", 0); + } + + strcpy (logfile, + (char *)panel_get_value (item)); + return (panel_text_notify (item,event)); +} + + +/* SETUP_PROC -- Toggle whether or not the setup panel is shown. + */ +static +setup_proc() +{ + if (setup_frame == NULL) { + create_setup_popup(); + create_setup_popup (0, NULL); + panel_set_item(); + window_set (setup_frame, WIN_SHOW, TRUE, 0); + } else { + window_destroy (setup_frame); + setup_frame = NULL; + } +} + + +/* TEXTCOPY_PROC -- Make a hardcopy of the tty window on the laserwriter. + */ +static +textcopy_proc() +{ + int depth = 1; + + window_set (gt_baseframe, WIN_SHOW, TRUE, 0); + notify_dispatch(); + + screendump ( + (int)window_get(gt_ttysw,WIN_FD), win_get_pixwin(gt_ttysw), + (int) window_get (gt_baseframe, WIN_WIDTH) - TOOL_BORDERWIDTH * 2, + (int) window_get (gt_baseframe, WIN_HEIGHT) - HEIGHTADJUST, + (int) window_get (gt_baseframe, WIN_X) + TOOL_BORDERWIDTH, + (int) window_get (gt_baseframe, WIN_Y) + HEIGHTADJUST - + TOOL_BORDERWIDTH, + depth); +} + + +/* GRAPHCOPY_PROC -- Make a hardcopy of the gio window on the laserwriter. + */ +static +graphcopy_proc() +{ + int depth = 1; + + window_set (gio_frame, WIN_SHOW, TRUE, 0); + notify_dispatch(); + + screendump ( + (int)window_get(gio_canvas,WIN_FD), pw, + (int) window_get (gio_frame, WIN_WIDTH) - TOOL_BORDERWIDTH * 2, + (int) window_get (gio_frame, WIN_HEIGHT) - TOOL_BORDERWIDTH * 2, + (int) window_get (gt_baseframe, WIN_X) + + (int) window_get (gio_frame, WIN_X) + TOOL_BORDERWIDTH, + (int) window_get (gt_baseframe, WIN_Y) + + (int) window_get (gio_frame, WIN_Y) + TOOL_BORDERWIDTH, + depth); +} + + +/* SCREENCOPY_PROC -- Make a bitmap hardcopy of the screen on the laserwriter. + */ +static +screencopy_proc() +{ + int depth = 1; + + screendump ( + (int)window_get(gt_ttysw,WIN_FD), win_get_pixwin(gt_ttysw), + screen.r_width, screen.r_height, screen.r_left, screen.r_top, + depth); +} + + +/* SCREENCOPY8_PROC -- Make a greyscale hardcopy of the screen on the + * laserwriter. + */ +static +screencopy8_proc() +{ + int depth = 8; + + screendump ( + (int)window_get(gt_ttysw,WIN_FD), win_get_pixwin(gt_ttysw), + screen.r_width, screen.r_height, screen.r_left, screen.r_top, + depth); +} + + +/* CREATE_PAUSE_POPUP -- Create the pause popup menu used to wait for + * a user response. + */ +static +create_pause_popup() +{ + pause_frame = window_create (gt_baseframe, FRAME, + FRAME_NO_CONFIRM, TRUE, + WIN_X, win_xoff + 5, + WIN_Y, win_yoff + 5, + 0); + pause_panel = window_create (pause_frame, PANEL, 0); + + panel_create_item (pause_panel, PANEL_MESSAGE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(0), + PANEL_LABEL_STRING, "Hit any key to continue", + 0); + + window_fit (pause_panel); + window_fit (pause_frame); +} + + +/* SHOW_PAUSEPANEL -- Toggle display of the pause panel. + */ +static +show_pausepanel (onoff) +int onoff; +{ + if (onoff == 0) { + if (pause_frame) { + window_destroy (pause_frame); + pause_frame = NULL; + } + } else { + if (!pause_frame) + create_pause_popup(); + window_set (pause_frame, + WIN_X, win_xoff + 5, + WIN_Y, win_yoff + 5, + 0); + window_set (pause_frame, WIN_SHOW, TRUE, 0); + } +} + + +/* CREATE_FRAME_MENU -- Gterm uses a special frame menu which provides the + * standard frame menu as a submenu. + */ +static +create_frame_menu (frame) +Frame frame; +{ + extern textcopy_proc(), graphcopy_proc(), screencopy_proc(); + extern setup_proc(), toggle_graphics(), restart_childpgrp(); + extern toggle_logging(); + Menu new_menu, old_menu; + + /* Get the standard frame menu. */ + old_menu = (Menu) window_get (frame, WIN_MENU); + + /* Create the new frame root menu */ + new_menu = menu_create ( + MENU_PULLRIGHT_ITEM, + "Frame", + old_menu, + MENU_ACTION_ITEM, + "Setup", + setup_proc, + MENU_ACTION_ITEM, + "Continue", + restart_childpgrp, + MENU_ACTION_ITEM, + "Logging on", + toggle_logging, + MENU_ACTION_ITEM, + "Show graph", + toggle_graphics, + MENU_ACTION_ITEM, + "Textcopy", + textcopy_proc, + MENU_ACTION_ITEM, + "Graphcopy", + graphcopy_proc, + MENU_ACTION_ITEM, + "Screencopy", + screencopy_proc, + /* + MENU_ACTION_ITEM, + "Screencopy8", + screencopy8_proc, + */ + 0); + + logitem = menu_find (new_menu, MENU_STRING, "Logging on", 0); + + /* Install the new menu. */ + window_set (frame, WIN_MENU, new_menu, 0); +} + + +/* TOGGLE_LOGGING -- Called from the frame menu to turn logging on/off. + */ +static +toggle_logging() +{ + if (gt_logfp) { + fclose (gt_logfp); + gt_logfp = NULL; + menu_set (logitem, MENU_STRING, "Logging on", 0); + } else { + if ((gt_logfp = fopen (logfile, "a")) == NULL) + fprintf (stderr, "cannot open logfile %s\n", logfile); + else + menu_set (logitem, MENU_STRING, "Logging off", 0); + } +} + + +/* EV_GT_TTYSW -- TTY subwindow input event handler. + */ +static Notify_value +ev_gt_ttysw (frame, event, arg, type) +Frame frame; +Event *event; +Notify_arg arg; +Notify_event_type type; +{ + register int key = event_id(event); + + if (pause_mode && (event_is_ascii(event) || event_is_button(event))) { + /* If we are pausing for input before closing the workstation, + * complete the close workstation operation and discard the event. + */ + show_pausepanel (0); + gio_close_workstation(); + return (NOTIFY_DONE); + } + + if (event_is_ascii(event)) { + /* Save the cursor position in tty window for later restoration. */ + tty_lastx = event_x(event); + tty_lasty = event_y(event); + + /* Ignore control codes if -ignore set? */ + if (iscntrl(key) && key != '\r' && ignore_inputevent(event)) + return (NOTIFY_DONE); + + /* Ignore typein into text window while a cursor read is in + * progress, else an invalid exit from the cursor read may result. + */ + if (cursor_read_pending) + return (NOTIFY_DONE); + + } else if (event_id(event) == KEY_TOP(7) && event_is_down(event)) { + /* Toggle between full screen and regular size graph. */ + toggle_fullscreen(); + + } else if (event_id(event) == KEY_TOP(8) && event_is_down(event)) { + /* Clear or enable the graphics plane. */ + char buf[4]; + + tty_lastx = event_x(event); + tty_lasty = event_y(event); + + /* If already in graphics mode, clear the graphics plane, else + * switch to graphics mode w/o clearing the screen (the user can + * simply type F8 again if they also want to clear the screen). + */ + if (gio_graphicsenabled && !cursor_read_pending) { + buf[0] = '\035'; + buf[1] = '\033'; + buf[2] = '\014'; + ev_ptyoutput (buf, 3); + + } else if (!gio_graphicsenabled && graphics_enable == GRAPHICS_ON) { + buf[0] = '\035'; + buf[1] = '\037'; + ev_ptyoutput (buf, 2); + /* + window_set (gt_ttysw, + WIN_CONSUME_KBD_EVENTS, KEY_TOP(9), 0, + 0); + */ + } + + return (NOTIFY_DONE); + + } else if (event_id(event) == KEY_TOP(9) && event_is_down(event)) { + /* Exit graphics mode, returning to text mode. + */ + if (gio_graphicsenabled && !cursor_read_pending) { + char buf[1]; + + cursor_used++; /* disable pause on CW */ + buf[0] = '\030'; + ev_ptyoutput (buf, 1); + /* + window_set (gt_ttysw, + WIN_IGNORE_KBD_EVENTS, KEY_TOP(9), 0, + 0); + */ + return (NOTIFY_DONE); + } else if (!gio_graphicsenabled) + ttysw_output (gt_ttysw, "\f", 1); + } + + /* Let frame operate upon the event. */ + return (notify_next_event_func (frame, event, arg, type)); +} + + +/* IGNORE_INPUTEVENT -- Ignore the current input event? + * The following is a kludge intended to prevent delivering the suspend + * signal to a process which is run in the gterm window without benefit of + * an intermediate shell. This is only done if "-ignore" (stop signals) + * is specified on the command line, and only if the command being run in + * GTERM is not a shell. This is a dangerous thing to do, as the characters + * may be valid input data to a program operating in raw input mode. + */ +static +ignore_inputevent (event) +Event *event; +{ + register int key = event_id(event); + struct ltchars lt; + struct sgttyb sg; + + if (!shell && event_ctrl_is_down(event)) { + /* Control code assignments may change, so reread them. */ + if (ioctl (pty_fd, TIOCGLTC, <) != -1) { + t_suspc = lt.t_suspc; + t_dsuspc = lt.t_dsuspc; + } + + /* Echo but ignore suspend control characters if not in raw mode. */ + if (key == t_suspc || key == t_dsuspc) { + if (ioctl(pty_fd,TIOCGETP,&sg) != -1 && (!(sg.sg_flags&RAW))) { + char out[2]; + out[0] = '^'; + out[1] = (key & 077) + '@'; + ttysw_output (gt_ttysw, out, 2); + return (1); + } + } + } + + return (0); +} + + +/* EV_TTYFRAME -- TTY frame event handler. + */ +static Notify_value +ev_ttyframe (frame, event, arg, type) +Frame frame; +Event *event; +Notify_arg arg; +Notify_event_type type; +{ + Notify_value value; + static int ignore_resize = 1; + + /* Let frame operate upon the event. */ + value = notify_next_event_func (frame, event, arg, type); + + if (event_id(event) == WIN_RESIZE) { + /* Tty_adjustheight, if it resizes the window, will cause a resize + * event to be queued and we will be called back. Set a flag to + * ignore this event or an infinite loop will result. + */ + if (ignore_resize) + ignore_resize = 0; + else { + ignore_resize = 1; + tty_adjustheight (0); + } + } + + return (value); +} + + +/* TTY_ADJUSTHEIGHT -- Called when the tty window is initially sized or when + * it is dynamically resized to adjust the size to an integral number of lines + * and allow space for the panel at the top (this is NOT done when the tty + * window resizes itself, although it should be). + */ +static +tty_adjustheight (nrows) +int nrows; +{ + struct pixfont *pf; + int height; + + if (nrows == 0) + nrows = (int) window_get (gt_ttysw, WIN_ROWS); + + pf = (struct pixfont *) window_get (gt_baseframe, WIN_FONT); + height = HEIGHTADJUST + pf->pf_defaultsize.y * nrows + 1; + + if (height != (int) window_get (gt_baseframe, WIN_HEIGHT)) + window_set (gt_baseframe, WIN_HEIGHT, height, 0); +} + + +/* GIO_OPEN_WORKSTATION -- Called by the low level gtermio code when there is + * output to the graphics frame but the frame is in a closed state. + */ +gio_open_workstation() +{ + cursor_used = 0; + gio_setcursor (CURSOR_OFF, 0); + if (openws_action == NO_ACTION) + return; + + if (!gio_frame_has_moved) + window_set (gio_frame, + WIN_HEIGHT, win_ysize + (TOOL_BORDERWIDTH * 2), + WIN_WIDTH, win_xsize + (TOOL_BORDERWIDTH * 2), + WIN_X, win_xoff, + WIN_Y, win_yoff, + 0); + + switch (openws_action) { + case SHOW_FRAME: + window_set (gio_frame, WIN_SHOW, TRUE, 0); + break; + case EXPOSE_FRAME: + set_coverwindow (gio_frame, gt_baseframe); + break; + } + + /* If the setup panel is on, move it to the top. */ + if ((int) window_get (setup_frame, WIN_SHOW) == TRUE) + window_set (setup_frame, WIN_SHOW, TRUE, 0); +} + + +/* GIO_CLOSE_WORKSTATION -- Called by the low level gtermio code when the CAN + * sequence is received, to turn off or hide the now inactive graphics window. + */ +gio_close_workstation() +{ + if (cursor_used) + window_set (gt_ttysw, WIN_MOUSE_XY, tty_lastx, tty_lasty, 0); + gio_setcursor (CURSOR_ON, CROSSHAIR_OFF); + + if (closews_action != NO_ACTION) + if (closews_pause && !pause_mode && !cursor_used) { + show_pausepanel (1); + pause_mode = 1; + return; + } + + /* If the window has been closed, do nothing. */ + if (window_get (gio_frame, WIN_SHOW)) + switch (closews_action) { + case UNSHOW_FRAME: + window_set (gio_frame, WIN_SHOW, FALSE, 0); + break; + case HIDE_FRAME: + set_coverwindow (gt_baseframe, gio_frame); + break; + } + + pause_mode = 0; +} + + +/* SET_COVERWINDOW -- Make the first window cover the second if they overlap. + */ +static +set_coverwindow (win_top, win_bot) +Frame win_top, win_bot; +{ + int fd_top, fd_bot; + + fd_top = (int) window_get (gt_baseframe, WIN_FD); + fd_bot = (int) window_get (gio_frame, WIN_FD); + + win_lockdata (fd_top); + win_lockdata (fd_bot); + win_remove (fd_bot); + win_setlink (fd_bot, WL_COVERING, win_fdtonumber(fd_top)); + win_insert (fd_bot); + win_unlockdata (fd_bot); + win_unlockdata (fd_top); +} + + +/* EV_GIOFRAME -- GIO frame event handler. + */ +static Notify_value +ev_gioframe (frame, event, arg, type) +Frame frame; +Event *event; +Notify_arg arg; +Notify_event_type type; +{ + Notify_value value; + int o_xoff, o_yoff, n_xoff, n_yoff; + + o_xoff = (int) window_get (gio_frame, WIN_X); + o_yoff = (int) window_get (gio_frame, WIN_Y); + + /* Let frame operate upon the event. */ + value = notify_next_event_func (frame, event, arg, type); + + n_xoff = (int) window_get (gio_frame, WIN_X); + n_yoff = (int) window_get (gio_frame, WIN_Y); + + /* Determine if the graphics window has been moved by the user. + * If so, we don't want to move it ourselves any more. + */ + if (n_xoff != o_xoff || n_yoff != o_yoff) { + gio_frame_has_moved = 1; + win_xoff = n_xoff; + win_yoff = n_yoff; + } + + return (value); +} + + +/* EV_GIOINPUT -- GIO input event handler. + */ +static Notify_value +ev_gioinput (frame, event, arg, type) +Frame frame; +Event *event; +Notify_arg arg; +Notify_event_type type; +{ + register int key; + Notify_value value; + char ch; + + /* If we are pausing for input before closing the workstation, + * complete the close workstation operation and discard the event. + */ + if (pause_mode && (event_is_ascii(event) || event_is_button(event))) { + show_pausepanel (0); + gio_close_workstation(); + return (NOTIFY_DONE); + } + + /* Let frame operate upon the event. */ + value = notify_next_event_func (frame, event, arg, type); + + switch (key = event_id (event)) { + case WIN_RESIZE: + win_xsize = (int) window_get (gio_frame, WIN_WIDTH) - + (TOOL_BORDERWIDTH * 2); + win_ysize = (int) window_get (gio_frame, WIN_HEIGHT) - + (TOOL_BORDERWIDTH * 2); + if (!gio_frame_has_moved) { + win_xoff = (int) window_get (gio_frame, WIN_X); + win_yoff = (int) window_get (gio_frame, WIN_Y); + } + + if (!cursor_read_pending) + gio_setcursor (CROSSHAIR_OFF, CURSOR_ON); + + gio_getbestfont (win_xsize, win_ysize); + gio_reset (DEF_TEKXRES, DEF_TEKYRES, alpha_font, text_font); + break; + + case MS_RIGHT: + /* When a cursor read is not in progress, i.e., the gio window + * is idle, the right mouse button will cause the crosshairs to + * be displayed while the button is held down and the cursor is + * in the graphics window. During a cursor read the right button + * may be used to alias a key, like the left and middle buttons + * below. + */ + if (cursor_read_pending && event_is_down(event)) { + if (event_ctrl_is_down (event)) + key_right = last_key; + else if (key = key_right) + goto readcur; + } else if (!cursor_read_pending) { + if (event_is_down (event)) + gio_setcursor (CROSSHAIR_ON, CURSOR_ON); + else + gio_setcursor (CROSSHAIR_OFF, 0); + } + break; + + case MS_LEFT: + case MS_MIDDLE: + /* The left and middle mouse buttons may be used while in the + * graphics window to alias keyboard events. Typing ctrl/button + * causes the last key to be aliased with the indicated button. + * Thereafter, pressing that mouse button during a cursor read + * causes the cursor read to terminate, returning the aliased + * key just as if the key had been typed on the keyboard. + */ + if (event_is_down (event)) + if (event_ctrl_is_down (event)) { + if (key == MS_LEFT) + key_left = last_key; + else + key_middle = last_key; + } else if (cursor_read_pending) { + if (key == MS_LEFT) + key = key_left; + else + key = key_middle; + if (key) + goto readcur; + } + break; + + case KEY_TOP(7): + /* Toggle full screen graphics mode. + */ + if (event_is_down(event)) + toggle_fullscreen(); + break; + + case KEY_TOP(8): + /* Clear the graphics screen, leaving the terminal in graphics + * mode. + */ + if (event_is_down(event) && !cursor_read_pending) { + char buf[3]; + + buf[0] = '\035'; + buf[1] = '\033'; + buf[2] = '\014'; + ev_ptyoutput (buf, 3); + } + break; + + case KEY_TOP(9): + case KEY_LEFT(7): + /* Exit graphics mode, returning to text mode. + */ + if (event_is_down(event) && !cursor_read_pending) { + char buf[1]; + + /* + window_set (gt_ttysw, + WIN_IGNORE_KBD_EVENTS, KEY_TOP(9), 0, + 0); + */ + + if (key == KEY_LEFT(7)) /* delay CW until after L7 */ + gio_pause (500); + + cursor_used++; /* disable pause on CW */ + buf[0] = '\030'; + ev_ptyoutput (buf, 1); + } + break; + + default: + /* Terminate a cursor read, returning the encoded cursor value + * sequence to the terminal output. + */ + if (event_is_down(event) && + (event_is_ascii(event) || event_is_key_right(event))) { + + /* Ignore control codes if -ignore set? */ + if (iscntrl(key) && key != '\r' && ignore_inputevent(event)) + return (value); + + /* Terminate cursor read? */ + if (cursor_read_pending) { + /* Map keypad function keys to digits. */ + if (event_is_key_right(event)) { + switch (key = event_id(event) - KEY_RIGHT(1) + 1) { + case 7: case 8: case 9: + break; + case 10: case 11: case 12: + key -= 6; + break; + case 13: case 14: case 15: + key -= 12; + break; + default: + return (value); + } + key += '0'; + } +readcur: + last_x = event_x (event); + last_y = event_y (event); + last_key = key; + + cursor_read_pending = 0; + gio_setcursor (CURSOR_OFF, CROSSHAIR_OFF); + gio_retcursor (key, last_x, last_y); + enable_arrow_keys(); + + } else + write (pty_fd, (ch=key, &ch), 1); + } + } + + return (value); +} + + +/* SIG_TSTP -- Signal handler for signal SIGTSTP. + */ +static Notify_func +sig_tstp() +{ + kill (getpid(), SIGSTOP); +} + + +/* RESTART_CHILDPGRP -- Send the SIGCONT signal to the process group + * associated with this terminal, e.g., to restart the processes after + * the user has accidentally typed the stop character. + */ +static +restart_childpgrp() +{ + int pgrp; + + ioctl (pty_fd, TIOCGPGRP, &pgrp); + killpg (pgrp, SIGCONT); +} + + +/* GIO_GETBESTFONT -- Scan the font table and open the tek-alpha font which + * best fits the given size window. The important dimension is the window + * width, since the character spacing is fixed. Also pick a text (status + * line) font small enough to provide space for at least 80 chars. + */ +static +gio_getbestfont (xsize, ysize) +int xsize, ysize; /* canvas size, x,y */ +{ + register struct fonttab *ft, *o_ft; + register int i; + struct pixfont *newfont; + char pathname[256]; + + /* Select tek-alpha font. + */ + for (i=0, o_ft=ft=alpha_fonts; ft->pointsize != 0; o_ft=ft++, i++) + if (ft->win_xsize > xsize) + break; + + if (i == 0) + i = 1; + + sprintf (pathname, o_ft->path, o_ft->pointsize); + if ((newfont = pf_open (pathname)) == NULL) { + fprintf (stderr, "cannot open font %s\n", pathname); + return (-1); + } else if (alpha_font != NULL) + pf_close (alpha_font->pixfont); + + alpha_font = o_ft; + alpha_font->pixfont = newfont; + alpha_font_index = i - 1; + + /* Load the text (status line) font. + */ + o_ft = &text_fonts[i-1]; + sprintf (pathname, o_ft->path, o_ft->pointsize); + if ((newfont = pf_open (pathname)) == NULL) { + fprintf (stderr, "cannot open font %s\n", pathname); + return (-1); + } else if (text_font != NULL) + pf_close (text_font->pixfont); + + text_font = o_ft; + text_font->pixfont = newfont; + text_font_index = i - 1; + + return (0); +} + + +/* GIO_SETCURSOR -- Set graphics frame cursor options. + */ +gio_setcursor (op1, op2) +int op1, op2; +{ + Cursor cursor; + int option[2], i; + int type=cursor_type, show=cursor_show; + + /* Normalize the argument list. */ + for (option[0]=op1, option[1]=op2, i=0; i < 2; i++) + switch (option[i]) { + case CROSSHAIR_OFF: + case CROSSHAIR_ON: + type = option[i]; + break; + case CURSOR_OFF: + case CURSOR_ON: + show = option[i]; + break; + } + + /* Do we need to change anything? */ + if (type == cursor_type && show == cursor_show) + return; + + /* Modify the cursor attributes. */ + cursor = window_get (gio_canvas, WIN_CURSOR); + cursor_set (cursor, + CURSOR_SHOW_CURSOR, FALSE, + CURSOR_SHOW_CROSSHAIRS, (show==CURSOR_ON) ? TRUE : FALSE, + CURSOR_CROSSHAIR_THICKNESS, 1, + CURSOR_CROSSHAIR_LENGTH, (type==CROSSHAIR_ON) ? CURSOR_TO_EDGE : 10, + CURSOR_CROSSHAIR_OP, PIX_SRC, + CURSOR_CROSSHAIR_COLOR, 1, + 0); + window_set (gio_canvas, WIN_CURSOR, cursor, 0); + + cursor_type = type; + cursor_show = show; +} + + +/* GIO_SETCURSORPOS -- Set the position of the graphics cursor within the + * graphics frame. + */ +gio_setcursorpos (x, y) +int x, y; /* pixwin pixel coords */ +{ + window_set (gio_canvas, WIN_MOUSE_XY, x, y, 0); + last_x = x; + last_y = y; + cursor_used++; +} + + +/* GIO_READCURSOR -- Initiate a cursor read. Set the cursor type to + * a full crosshair cursor to indicate to the user that the program is + * waiting for cursor input. Set the cursor read pending flag so that + * the next input event in graphics window will cause termination of the + * cursor read and transmission of the cursor value to the terminal output. + */ +gio_readcursor() +{ + /* When a cursor read is initiated, move the cursor into the gio + * window so that the user knows that cursor input is expected. + */ + if (last_x < 0) { + last_x = win_xsize / 2; + last_y = win_ysize / 2; + } + + /* Disable the mapping of the right function keys to the ansi arrow + * key escape sequences, since we want to receive these keys as + * function key events. + */ + disable_arrow_keys(); + + gio_setcursorpos (last_x, last_y); + gio_setcursor (CURSOR_ON, CROSSHAIR_ON); + cursor_read_pending++; + cursor_used++; +} + + +/* TOGGLE_GRAPHICS -- Show or hide the graphics frame. + */ +static +toggle_graphics() +{ + if ((int) window_get (gio_frame, WIN_SHOW) == TRUE) + window_set (gio_frame, WIN_SHOW, FALSE, 0); + else { + if (!gio_frame_has_moved) + window_set (gio_frame, + WIN_HEIGHT, win_ysize + (TOOL_BORDERWIDTH * 2), + WIN_WIDTH, win_xsize + (TOOL_BORDERWIDTH * 2), + WIN_X, win_xoff, + WIN_Y, win_yoff, + 0); + window_set (gio_frame, WIN_SHOW, TRUE, 0); + + /* If the setup panel is on, move it to the top. */ + if ((int) window_get (setup_frame, WIN_SHOW) == TRUE) + window_set (setup_frame, WIN_SHOW, TRUE, 0); + } +} + + +/* RESET_PROC -- Called from the setup panel to reset the state of the + * terminal. + */ +static +reset_proc() +{ + /* Cancel any pending cursor read. */ + if (cursor_read_pending) { + gio_retcursor ('\r', 0, 0); + enable_arrow_keys(); + } + + /* Cancel logging if enabled. */ + if (gt_logfp) { + fclose (gt_logfp); + gt_logfp = NULL; + menu_set (logitem, MENU_STRING, "Logging on", 0); + } + + /* Restore user settable options. */ + restore_params(); + + /* Reset internal state variables. */ + cursor_type = -1; /* crosshair or small cursor */ + cursor_show = -1; /* cursor on or off */ + cursor_read_pending = 0; /* waiting for cursor event */ + key_left = 0; /* key aliased to left msbutton */ + key_middle = 0; /* key aliased to mid msbutton */ + key_right = 0; /* key aliased to mid msbutton */ + last_key = 0; /* last cursor read key */ + last_x= -1,last_y= -1; /* last cursor read position */ + setup_xoff = 150; /* offset to setup panel */ + setup_yoff = 150; + red[0] = green[0] = 0; + red[1] = green[1] = 255; + blue[0] = 128; blue[1] = 0; + gio_frame_has_moved = 0; + pause_mode = 0; + cursor_used = 0; + + /* Reset internal state. */ + notify_remove_event_func (gio_canvas, ev_gioinput, NOTIFY_SAFE); + notify_remove_event_func (gio_frame, ev_gioframe, NOTIFY_SAFE); + window_destroy (gio_frame); + parse_args (main_argc, main_argv, + &tty_argc, tty_argv, &gio_argc, gio_argv); + create_gio_popup (gio_argc, gio_argv); + notify_interpose_event_func (gio_frame, ev_gioframe, NOTIFY_SAFE); + notify_interpose_event_func (gio_canvas, ev_gioinput, NOTIFY_SAFE); + gio_setup (pty_fd, pw); + gio_hardreset (DEF_TEKXRES, DEF_TEKYRES, alpha_font, text_font); + gio_enable (graphics_enable); + + if (pause_frame) + window_destroy (pause_frame); + + window_destroy (setup_frame); + create_setup_popup (0, NULL); + panel_set_item(); + window_set (setup_frame, WIN_SHOW, TRUE, 0); +} + + +/* SAVE_PARAMS -- Save the user settable options. + */ +static +save_params() +{ + s_clip_graphics = clip_graphics; + s_graphics_enable = graphics_enable; + s_openws_action = openws_action; + s_closews_action = closews_action; + s_closews_pause = closews_pause; + s_canvas_retained = canvas_retained; + s_reverse_video = reverse_video; + s_color = color; + s_win_xsize = win_xsize; + s_win_ysize = win_ysize; + s_win_xoff = win_xoff; + s_win_yoff = win_yoff; + s_ignore = ignore; + strcpy (s_gin_modeterm, gin_modeterm); +} + + +/* RESTORE_PARAMS -- Restore the user settable options. + */ +static +restore_params() +{ + clip_graphics = s_clip_graphics; + graphics_enable = s_graphics_enable; + openws_action = s_openws_action; + closews_action = s_closews_action; + closews_pause = s_closews_pause; + canvas_retained = s_canvas_retained; + reverse_video = s_reverse_video; + color = s_color; + win_xsize = s_win_xsize; + win_ysize = s_win_ysize; + win_xoff = s_win_xoff; + win_yoff = s_win_yoff; + ignore = s_ignore; + + strcpy (gin_modeterm, s_gin_modeterm); + gio_setginmodeterm (gin_modeterm); +} + + +/* CLEAR_PROC -- Called when the clear button is clicked to transmit the + * screen clear sequence to the TTY subwindow. + */ +static +clear_proc() +{ + static char clearscreen[] = "\f"; + ttysw_output (gt_ttysw, clearscreen, strlen(clearscreen)); +} + + +/* GCLEAR_PROC -- Called when the gclear button is clicked to clear the + * graphics window. + */ +static +gclear_proc() +{ + static char clearscreen[] = "\035\033\f"; + ev_ptyoutput (clearscreen, strlen(clearscreen)); +} + + +/* PRINT_USAGE -- Print instructions on how to use this window tool. + */ +static +print_usage (toolname) +char *toolname; +{ + char *bstyle = "[-B boldstyle] "; + + fprintf (stderr, + "syntax: %s [-C] %s[program [args]]\n", toolname, bstyle); + fprintf (stderr, + "-C redirect console output to this instance of %s\n", toolname); + fprintf (stderr, + "-B set boldstyle for this instance of %s\n", toolname); + fprintf (stderr, + " where boldstyle is a number from 1 to 8\n"); + fprintf (stderr, + "-I input the next argument to the shell run from %s\n", toolname); +} diff --git a/unix/sun/gterm.esc b/unix/sun/gterm.esc new file mode 100644 index 00000000..a557bd73 --- /dev/null +++ b/unix/sun/gterm.esc @@ -0,0 +1,46 @@ +/* + * GTERM.ESC -- Macros and data defining the escape sequences recognized by + * the graphics terminal. Ambiguous cases are resolved in favor of the + * entry which occurs first in the table. + */ +#define ESC_SETTEXTMODE 1 +#define ESC_ENQUIRE 2 +#define ESC_READCURSOR 3 +#define ESC_CLEARSCREEN 4 +#define ESC_SETCURSOR 5 +#define ESC_SETCHARSIZE0 6 +#define ESC_SETCHARSIZE1 7 +#define ESC_SETCHARSIZE2 8 +#define ESC_SETCHARSIZE3 9 +#define ESC_SETDATALEVEL0 10 +#define ESC_SETDATALEVEL1 11 +#define ESC_SETDATALEVEL2 12 +#define ESC_SETLINESTYLE0 13 +#define ESC_SETLINESTYLE1 14 +#define ESC_SETLINESTYLE2 15 +#define ESC_SETLINESTYLE3 16 +#define ESC_SETLINESTYLE4 17 +#define ESC_SETLINEWIDTH0 18 +#define ESC_SETLINEWIDTH1 19 +#define ESC_SETLINEWIDTH2 20 + +ESC_SETTEXTMODE, 015, 000, 000, 000, 000, 000, 0, +ESC_ENQUIRE, ENQ, 000, 000, 000, 000, 000, 0, +ESC_READCURSOR, SUB, 000, 000, 000, 000, 000, 0, +ESC_CLEARSCREEN, 014, 000, 000, 000, 000, 000, 0, +ESC_SETCURSOR, '/', 'f', 000, 000, 000, 000, 0, +ESC_SETCHARSIZE0, '0', 000, 000, 000, 000, 000, 0, +ESC_SETCHARSIZE1, '1', 000, 000, 000, 000, 000, 0, +ESC_SETCHARSIZE2, '2', 000, 000, 000, 000, 000, 0, +ESC_SETCHARSIZE3, '3', 000, 000, 000, 000, 000, 0, +ESC_SETDATALEVEL0, '/', '0', 'd', 000, 000, 000, 0, +ESC_SETDATALEVEL1, '/', '1', 'd', 000, 000, 000, 0, +ESC_SETDATALEVEL2, '/', '2', 'd', 000, 000, 000, 0, +ESC_SETLINESTYLE0, '`', 000, 000, 000, 000, 000, 0, +ESC_SETLINESTYLE1, 'a', 000, 000, 000, 000, 000, 0, +ESC_SETLINESTYLE2, 'b', 000, 000, 000, 000, 000, 0, +ESC_SETLINESTYLE3, 'c', 000, 000, 000, 000, 000, 0, +ESC_SETLINESTYLE4, 'd', 000, 000, 000, 000, 000, 0, +ESC_SETLINEWIDTH0, '/', '0', 'w', 000, 000, 000, 0, +ESC_SETLINEWIDTH1, '/', '1', 'w', 000, 000, 000, 0, +ESC_SETLINEWIDTH2, '/', '2', 'w', 000, 000, 000, 0, diff --git a/unix/sun/gterm.h b/unix/sun/gterm.h new file mode 100644 index 00000000..121587ae --- /dev/null +++ b/unix/sun/gterm.h @@ -0,0 +1,18 @@ +/* GTERM.H -- Global definitions for GTERM. + */ +#define CURSOR_OFF 3 /* turn cursor off entirely */ +#define CURSOR_ON 4 /* turn it back on */ + +#define GRAPHICS_OFF 0 +#define GRAPHICS_ON 1 +#define GRAPHICS_DISCARD 2 + + +struct fonttab { /* Gterm font descriptor. */ + short pointsize; + char ch_xsize, ch_ysize; + short win_xsize, win_ysize; + struct pixfont *pixfont; + char *path; + char *label; +}; diff --git a/unix/sun/gterm.icon b/unix/sun/gterm.icon new file mode 100644 index 00000000..05c634a6 --- /dev/null +++ b/unix/sun/gterm.icon @@ -0,0 +1,34 @@ +/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16 + */ + 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xF3FF,0xFFFF,0xFFFF, + 0xFFFF,0xF0FF,0xFFFF,0xFFFF,0xFFFF,0xF03F,0xFFFF,0xFFFF, + 0xFFFF,0xE01F,0xFFFF,0xFFFF,0xFFFF,0xE00F,0xFFFF,0xFFFF, + 0xFFFF,0xE007,0xFFFF,0xFFFF,0xFFFF,0xE003,0xFFFF,0xFFFF, + 0xFFFF,0xE103,0xFFFF,0xFFFF,0xFFFF,0xE101,0xFFFF,0xFFFF, + 0xFFFF,0xC181,0x3FFF,0xFFFF,0xFFFF,0xC181,0x9FFF,0xFFFF, + 0xFFFF,0xC1C1,0x8FFF,0xFFFF,0xFFFF,0xC1C1,0x87FF,0xFF8F, + 0xFFFF,0xC1C0,0x8307,0xFE1F,0xFFFE,0xC1E0,0x8180,0x001F, + 0xFFFC,0xC1E0,0xC0C0,0x00FF,0xFFF8,0x81E0,0xC0C0,0x3FFF, + 0xFFE0,0x81E0,0xC060,0x1DFF,0xFE01,0x81E0,0xC030,0x11FF, + 0xF001,0x81E0,0xC038,0x03FF,0x8001,0x81C0,0xC018,0x07FF, + 0x8001,0x8180,0xC00C,0x03FF,0x8001,0x0100,0xC006,0x03FF, + 0xFC01,0x0001,0xC007,0x01FF,0xFF81,0x0001,0xC083,0x03FF, + 0xFFE3,0x0007,0xC0C1,0x87FF,0xFFF3,0x0007,0xC060,0xDFFF, + 0xFFF3,0x0007,0xC030,0xFFFF,0xFFFB,0x0003,0xC030,0x7FFF, + 0xFFFE,0x0003,0xC018,0x3FFF,0xFFFE,0x0001,0xC018,0x1FFF, + 0xFFFE,0x0001,0xC00C,0x1FFF,0xFFFE,0x0000,0xC00C,0x0FFF, + 0xFFFE,0x0000,0xC00E,0x0FFF,0xFFFE,0x0000,0x4006,0x07FF, + 0xFFFC,0x0000,0xC006,0x07FF,0xFFFC,0x0001,0xC007,0x03FF, + 0xFFFC,0x0003,0xE007,0x03FF,0xFFFC,0x0187,0xF007,0x01FF, + 0xFFF8,0x01EF,0xF807,0x01FF,0xFFF8,0x01FF,0xF807,0x80FF, + 0xFFF0,0x01FF,0xFC07,0x80FF,0xFFF0,0x01FF,0xFF07,0x80FF, + 0xFFF0,0x01FF,0xFF81,0x807F,0xFFF0,0x03FF,0xFFC0,0x007F, + 0xFFF0,0x07FF,0xFFE6,0x007F,0xFFE0,0x07FF,0xFFF7,0x803F, + 0xFFE0,0x0FFF,0xFFFF,0x803F,0xFFE0,0x1FFF,0xFFFF,0x801F, + 0xFFE0,0x3FFF,0xFFFF,0x800F,0xFFC0,0x3FFF,0xFFFF,0x800F, + 0xFFC0,0x7FFF,0xFFFF,0x800F,0xFFC0,0xFFFF,0xFFFF,0xE007, + 0xFFC1,0x8000,0x0000,0xF007,0xFF81,0x8040,0x0000,0xF803, + 0xFF83,0x9CF1,0x8A34,0xFC03,0xFF87,0xA442,0x4D2A,0xFF03, + 0xFF8F,0xA443,0x882A,0xFF81,0xFF9F,0x9C42,0x082A,0xFFE1, + 0xFF1F,0x8431,0xC82A,0xFFF1,0xFF3F,0xB800,0x0000,0xFFF9, + 0xFF7F,0x8000,0x0000,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF diff --git a/unix/sun/gterm.icon.OLD b/unix/sun/gterm.icon.OLD new file mode 100644 index 00000000..6a40db4b --- /dev/null +++ b/unix/sun/gterm.icon.OLD @@ -0,0 +1,34 @@ +/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16 + */ + 0x8888,0x8888,0x8888,0x8888,0x8888,0x889F,0xFC88,0x8888, + 0x2222,0x23FF,0xFFE2,0x2222,0x2222,0x27FF,0xFFF2,0x2222, + 0x8888,0xBFFF,0xFFFE,0x8888,0x8888,0xFFFF,0xFFFF,0x8888, + 0x2223,0xFFFF,0xFFFF,0xE222,0x2223,0xFFF0,0x07FF,0xE222, + 0x888F,0xFF00,0x007F,0xF888,0x888F,0xFC00,0x001F,0xF888, + 0x223F,0xF000,0x0007,0xFE22,0x223F,0xE000,0x0003,0xFE22, + 0x88FF,0x8000,0x0000,0xFF88,0x88FF,0x0000,0x0000,0x7F88, + 0x23FE,0x0000,0x0000,0x3FE2,0x23FC,0x0000,0x0000,0x1FE2, + 0x8BF8,0x0000,0x0000,0x0FE8,0x8FF8,0x0000,0x0000,0x0FF8, + 0x27F0,0x0000,0x0000,0x07F2,0x27E0,0x0000,0x0000,0x03F2, + 0x8FE0,0x0000,0x0000,0x03F8,0x8FC0,0x0000,0x0000,0x01F8, + 0x3FC0,0x0000,0x0000,0x01FE,0x3F80,0x0000,0x0000,0x00FE, + 0x9F80,0x0000,0x0000,0x00FC,0x9F83,0xE3F0,0x1C3F,0xC0FC, + 0x3F81,0xC1D8,0x1C1C,0xC0FE,0x3F01,0xC1DC,0x1C1C,0x007E, + 0xBF01,0xC1DC,0x1C1C,0x007E,0xBF01,0xC1D8,0x3E1F,0x007E, + 0x3F01,0xC1F0,0x3E1F,0x007E,0x3F01,0xC1F0,0x3E1F,0x007E, + 0xBF01,0xC1F8,0x3E1C,0x007E,0xBF01,0xC1F8,0x671C,0x007E, + 0x3F01,0xC1DE,0x671C,0x007E,0x3F03,0xE3EE,0xFFBE,0x007E, + 0xBF80,0x0000,0x0000,0x00FE,0x9F80,0x0000,0x0000,0x00FC, + 0x3F80,0x0000,0x0000,0x00FE,0x3F80,0x0000,0x0000,0x00FE, + 0x9FC0,0x0000,0x0000,0x01FC,0x8FC0,0x0000,0x0000,0x01F8, + 0x2FE0,0x0000,0x0000,0x03FA,0x27E0,0x0000,0x0000,0x03F2, + 0x8FF0,0x0000,0x0000,0x07F8,0x8FF8,0x0000,0x0000,0x0FF8, + 0x23F8,0x0000,0x0000,0x0FE2,0x23FC,0x0000,0x0000,0x1FE2, + 0x89FE,0x0000,0x0000,0x3FC8,0x88FF,0x0000,0x0000,0x7F88, + 0x227F,0x8000,0x0000,0xFF22,0x223F,0xE000,0x0003,0xFE22, + 0x889F,0xF000,0x0007,0xFC88,0x888F,0xFC00,0x001F,0xF888, + 0x2227,0xFF00,0x007F,0xF222,0x2223,0xFFF0,0x07FF,0xE222, + 0x8889,0xFFFF,0xFFFF,0xC888,0x8888,0xFFFF,0xFFFF,0x8888, + 0x2222,0x3FFF,0xFFFE,0x2222,0x2222,0x27FF,0xFFF2,0x2222, + 0x8888,0x89FF,0xFFC8,0x8888,0x8888,0x889F,0xFC88,0x8888, + 0x2222,0x2222,0x2222,0x2222,0x2222,0x2222,0x2222,0x2222 diff --git a/unix/sun/gterm.man b/unix/sun/gterm.man new file mode 100644 index 00000000..fd09b5f4 --- /dev/null +++ b/unix/sun/gterm.man @@ -0,0 +1,784 @@ +.\" @(#)gterm.1 1.1 28-Jul-87 DCT +.TH GTERM 1 "31 December 1987" +.SH NAME +gterm \- virtual graphics terminal for the SunView environment +.SH SYNOPSIS +.B gterm +[ +.B \-C +] +[ +.B \-T +] +[ +.B \-B +\fIboldstyle\fR +] +[ +.B \-I +\fIcommand\fR +] +.if n .ti +0.5i +[ +.B \-ignore +] +[ +\fIttyargs\fR +] +.ti +.5i +[ +.B \-G +[ +.B \-Gopen +\fR(\fP\fBnoaction\fR | \fBshow\fR | \fBexpose\fR\fR)\fP +] +.if n .ti +1.0i +[ +.B \-Gclose +\fR(\fP\fBnoaction\fR | \fBblank\fR | \fBhide\fR\fR)\fP +] +.ne 4 +.ti +1.0i +[ +.B \-\fR[\fPno\fR]\fPpause +] +[ +.B \-\fR[\fPno\fR]\fPretain +] +[ +.B \-\fR[\fPno\fR]\fPclip +] +.if n .ti +1.0i +[ +.B \-\fR[\fPno\fR]\fPreverse +] +[ +.B \-color +| +.B \-mono +] +.ti +1.0i +[ +.B \-ginterm +\fR[\fIchar \fR[\fIchar\fR]] +] +[ +\fIgioargs\fR +] +] +.ti +.5i +[ +\fIprogram\fR +[ +\fIargs\fR +] +] +.SH GETTING STARTED +\fIgterm\fR is a virtual graphics terminal implemented as a set of windows +running within the SunView environment. The graphics terminal consists of +two primary windows, the main \fBtext window\fR and a \fBgraphics subwindow\fR. +The text window is a standard SunView TTY subwindow, identical to that used +in \fIshelltool\fR. The graphics window is a Tektronix 4012 compatible +graphics window. The two windows may be moved and sized independently. +Terminal i/o may be directed to either window, but to only +one window at a time. When i/o is directed to the text window the terminal +is said to be in \fBtext mode\fR, and when i/o is directed to the graphics +window the terminal is said to be in \fBgraphics mode\fR. Mode switching +may be performed either manually or under program control. +\fIgterm\fR is upwards compatible with \fIshelltool\fR. +.SH OPTIONS +.TP +.B \-C +Redirect system console output to this instance of \fIgterm\fR. +.TP +.B \-T +Run \fIgterm\fR with the graphics plane disabled. Any graphics commands +embedded in the input data stream will appear as printable characters in the +text window. This option is useful when using \fIgterm\fR for a nongraphics +session over a noisy line, or when debugging a graphics program and switching +back and forth between text and graphics mode would interfere with the +operation of the debugger. +.TP +\fB\-B\fP \fIboldstyle\fR +Sets the \fIboldstyle\fR +(rendering of boldface type in the text window) +for this instance of \fIgterm\fR. +The choices are the same as for any tool based +on a SunView tty subwindow: see \fIshelltool\fR(1) for a description of the +\fIboldstyle\fR options. +.TP +\fB\-I\fP \fIcommand\fR +Input the given command to the program or shell run in the \fIgterm\fR window, +as if it had been typed into the window. Spaces in the command must be +escaped, or the command string must be quoted. +.TP +.B \-ignore +Ignore the suspend control characters (SIGTSTP), \fIif\fR the process being +run in the \fIgterm\fR window is not the default SHELL process. +If this option is in effect, typing one of the \fIstty\fR suspend-process +control characters \fBsusp\fR or \fBdsusp\fR while the terminal is not in raw +mode will cause the character to be echoed in the text window, but to be +otherwise ignored. This may be desirable if the process being run in the +\fIgterm\fR window is not capable of restarting itself after it has been +suspended (see also the \fBcontinue\fR frame menu option). +.TP +\fIttyargs\fR +\fIgterm\fR also takes generic tool arguments; see \fIsuntools\fR(1) for a +list of these arguments. The \fIttyargs\fR generic tool arguments affect +only the text window. +.TP +.B \-G +Generic tool arguments preceding this optional placeholder switch affect only +the text window; those following the switch affect only the graphics window. +.TP +\fB-Gopen \fR(\fPnoaction \fR|\fP show \fR|\fP expose\fR)\fP +Specifies the action to be taken when graphics mode is entered, i.e., when +terminal i/o is redirected from the text window to the graphics window. +\fBnoaction\fR means do nothing which visibly affects the screen. +\fBshow\fR means display the graphics frame if it is not already visible on +the screen, i.e., because the graphics window has been closed. +\fBexpose\fR means move the graphics window, if already displayed, to the +top of the stack of open windows. +.TP +\fB-Gclose \fR(\fPnoaction \fR|\fP blank \fR|\fP hide\fR)\fP +Specifies the action to be taken when graphics mode is exited, restoring +terminal i/o to the text window. +\fBnoaction\fR means do nothing which visibly affects the screen. +\fBblank\fR means close the graphics subwindow, causing the window to +disappear from the screen (the closed window can be redisplayed at any time +provided the contents are \fIretained\fR). +\fBhide\fR means move the graphics window to the bottom of the stack of +open windows. +.TP +\fB\-\fR[\fPno\fR]\fPpause +Pause before closing the graphics window and returning to text mode, +after opening the graphics frame to display a plot noninteractively +(no cursor reads). If \fB\-nopause\fR is specified and the \fB\-Gclose\fR +option is \fBblank\fR, a newly plotted graph will disappear immediately after +the plotting operation is completed, assuming no blocking operation such as +a cursor read occurs while in graphics mode. If \fB\-pause\fR is specified +\fIgterm\fR will detect this condition and pause for a keystroke to be typed +before exiting graphics mode. +.TP +\fB\-\fR[\fPno\fR]\fPretain +Specifies whether or not the contents of the graphics frame are to be retained. +If \fB\-noretain\fR is specified plotting will be somewhat faster, but any +window event which affects the region of the workstation screen occupied by +the graphics frame will cause the plot to be lost. +.TP +\fB\-\fR[\fPno\fR]\fPclip +Specifies whether or not clipping of graphics vectors is to be performed. +If \fB\-noclip\fR is specified plotting will be somewhat faster, but vectors +may be drawn outside the graphics window if the screen changes while a graph +is being drawn. +.TP +\fB\-\fR[\fPno\fR]\fPreverse +Specifies whether the graphics frame is to be displayed in normal or reverse +video. What constitutes normal video depends upon whether color or monochrome +is specified, and upon what has been specified for the foreground and +background colors. Reverse video swaps the foreground and background colors +within the graphics window. +.TP +.B \-color +Display the graphics frame in two colors, if \fIgterm\fR is run on a color +workstation. +.TP +.B \-mono +Display the graphics frame in monochrome, using the foreground and background +colors specified when \fIsuntools\fR(1) was started. +.TP +.B \-ginterm \fR[\fIchar \fR[\fIchar\fR]] +Set the GIN terminator character or characters (used to delimit the value +returned for a cursor read) to the indicated octal values \fIchar\fR. +If a \fIchar\fR value is omitted the corresponding GIN mode terminator will +be omitted when a cursor value is returned. For example, "\-ginterm" causes +both GIN delimiter characters to be omitted, and "\-ginterm 015" causes the +single GIN terminator character CR (carriage return) to be transmitted. +.TP +\fIgioargs\fR +\fIgterm\fR also takes generic tool arguments; see \fIsuntools\fR(1) for a +list of these arguments. The \fIgioargs\fR generic tool arguments affect +only the graphics subwindow, and are recognized only after the \fB\-G\fR +placeholder argument. +.TP +[\fIprogram\fP [\fIargs\fP]] +If a \fIprogram\fR argument is present, the named program is run in the +\fIgterm\fR window without spawning an intermediate shell. +If no \fIprogram\fR is specified, +\fIgterm\fR runs the shell specified by your \fLSHELL\fR environment +variable. If this environment variable is not defined, \fIgterm\fR runs +\fB/bin/sh\fR. +.LP +Minimum match abbreviations are permitted for all \fIgterm\fR arguments except +the generic tool arguments, which have two character aliases. Use of the full +names is however recommended, as the number of characters required for minimum +matching a specific argument may change in a future release of \fIgterm\fR +when new command line arguments are added. +.if t .sp 0.08i +.SH DESCRIPTION +.SS Virtual Graphics Terminal +.LP +\fIgterm\fR is a virtual graphics terminal implemented as a set of windows +running within the SunView environment. The terminal consists of two primary +windows, a \fBtext window\fR and a \fBgraphics window\fR, and several special +purpose subwindows, the most important of which is the \fBsetup panel\fR, +used to dynamically change \fIgterm\fR options at runtime, or to reset the +terminal to a known state. The virtual terminal is interfaced to applications +programs via the UNIX pseudoterminal or \fIpty\fR(4) interface, providing an +applications interface identical to that provided for ordinary terminals, +allowing applications running either on the local machine or on a remote +node communicating via a network interface (\fItelnet\fR, \fIrlogin\fR, +modem etc.) to communicate transparently with the \fIgterm\fR virtual terminal. +.if t .sp 0.08i +.SS Text Window +.LP +The text window is a standard SunView TTY subwindow, as used in +\fIshelltool\fR, \fIgfxtool\fR, and so on. Documentation for tty subwindows, +including both user documentation and a description of the special escape +sequences recognized by tty subwindows, is given in \fIshelltool\fR(1). +In particular, note that a \fB.ttyswrc\fR file may be placed in one's login +directory to set tty subwindow parameters, and to map function keys to control +sequences to be sent either to the tty subwindow or to the program running in +the tty subwindow. The \fBselection service\fR can be useful for passing +text to programs via the mouse instead of the keyboard, and numerous terminal +\fBescape sequences\fR are defined for resizing the text window, setting the +frame label, and so on. +.if t .sp 0.08i +.SS Graphics Window +The graphics window emulates a Tektronix 4012 terminal with minor differences, +e.g., the screen size is 35x80 rather than 35x75, and some significant +extensions, e.g., graphics and text can be selectively erased, and support +is provided for a \fBstatus line\fR at the bottom of the screen, in which text +can be dynamically read and written without affecting the contents of the +graphics plane. Although nonstandard, these features are very useful when +designing interactive user interfaces, and they can be emulated on most +modern graphics terminals (hence programs which use these features need not +be device dependent). +.LP +The position and size of the graphics window may be set at startup time via +the generic tool arguments \fIgioargs\fR. A number of preprogrammed sizes +may also be selected via the setup panel at runtime, or the mouse may be used +to directly resize the window to produce a window of any size and aspect ratio. +The standard graphics window sizes range from very small to the full screen +and all share the same standard landscape mode aspect ratio; users should note +that manually adjusting the window size usually results in a window with a +nonstandard aspect ratio, which may cause graphics programs which assume the +standard aspect ratio to misbehave, producing oddly shaped objects, or poorly +centered text strings. +.LP +\fIgterm\fR will automatically detect any changes in the size of the graphics +window, adjusting the transformation from 4012 coordinates (780x1024) to +screen coordinates so that subsequent graphics and text will be drawn at the +correct relative position within the window. The best text font for the new +window size is also selected; if the window is of an arbitrary size it will +not in general be possible to select a font which provides exactly 35x80 +characters on the screen without overlap, since there are only a limited number +of fixed size fonts to choose from. If the window is especially wide and +short text lines may overlap vertically. After resizing the graphics window, +the previously displayed graph \fImust\fR be redrawn under program control to +adjust the graph to fit the new window. +.LP +By default, the graphics window overlaps the text window, with eight or ten +characters of text visible to the left of the graphics window. If the graphics +window is left in its default position and the text window is repositioned on +the workstation screen, the graphics window will "track" the text window, +i.e., retain its position relative to the text window (this is desirable when +there are multiple instances of \fIgterm\fR in use at one time to avoid losing +track of which graphics frame goes with which text window). If the graphics +window is manually repositioned, however, then thereafter the positions of +the two windows are completely independent. +.LP +Although the graphics window is normally used only for graphics (plotting), +one should not forget that the graphics window emulates an (80 column wide) +Tektronix 4012 terminal, and hence may be used as a terminal for ordinary +text i/o, as well as for graphics. The TTY subwindow will normally be +superior for terminal graphics, but the extra page of text and the larger, +brighter font typically used in the graphics window may occasionally be useful +for some applications. Text i/o may easily be switched back and forth between +the text and graphics windows via the function keys described below, +transparently to most applications software. +.if t .sp 0.08i +.SS Active Window +.LP +At any one time, terminal output is always directed to either the text window +or the graphics window, but never to both at the same time. When output is +directed to the text window the terminal is said to be in \fBtext mode\fR, +and when output is directed to the graphics window the terminal is said to +be in \fBgraphics mode\fR, although either text or graphics may be written +into the graphics plane. Mode switching is normally in response to control +codes embedded in the input data stream from the applications program being +run, but keyboard function keys may be used to manually perform mode switching +if desired. +.LP +Keyboard \fIinput\fR may be directed to either window at any time, regardless +of which window is currently active, i.e., text may be typed into one window +but echoed in the other window. This can be confusing if the window in which +text is echoed is not currently displayed; one types and nothing seems to be +happening, but in fact commands are being input and executed normally. +For example, if the \fB\-Gclose\fR option is set to \fBnoaction\fR and the +graphics window is adjusted to fill the full screen, then when graphics mode +is exited terminal output will be directed to the text window, but the text +window will be covered by the graphics window, and subsequent commands and +textual output will not be visible without manually redisplaying the text +window (or undisplaying the graphics window) with a function key. +.if t .sp 0.08i +.SS The Frame Menu +.LP +\fIgterm\fR uses a special frame menu which may be called up by the mouse +at any time, by placing the cursor on the border of the \fItext window\fR and +holding down the right mouse button. +The items in the \fIgterm\fR frame menu are as follows: +.RS +.IP "\fBFrame\fP" 15 +Access the standard SunView frame menu. +.IP "\fBSetup\fP" +Display the setup panel. +.IP "\fBContinue\fP" +Send the SIGCONT signal to the process group attached to the \fIgterm\fR +window, e.g., after accidentally suspending a process which cannot otherwise +restart itself. See also the \fB\-ignore\fR command line option. +.IP "\fBShow graph\fP" +Display the graphics window. +.IP "\fBTextcopy\fP" +Make a hardcopy of the text window. +.IP "\fBGraphcopy\fP" +Make a hardcopy of the graphics window. +(IRAF users should use the cursor mode \fIsnap\fR function instead). +.IP "\fBScreencopy\fP" +Make a hardcopy of the full screen. +.RE +.LP +The textcopy, graphcopy, and screencopy selections are all entry points to the +general screen capture utility, discussed in the next section. +.if t .sp 0.08i +.SS Hardcopy Output +.LP +The hardcopy functions produce a "what you see is what you get" bitmap of the +rectangular region of the screen occupied by the indicated object of interest. +If the region of interest is partially covered by another window, then the +hardcopy will be a picture of a partially covered window. +If the window is displayed in reverse video, the hardcopy will also be +rendered in reverse video. +.LP +The screen capture software reads out the full memory of the workstation in +the region of interest, and in the case of a color workstation, processes the +screen pixels through the colortable to produce an image corresponding to what +appears on the screen. No full color output options +are currently provided, hence the average of the red, green, and blue color +values is next computed. If a bitmap output image is desired a simple +thresholding algorithm is used to produce the final bitmap image, +otherwise a greyscale image is produced. If rasterfile output +is being generated, the raw pixel values and RGB color table entries are saved +directly in the rasterfile, rather than applying the tables in software to +produce a monochrome or bitmap image. +.LP +Two output options are currently provided, i.e., \fBPostscript\fR output +suitable for output directly to a laser writer to produce the final graphics +hardcopy, or \fBSun rasterfile\fR output. The default action is to output a +Postscript program to the device "lw", e.g., the Apple Laserwriter +(any 300 dpi Postscript device should do). +These defaults may be changed by defining the following environment variables: +.IP R_RASTERFILE +If this variable is defined a Sun rasterfile will be generated, otherwise a +Postscript plotfile is generated. The string value of the variable is a +\fIprintf\fR style format string to be used to generate the filename of +the rasterfile. If multiple rasterfiles are to be generated, the format +string may contain a decimal integer field (e.g., "\fLframe.%d\fR") to be +replaced by the \fIfile number\fR of the current rasterfile. The first file +generated will be number zero, with the file number being incremented once +for every rasterfile produced. If Postscript plotfile output is desired, +the plotfile will be a uniquely named temporary file in \fB/tmp\fR. +.IP R_DISPOSE +The string value of this variable is a \fIprintf\fR style format string with +one string valued subfield to be replaced by the plotfile or rasterfile name, +to be used to generate the command used to dispose of the output file. +If this variable is not defined and the output file is a Postscript plotfile, +the default format string \fL"lpr -Plw -r -s %s"\fR will be used. +If the variable is not defined and the output file is a rasterfile, +no action is taken. It is the responsibility of the dispose command to +delete the output file. +.LP +It should only take several seconds to capture the screen and produce the +output rasterfile or queue the Postscript job to the printer. The screen +is flashed to indicated when the operation has completed. The Postscript +processing time may take up to several minutes (of laserwriter time) in the +worst case, i.e., a hardcopy of the full workstation screen. +.if t .sp 0.08i +.SS The Setup Panel +.LP +The setup panel is used to dynamically change terminal options while the +terminal is in use. In general, nearly any terminal option which can be +set on the command line when \fBgterm\fR is started can also be set via the +setup panel, and vice versa. The setup panel can also be used to reset +the terminal to the startup or "power on" state. +The setup panel may be called up at any time via the frame menu; it is normally +closed after the desired setup action has been performed. By default the setup +panel is located within the text window, but it may be moved anywhere else on +the workstation screen if desired. +.LP +There are two types of items in the setup panel: multiple choice options and +"push buttons". To see what the choices are in a multiple choice option, +position the mouse to the area where the current choice is displayed and +depress the right mouse button. At this point a selection may be made by +moving the mouse to the desired selection and releasing the mouse button. +Alternatively, the left mouse button may be used to cycle through the choices. +To perform the action indicated on a push button, place the mouse cursor on +the button and press the left mouse button. +.LP +The multiple choice options in the setup panel are the following: +.IP "\fBGraphics plane" +These options determine what the terminal does when graphics data and +control instructions are encountered in the input stream. +\fBDisable\fR means disable the graphics plane, causing the terminal to +output graphics control codes and data as printable characters +in the text window. +\fBEnable\fR means enable the graphics plane for normal mixed text and +graphics operation. +\fBDiscard Graphics Data\fR means discard all graphics data, effectively +disabling the graphics plane. +.IP "\fBOpen workstation action\fR" +These options determine the action taken by the terminal when graphics mode +is entered. Some visible action is generally desirable to render the graphics +window fully visible, and to indicate that a mode switch has occurred. +\fBNo action\fR means do nothing which visibly affects the workstation. +\fBShow graphics\fR means open the graphics window, e.g., if the graphics +window is to be closed (not displayed) when the terminal is in text mode. +\fBExpose graphics\fR means move the graphics window to the top of the stack +of open windows, displaying any portions of the graphics window which may have +been covered by other windows (such as the text window). +.IP "\\fBClose workstation action\\fR" +These options determine the action taken by the terminal when graphics mode +is exited, returning the terminal to text mode. +\fBNo action\fR means do nothing. +\fBBlank graphics\fR means close the graphics window, i.e., remove the window +from the screen. +\fBHide graphics\fR means move the graphics window to the bottom of the stack +of open windows, allowing any overlapping windows to cover the graphics window. +.IP "\\fBPause on close workstation\\fR" +This boolean option determines whether or not the terminal displays the +\fBpause panel\fR, waiting for a key to be typed, before exiting graphics +mode following a noninteractive graphics session (no cursor input). +.IP "\\fBRetain graphics frame\\fR" +This boolean option determines whether or not the contents of the graphics +window are \fIretained\fR. Graphics drawing will be somewhat faster if the +graphics plane is not retained, but almost any event which affects the region +of the screen occupied by the graphics window will cause the contents +of an unretained window to be lost. +.IP "\\fBClip graphics\\fR" +This boolean option determines whether or not graphics vectors are clipped +to the boundaries of the visible portions of the graphics window. Graphics +drawing will be somewhat faster if clipping is disabled, but +vectors may be drawn in nearby, unrelated windows, +especially if the graphics window is partially covered by other windows. +.IP "\\fBGraphics screen type\\fR" +This option determines whether the graphics plane is to be displayed in color +or monochrome on a color workstation. If \fBmono\fR is selected the foreground +and background colors specified when \fIsuntools\fR was started are used. +If \fBcolor\fR is specified graphics will be rendered in color, with the +colors used being specified by the \fB\-Wb\fR and \fB\-Wf\fR generic tool +arguments in \fIgioargs\fR. On a monochrome workstation the only option +displayed will be \fBmono only\fR, indicating that color is not available. +.IP "\\fBGraphics video\\fR" +This option specifies whether graphics are to be rendered in \fBnormal\fR or +\fBreverse\fR video. Specifying reverse video causes the foreground and +background colors of the graphics window to be reversed. +This option may not work on some monochrome workstations. +.IP "\fBGraphics font and screen sizes\fR" +This option is used to select at runtime the size of graphics window to be used. +The graphics window may be resized at any time, including while graphics is +being drawn or during a cursor read, but any displayed graphics should always +be redrawn following a window resize to ensure that the graph reflects the new +coordinate system. +The graphics window configurations currently available are listed below +in the form ``\fIpointsize\fR:[\fIwidth\fRx\fIheight\fR]'', +where \fIwidth\fR and \fIheight\fR are in pixels. The size of the full screen +is workstation dependent, the most common size currently being 1152x900. +The exact set of fonts and screen sizes may change in the future as new +fonts become available and workstations increase in resolution. +.if t .sp 0.05i +.ti +0.3i +10:[560x420] 12:[640x490] 14:[720x560] 16:[800x630] 18:[880x665] 24:fullscreen +.if t .sp 0.05i +All choices represent 35x80 windows with the standard landscape mode aspect +ratio. The size of the graphics window is the size in pixels of a character +of the fixed width font used, scaled by 35 vertically and by 80 horizontally. +Arbitrary sized windows may also be created by manually sizing the window +with the mouse, but this is bound to result in windows with a nonstandard +number of lines or columns of text, or a nonstandard aspect ratio. +.IP "\fBGIN mode terminators\fR" +Set the GIN (graphics or cursor mode input) terminator characters to the +indicated octal values. When a key is hit to terminate a cursor read, the +terminal transmits a 5 character cursor value sequence to the applications +program, following by one or two GIN mode terminator characters. +The required GIN mode terminator(s) will in general depend upon the +applications program being run. Some programs require no terminators, +others require a single CR (octal 015), and so on. +The default GIN mode terminator is a single CR. +.if t .sp 0.05i +To enter a new value, select the value box with the left mouse button, +rubout the old value, and type in the new value as a string, with zero, one, +or two octal values denoting the desired terminator characters, then hit +return to establish the new value. Entering a blank string disables both +terminators. +.LP +The following "push buttons" are also provided in the setup panel: +.RS +.IP \fBReset\fR 15 +Reset the terminal to the "power on" state, preserving the values of any +options set on the command line, but cancelling any options selected via +the setup panel. A \fBsetup reset\fR is indicated if the terminal does not +seem to be behaving correctly. Resetting the internal state of the terminal +has no effect on the operation of any applications program being run from +the terminal. +.IP \fBClear\fR +Clear the text window (the F9 function key performs the same function). +.IP \fBGclear\fR +Clear the graphics window, leaving the terminal in graphics mode +(the F8 function key performs the same function). +.IP "\fBShow graphics\fR" +Open (display) or close (undisplay) the graphics frame. The contents of the +graphics frame are not affected. +.IP \fBQuit\fR +Close the setup panel. +.RE +.LP +Closing and opening either the text or graphics frame has no effect on the +state of the terminal or on the applications program running within it, +even while a cursor read is in progress. +.if t .sp 0.08i +.SS Function Keys +.LP +The following function keys have special significance to \fIgterm\fR: +.RS +.IP F8 15 +In text mode, causes a switch to graphics mode. +When already in graphics mode, causes the graphics frame to be cleared. +.IP F9 +In graphics mode, causes a switch to text mode. +When already in text mode, causes the text frame to be cleared. +.RE +.LP +To momentarily view the graphics frame while in text mode, one can type F8 +followed by F9, without affecting the contents of either window. +Commands may be entered in either window, hence to direct the output of +a command to the graphics window, one could hit F8, execute the command, +and then hit F9 to return to the text window. The standard SunView L7 key, +used to close a window, is also detected by \fIgterm\fR, +hence closing the graphics +window with L7 while in graphics mode will automatically cause the terminal +to revert to text mode. +.LP +Manual control of the terminal mode is sometimes necessary when running +naive graphics programs in a \fIgterm\fR window. +When running a graphics program +which uses only standard 4012 instructions, it may be necessary to manually +put the terminal into graphics mode with the F8 function key before running the +program, or part of the program output may be "lost" (directed to the text +window and discarded). Similarly, naive programs will not return the terminal +to text mode after generating a plot, hence it will be necessary for the +user to hit the F9 key to return to text mode. +.LP +Additional function keys may be defined in the user \fB~/.ttyswrc\fR file. +For example, the function key definitions +.if t .sp 0.05i +.if n .sp +.RS +.nf +mapo R1 ^[[8;24;80t +mapo R2 ^[[8;34;80t +mapo R3 ^[[8;40;80t +.fi +.RE +.if t .sp 0.05i +.if n .sp +will program the R1, R2, and R3 function keys to set the size of the text +window to 24, 34, or 40 lines by 80 columns when the corresponding function +key is typed. These definitions are handy for rapidly resizing the text +window to one of the "standard" terminal sizes; this is especially useful +when executing programs remotely over the network, as most such programs +assume some standard size terminal screen. +.if t .sp 0.08i +.SS Mouse Buttons +.LP +The significance of the mouse buttons depends upon which window the mouse is +in, and upon whether or not the terminal is in GIN mode, i.e., in the process +of reading the graphics cursor. When the terminal is in text mode and the +mouse is in the text window, the mouse buttons are used only for the +\fBselection service\fR, as described in \fIshelltool\fR(1). +The functions of the mouse buttons while the mouse is in the graphics window +are outlined below. +.RS +.IP "Left button" 15 +Ignored except in GIN mode, when it may be aliased to a keyboard key and used +to terminate a cursor read. +.IP "Middle button" +Ignored except in GIN mode, when it may be aliased to a keyboard key and used +to terminate a cursor read. +.IP "Right button" +In GIN mode, may be aliased to a keyboard key and used to terminate a cursor +read. When not in GIN mode, causes the cursor crosshairs to be displayed +while the button is depressed. +.RE +.LP +The ability to \fBalias\fR mouse buttons to keyboard keys is a very important +one as it allows arbitrary graphics programs which are driven via an +interactive graphics cursor loop to be controlled completely from the mouse, +rather than having to position the mouse and then hit a key on the keyboard +to terminate each cursor read. For example, to alias \fIkey\fR to the left +mouse button, one would depress the control key and tap the left mouse button +twice, immediately after hitting \fIkey\fR to terminate a normal cursor read. +Thereafter, either \fIkey\fR or the left mouse button may be used equivalently +to terminate a cursor read. The alias remains in effect until the terminal is +\fIreset\fR or the alias is reassigned to a different key. +.if t .sp 0.08i +.SS The Terminal Emulator +.LP +The normal function of the terminal is to simultaneously listen for input +(program output) on the pseudoterminal file descriptor, while servicing +asynchronous keyboard and mouse events generated by the user. +The input data stream from the applications program consists of a mixture +of text and graphics data transmitted as an ASCII byte stream with no record +boundaries. Null bytes in the input data stream are ignored, and no programmed +delays are needed for proper terminal operation. As input data is received +asynchronously it is copied into a circular buffer and a synchronous event is +queued to call a routine which subsequently processes the input characters +onto the screen. If input data arrives faster than it can be processed onto +the screen \fB<ctrl/s>\fR is transmitted to the \fIpty\fR terminal driver, +followed by \fB<ctrl/q>\fR once the circular buffer empties. +Characters typed by the user are transmitted directly to the terminal driver, +which in normal operation will echo the characters back to the terminal as +ordinary data. +.LP +The initial state of the terminal is text mode. Transition to graphics mode +occurs when the GS character is encountered in the input data stream. +Transition back to text mode occurs when the CAN character is encountered in +the input stream. While text mode is in effect all input is passed on to the +TTY subwindow; while graphics mode is in effect all input is passed on to the +graphics subwindow. The behavior of the ANSI standard TTY subwindow is +documented elsewhere (e.g., \fIshelltool\fR(1), \fIcons\fR(4s), and Chapter 10 +of the \fISunView Programmer's Guide\fR) hence will not be discussed further +here. Likewise, the basic Tektronix 4012 protocol is a well known standard +and need not be documented in detail here. +.LP +The control codes and escape sequences recognized by the \fIgterm\fR graphics +window are summarized below. Sequences marked with a \(**\(** at the right +are nonstandard extensions, although all except the status line feature are +fairly common extensions. +.if t .sp 0.05i +.ta +0.5i +1.5i +3.5i +.nf + GS (035) \fBopen workstation\fR, start normal vector drawing sequence + CAN (030) \fBclose workstation\fR ** + FS (034) start pointmode vector + US (037) set alpha mode + CR (015) set alpha mode and execute carriage return + BEL (007) ring bell and/or flash screen +.if t .sp 0.05i + ESC CR set status line mode (ESC = 033) ** + ESC ENQ inquire graphics state and cursor position + ESC SUB initiate a cursor read (SUB = 032) + ESC FF clear screen, home alpha cursor (FF = 014) + ESC / f set cursor position to current drawing coordinates ** + ESC 0 set character size 0 + ESC 1 set character size 1 [not implemented] + ESC 2 set character size 2 [not implemented] + ESC 3 set character size 3 [not implemented] + ESC / 0 d set data level 0 (clear bits) ** + ESC / 1 d set data level 1 (set bits) ** + ESC / 2 d set data level 2 (toggle bits) ** + ESC ` set line style 0 (solid) + ESC a set line style 1 (dashed) + ESC b set line style 2 (dotted) + ESC c set line style 3 (dashdot) + ESC d set line style 4 (dash3dot) + ESC / 0 w set line width 0 (1 pixel) ** + ESC / 1 w set line width 1 (2 pixels) ** + ESC / 2 w set line width 2 (3 pixels) ** +.fi +.if t .sp 0.05i +.LP +Both text and vectors may be erased by setting the data level to 0 and +redrawing the objects to be erased. Erasing points which are common to more +than one object will cause gaps in other objects sharing the erased point. +.LP +Setting \fBstatus line\fR mode causes the region of the graphics frame +occupied by the status line to be saved in a memory pixrect, after which the +status line is cleared and the status line alpha cursor positioned to the +start of the line (the status line is a single 80 character line of text at +the bottom of the graphics window). While output is directed to the status +line, data characters are output in the status line as for a terminal. +BS and DEL behave as expected, allowing characters to be erased. +Lines longer than 80 characters are truncated at the right margin. +LF (newline) is treated the same as CR, causing the entire line to be erased, +and if multiple lines of text are rapidly written to the status line +they will scroll as on a one-line terminal. Status line mode is terminated +by any control character in the input data stream, e.g., GS, FS, CAN, ESC, +and so on. Note that terminating status line mode does not in itself erase +the status line, restoring the saved region of the graphics frame to the +screen; this is done by transmitting newline or CR to the terminal. +.if t .sp 0.08i +.SH SEE ALSO +suntools(1), shelltool(1), tektool(1), cmdtool(1), pty(4), cons(4s) +.br +\fISunView Programmer's Guide\fR, Chapter 10 \- TTY Subwindows +.br +\fIWindows and Window-Based Tools: Beginner's Guide\fR +.if t .sp 0.08i +.SH FILES +.LP +.nf +~/.ttyswrc +/usr/bin/suntools +/usr/lib/rootmenu +/usr/lib/fonts/fixedwidthfonts/* +$iraf/local/sun/gterm.c +.fi +.if t .sp 0.08i +.SH BUGS +.IP (1) +\fIgterm\fR is a complex program operating in an extremely dynamic environment. +The program has been thoroughly tested and is quite reliable, but it is +nonetheless possible for the program to get into peculiar states where it +does not behave as expected. Should this happen, a \fIsetup reset\fR should +restore the terminal to a known state. +.IP (2) +If more than 256 characters are input to a terminal emulator subwindow without +an intervening newline, the terminal emulator may hang (to demonstrate this, +hold any key down until the autorepeat generates sufficient characters). +If this occurs, display the tty subwindow menu and select the \fBflush input\fR +item to correct the problem. +.IP (3) +When using a terminal emulator to execute a program on a remote node via a +network interface (rlogin, telnet, etc.), and the remote program continuously +outputs a large amount of data, the terminal will occasionally hang up for +several seconds, after which normal output will resume. Typing any character +will cause output to resume immediately, but the character will later be +delivered to the remote program as normal input hence should be selected with +care (\fB<ctrl/q>\fR is always harmless). The origin of this bug is not clear, +but since all terminal emulators are equally affected, it must be something +in the terminal driver, or elsewhere in the SunOS kernel. +.IP (4) +The hardcopy functions assume a 1 or 8 bit frame buffer and will not work +properly on a Sun-3/110, 3/60, etc., unless the \fB\-8bit_color_only\fR option +is specified to \fIsuntools\fR [\fIfixed in Gterm V1.2]\fR. +.IP (5) +Reverse video does not work on a monochrome workstation as there is no +colortable and no way to exchange the foreground and background colortable +entries; try the \fB\-i\fR option to \fIsuntools\fR instead. +.IP (6) +\fIgterm\fR modifies the keyboard translation table entries for the arrow keys +while a cursor read is in progress, restoring the translation table entries +when done (this is necessary to allow the arrow keys to be used to terminate +cursor reads). If something should happen to \fIgterm\fR while it is waiting +for cursor input, it is possible that the arrow key translation table entries +may not be restored. If this should happen, executing \fBsetkeys reset\fR will +fix things. Note also that changes to the keyboard translation tables are +global, i.e., all windows are affected, hence while a cursor read is in +progress in a \figterm\fR window, the arrow keys may not be usable with a +program running in a different window. +.IP (7) +When plotting with clipping disabled there are cases where it is possible for +\fIgterm\fR to coredump with a segmentation violation, killing any interactive +subprocesses running within the terminal. +.SH AUTHOR +Doug Tody, National Optical Astronomy Observatories (NOAO), IRAF project. diff --git a/unix/sun/gtermio.c b/unix/sun/gtermio.c new file mode 100644 index 00000000..d0348de2 --- /dev/null +++ b/unix/sun/gtermio.c @@ -0,0 +1,1224 @@ +/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + */ + +#include <suntool/sunview.h> +#include <pixrect/pr_line.h> +#include <sys/ioctl.h> +#include <ctype.h> +#include <stdio.h> +#include "gterm.h" + +/* + * GTERMIO -- Graphics terminal i/o. This is the low level code which + * filters graphics output out of the pseudoterminal output stream and + * then processes the graphics instructions, drawing into the graphics + * pixwin. Graphics output from the pty is written into a circular + * buffer by a low level routine called when data is read from the pty + * by the ttysw code. A differed routine is called back by the notifier + * to process the data, writing graphics into the gio pixwin. The graphics + * data language implemented is tektronix standard plus extensions. + */ + +extern int clip_graphics; +extern int cursor_show; +extern int gio_canvas; +extern FILE *gt_logfp; +int gio_graphicsenabled = 0; /* switch text/graphics output */ +int gio_enabled = 1; /* enable graphics window */ + +/* Size limiting definitions. */ +#define SZ_GBUF 8192 /* max buffered graphics data */ +#define GB_MINSPACE 2048 /* XOFF when this much left */ +#define GB_BIGSPACE 3072 /* XON when this much available */ +#define MAX_PLPTS 4096 /* max points in a polyline */ +#define SZ_TXBUF 256 /* max chars in a polytext */ +#define MAX_TEXTCHARS 80 /* max chars in text line */ +#define SL_XOFFSET 0 /* x offset to status line */ +#define SL_YOFFSET 5 /* y offset to status line */ +#define MAX_QUOTA 512 /* limit for one proc. loop */ +#define WSOPEN_DELAY 100 /* delay at openws (msec) */ +#define WSCLOSE_DELAY 0 /* delay at closews (msec) */ +#define LOG_SYNCTIME 15 /* sync interval for logfile */ + +/* Magic numbers. */ +#define SET_BITS 0 /* draw vectors|points */ +#define CLEAR_BITS 1 /* erase vectors|points */ +#define TOGGLE_BITS 2 /* toggle data bits */ +#define COMMAND_MODE 0 /* initial state */ +#define ALPHA_MODE 1 /* tek-alpha character drawing */ +#define TEXT_MODE 2 /* output to status line */ +#define VECTOR_MODE 3 /* draw vectors or points */ +#define CURSOR_MODE 4 /* read crosshair cursor posn */ +#define BREAK_LINE (-2) /* special automargin code */ + +/* ASCII codes. */ +#define ENQ '\005' +#define BEL '\007' +#define CR '\015' +#define CAN '\030' +#define SUB '\032' +#define ESC '\033' +#define FS '\034' +#define GS '\035' +#define RS '\036' +#define US '\037' + +/* Pseudoterminal i/o. + */ +static int pty_fd; /* fd of pseudoterminal */ +static int pty_stop = 0; /* set when XOFF is set on pty */ + +/* The graphics data buffer, a circular buffer. + */ +static char g_buf[SZ_GBUF]; /* circular buffer */ +static char *g_top= &g_buf[SZ_GBUF];/* end of buffer + 1 */ +static char *g_ip = g_buf; /* input pointer */ +static char *g_op = g_buf; /* output pointer */ + +#define g_getc(c)\ + (g_ip==g_op ? -1 : ((c) = *g_ip++, g_ip >= g_top ? *(g_ip=g_buf):0)) +#define g_putc(c)\ + (*g_op++ = (c), ((g_op >= g_top) ? g_op = g_buf : g_op)) +#define g_ungetc(c)\ + (g_ip = ((g_ip==g_buf) ? g_top-1 : g_ip-1)) +#define g_spaceleft\ + (g_ip <= g_op ? (g_top - g_op + g_ip - g_buf) : (g_ip - g_op)) +#define g_havedata (g_ip != g_op) +#define g_mark(ip) ((ip)=g_ip) +#define g_reset(ip) (g_ip=(ip)) +#define g_equal(ip) ((ip)==g_ip) + +/* Polyline (polymarker) output-point buffer. + */ +static char pl_text[MAX_PLPTS]; /* encoded [x,y] coord data */ +static struct pr_pos pl_p[MAX_PLPTS]; /* polyline storage */ +static int pl_npts = 0; /* npoints in polyline */ +static int pl_op = 0; /* which char in coord pair */ +static int pl_linestyle = 0; /* dashline drawing style */ +static int pl_pointmode = 0; /* point or line mode */ + +static int ohiy=0; oloy=0; /* encoded current position */ +static int ohix=0; olox=0; + +static Pr_brush brush = { 1 }; +#define pl_linewidth brush.width /* vector drawing linewidth */ + +/* Graphics text variables. + */ +static struct fonttab *alpha_font; /* alpha mode font */ +static struct fonttab *text_font; /* text mode font */ +static char tx_buf[SZ_TXBUF+1]; /* polytext text buffer */ +static int tx_len = 0; /* nchars in buffer */ +static int tx_maxlines; /* nlines of text on a screen */ +static int tx_maxcols; /* ncols of text on a screen */ +static int tx_charheight; /* height of a char in pixels */ +static int tx_charwidth; /* width of a char in pixels */ +static int tx_charbase; /* topline to baseline distance */ +static int tx_leftmargin; /* where columns start */ +static int sl_x, sl_y; /* current pos. in status line */ +static int sl_xoff, sl_yoff; /* x,y offset of status line */ +static int sl_cwidth; /* status line char width */ +static int sl_cheight; /* status line char height */ +static int sl_cbase; /* topline to baseline distance */ +static int sl_width; /* status line rect width */ +static int sl_height; /* status line rect height */ +static int sl_rect_saved = 0; /* set after sl rect is saved */ +static struct pixrect *sl_pr=NULL; /* saved status line pixrect */ +static struct fonttab *chcur_font; /* character cursor font */ +static int chcur_x; /* character cursor xpos */ +static int chcur_y; /* character cursor ypos */ +static int chcur_on = 0; /* character cursor displayed? */ +static int chcur_skip = 0; /* used to skip cursor updates */ + +/* Miscellaneous variables. + */ +static struct pixwin *pw; /* graphics pixwin */ +static struct rect pw_r; /* full rect of the pixwin */ +static int cur_x, cur_y; /* current x,y position */ +static int win_xres, win_yres; /* size of graphics pixwin */ +static int tek_xres; /* X resolution of input data */ +static int tek_yres; /* Y resolution of input data */ +static int trailer1 = '\r'; /* trailer code, cursor value */ +static int trailer2 = -1; /* second trailer code (opt) */ +static int gio_mode=COMMAND_MODE; /* graphics drawing mode */ +static int gio_datalevel=SET_BITS; /* set, clear, or toggle bits */ +static int workstation_open = 0; /* have issued open workstation */ +static int wait_cursor = 0; /* waiting for cursor input */ +static int gio_delay = 0; /* programmed delay in progress */ + +int ev_ptyoutput(); +static Pr_texture *pl_texture(); +static Notify_value ev_gioprocessdata(); + +/* Macros to convert between tektronix and window coordinates. */ +#define X_TEK2WIN(x) ( ((x) * win_xres + tek_xres/2) / tek_xres) +#define Y_TEK2WIN(y) (win_yres - (((y) * win_yres + tek_yres/2) / tek_yres)) +#define X_WIN2TEK(x) ((( (x)) * tek_xres + win_xres/2) / win_xres) +#define Y_WIN2TEK(y) (((win_yres - (y)) * tek_yres + win_yres/2) / win_yres) + + +/* GIO_SETUP -- Called by the high level Gterm window management code to + * give the gtermio code the file descriptor of the pty and the pixwin of + * the graphics frame. + */ +gio_setup (fd, gio_pw) +int fd; /* fd of pty */ +struct pixwin *gio_pw; /* graphics pixwin */ +{ + pty_fd = fd; + pw = gio_pw; + + notify_read_post_monitor_fcn (pty_fd, ev_ptyoutput); + notify_set_event_func (ev_gioprocessdata, + ev_gioprocessdata, NOTIFY_SAFE); +} + + +/* GIO_HARDRESET -- Reset everything, including cancelling any cursor read + * that may be in progress. + */ +gio_hardreset (mc_xres, mc_yres, a_font, t_font) +int mc_xres, mc_yres; /* virtual x,y resolution */ +struct fonttab *a_font; /* alpha mode font */ +struct fonttab *t_font; /* text mode font */ +{ + gio_mode = COMMAND_MODE; + gio_graphicsenabled = 0; + workstation_open = 0; + wait_cursor = 0; + gio_delay = 0; + pty_stop = 0; + + ioctl (pty_fd, TIOCSTART, NULL); + gio_reset (mc_xres, mc_yres, a_font, t_font); +} + + +/* GIO_RESET -- Reset the state of the gtermio code. Should be called + * whenever any important data structures change, e.g., if the graphics + * frame is resized. + */ +gio_reset (mc_xres, mc_yres, a_font, t_font) +int mc_xres, mc_yres; /* virtual x,y resolution */ +struct fonttab *a_font; /* alpha mode font */ +struct fonttab *t_font; /* text mode font */ +{ + erase_cursor(); + chcur_skip = 0; + + tek_xres = mc_xres; + tek_yres = mc_yres; + alpha_font = a_font; + text_font = t_font; + + pw_get_region_rect (pw, &pw_r); + win_xres = pw_r.r_width; + win_yres = pw_r.r_height; + + tx_leftmargin = 0; + tx_charwidth = alpha_font->ch_xsize; + tx_charheight = alpha_font->ch_ysize; + tx_charbase = -alpha_font->pixfont->pf_char['0'].pc_home.y; + tx_maxlines = win_yres / tx_charheight; + tx_maxcols = win_yres / tx_charwidth; + tx_len = 0; + + sl_cwidth = text_font->ch_xsize; + sl_cheight = text_font->ch_ysize; + sl_cbase = -text_font->pixfont->pf_char['0'].pc_home.y; + sl_xoff = SL_XOFFSET; + sl_yoff = win_yres - SL_YOFFSET; + sl_x = sl_xoff; + sl_y = sl_yoff; + sl_width = win_xres - sl_xoff; + sl_height = sl_cheight; + + if (sl_pr != NULL) + pr_destroy (sl_pr); + sl_pr = mem_create (sl_width, sl_height, 1); + sl_rect_saved = 0; + + g_top = &g_buf[SZ_GBUF]; + g_ip = g_op = g_buf; + pl_npts = 0; + pl_op = 0; + pl_linestyle = 0; + pl_linewidth = 1; + pl_pointmode = 0; + ohiy = 0; oloy = 0; + ohix = 0; olox = 0; + + cur_x = tx_leftmargin; + cur_y = tx_charbase; +} + + +/* GIO_ENABLE -- Enable or disable the graphics window. If graphics is + * disabled, all i/o is directed to the text window. + */ +gio_enable (onoff) +int onoff; +{ + if ((gio_enabled = onoff) == GRAPHICS_OFF) + gio_graphicsenabled = 0; +} + + +/* GIO_SETGINMODETERM -- Set the GIN mode (cursor read) trailer codes, + * expressed as octal constants in the input string argument. + */ +gio_setginmodeterm (str) +char *str; +{ + register char *ip; + register int n; + + trailer1 = trailer2 = -1; + + for (ip=str; isspace(*ip); ip++) + ; + if (isdigit(*ip)) { + for (n=0; isdigit(*ip); ip++) + n = n * 8 + *ip - '0'; + trailer1 = n; + } + + while (*ip && isspace(*ip)) + ip++; + if (isdigit(*ip)) { + for (n=0; isdigit(*ip); ip++) + n = n * 8 + *ip - '0'; + trailer2 = n; + } +} + + +/* EV_PTYOUTPUT -- Process pty output packets. Output directed to the + * terminal (/dev/tty) by the applications program appears as read-pending + * events on the pty seen by the Gterm program. We let the TTY code monitor + * the pty and respond to read-pending events. The low level read primitive + * (notify_read) ultimately called to service a read request by TTY reads + * the data and then calls us to process the data packet. We extract any + * graphics output from the packet and append it to the gio buffer. If data + * is added to the gio buffer a gio-data-pending event is queued so that + * the graphics drawing code will be called to process the new data. The + * remaining data, or a null length packet if the packet contained only + * graphics data, is returned to TTY, completing the read. Sometime later + * the graphics drawing code will be called to process the data. + */ +ev_ptyoutput (ttybuf, nchars) +char *ttybuf; /* raw data on input, tty data on output */ +int nchars; /* nchars of raw data */ +{ + register char *itop = ttybuf + nchars; + register char *op, *ip = ttybuf, ch; + static unsigned long oldtime = 0; + + /* Copy to logfile if logging is enabled. */ + if (gt_logfp) { + fwrite (ttybuf, nchars, 1, gt_logfp); + if (time(0) - oldtime > LOG_SYNCTIME) { + /* Sync the logfile output every so often. */ + fflush (gt_logfp); + oldtime = time(0); + } + } + + if (gio_enabled == GRAPHICS_OFF || nchars <= 0) + return (nchars); + + /* If in text mode, make a quick scan for the GS character and return + * the entire data packet if GS is not seen. + */ + if (!gio_graphicsenabled) { + while (ip < itop && *ip != GS) + ip++; + if (ip >= itop) + return (nchars); + else { + gio_graphicsenabled++; + op = ip; + } + } else + op = ttybuf; + + /* Process rest of data in graphics mode. IP is pointing at the + * first char of graphics data, ITOP at the top of the buffer, + * and OP at the next tty output char. Filter out any NULs in + * the process of copying the data. + */ + while (ip < itop) + if (gio_graphicsenabled) { + while (ip < itop) + if ((ch = *ip++) == CAN) { + g_putc (ch); + gio_graphicsenabled = 0; + break; + } else if (ch) + g_putc (ch); + } else { + while (ip < itop) + if ((ch = *ip++) == GS) { + g_putc (ch); + gio_graphicsenabled = 1; + break; + } else if (ch) + *op++ = ch; + } + + /* If the gio buffer has reached the high-water mark and XOFF is + * not currently set, send XOFF to the terminal driver. + */ + if (g_spaceleft < GB_MINSPACE && !pty_stop) { + ioctl (pty_fd, TIOCSTOP, NULL); + pty_stop++; + } + + /* Post an event with the notifier to call the graphics drawing code + * back to process the new data. + */ + if (!gio_delay) + notify_post_event (ev_gioprocessdata, NULL, NOTIFY_SAFE); + + return (op - ttybuf); +} + + +/* EV_GIOPROCESSDATA -- Called to process graphics instructions and data from + * the gio buffer. This is the routine which actually draws lines and text + * in the graphics frame. May be called repeatedly to process any amount of + * data at a time. If there is a great amount of data to be processed the + * routine should return occasionally to allow the other GTERM event handlers + * to run (operation is not fully asynchronous). + * + * Graphics data is processed as a stream with no record boundaries, so that + * operation is not dependent on how data is buffered through the system. + * The graphics frame is a state machine which is by definition always in a + * legal state; garbage input causes garbage output, just like a real terminal. + * The states are as follows: + * + * COMMAND_MODE This is the initial state. Characters are accumulated + * until a known state is recognized. Receipt of ESC + * always causes command mode to be entered, since + * additional characters are needed to define the next + * instruction. + * + * ALPHA_MODE Characters are drawn in the graphics frame at the + * "current" position (normally set beforehand with a + * GS/US vector move), using the alpha mode font. + * Receipt of any control code causes alpha mode to be + * exited. + * + * TEXT_MODE Text mode is a special mode used to write transient + * text in the status line, using the text mode font. + * Lines of text are accumulated and displayed on the + * status line in reverse video; successive lines of text + * overwrite one another. The status line is cleared + * when text mode is entered, even if no text is drawn. + * Text mode is terminated by receipt of GS or CAN. + * + * VECTOR_MODE Vector mode refers to both polyline and polypoint + * vector sequences. The vertices of the points are + * accumulated in a buffer and displayed when the buffer + * fills or when vector mode is terminated. Vector + * mode is terminated by receipt of any control code; + * the tektronix coordinate encoding maps all possible + * coordinates into the printable ascii codes. + * + * CURSOR_MODE The crosshair cursor is turned on, signifying to the + * user that the system is waiting on a cursor read. + * Output processing ceases until the user types a key + * or presses a mouse button to trigger the cursor read. + * The cursor value is then encoded and transmitted back + * to the pty, and output processing resumes. + * + * Clearing the screen causes the mode to be reset to command mode, and all + * other drawing parameters to be set to their default values, e.g., data level + * on, solid line type, and so on. + */ +static Notify_value +ev_gioprocessdata() +{ + register int quota, ch; + char *save_ip, *ip_start; + int delay = 0; + + pw_lock (pw, &pw_r); + g_mark (ip_start); + + /* Process data. + */ + for (quota=MAX_QUOTA; --quota >= 0 && g_getc(ch) >= 0; ) { + if (ch == 0 || gio_enabled == GRAPHICS_DISCARD) + continue; +again: + switch (gio_mode) { + case COMMAND_MODE: + switch (ch) { + case GS: + case FS: + gio_mode = VECTOR_MODE; + pl_npts = 0; + pl_op = 0; + pl_pointmode = (ch == FS); + chcur_skip = -1; + if (cursor_show) + gio_setcursor (CURSOR_OFF, 0); + + /* Only execute an open workstation if we have not already + * done so and if the next command is something other than + * close workstation, i.e., no-op sequences GS-CAN are + * filtered out, since they would only cause a pointless + * switch to the graphics frame and back without drawing. + */ + if (ch == GS && !workstation_open) + if (g_getc(ch) < 0) { + g_ungetc (GS); + gio_mode = COMMAND_MODE; + goto exit; + } else if (ch != CAN) { + gio_open_workstation(); + workstation_open = 1; + delay = WSOPEN_DELAY; + g_ungetc (ch); + goto exit; + } + break; + + case US: + case CR: + gio_mode = ALPHA_MODE; + tx_len = 0; + if (ch == CR) + goto again; + break; + + case CAN: + if (workstation_open) { + pw_unlock (pw); + gio_close_workstation(); + workstation_open = 0; + delay = WSCLOSE_DELAY; + } + gio_mode = COMMAND_MODE; + goto exit; + + case ESC: + g_ungetc (ch); + g_mark (save_ip); + erase_cursor(); + if ((gio_mode = gio_escape()) == -1) { + gio_mode = COMMAND_MODE; + g_reset (save_ip); + goto exit; + } else if (gio_mode == CURSOR_MODE) + goto again; + break; + + case BEL: + window_bell (gio_canvas); + break; + + default: + ; /* ignore unknown control chars */ + } + break; + + case ALPHA_MODE: + /* Tek alpha mode is used to write text to random positions on + * the screen, or to write lines of text to the gio frame in + * "storage scope" mode, where the left and right columns are + * alternately written into with an inclusive-or rop. + */ + if (ch >= 040) { + tx_buf[tx_len++] = ch; + } else if (ch == '\t') { + tx_buf[tx_len++] = 040; + if (tx_leftmargin == 0) + while ((tx_len + (cur_x / tx_charwidth)) % 8 != 0) + tx_buf[tx_len++] = 040; + } else if (ch == '\010' || ch == '\177') { + if (tx_len > 0) + tx_len--; + else if (cur_x > tx_leftmargin) + cur_x -= tx_charwidth; + } else { +flush_alpha: if (tx_len > 0) { + tx_buf[tx_len] = '\0'; + erase_cursor(); + pw_text (pw, cur_x, cur_y, gio_rop(), + alpha_font->pixfont, tx_buf); + } + + cur_x += tx_len * tx_charwidth; + tx_len = 0; + + if (ch == '\n' || ch == BREAK_LINE) { + cur_y += tx_charheight; + if (cur_y > win_yres) { + if (tx_leftmargin == 0) + tx_leftmargin = win_xres / 2; + else + tx_leftmargin = 0; + cur_y = tx_charbase; + if (cur_x < tx_leftmargin) + cur_x = tx_leftmargin; + } + if (ch == BREAK_LINE) + cur_x = tx_leftmargin; + } else if (ch == '\r') { + cur_x = tx_leftmargin; + } else if (ch != 0) { + gio_mode = COMMAND_MODE; + goto again; + } + } + + /* Break long lines at the right margin. */ + if (cur_x + (tx_len * tx_charwidth) >= win_xres) { + ch = BREAK_LINE; + goto flush_alpha; + } + + break; + + case TEXT_MODE: + if (ch >= 040) + tx_buf[tx_len++] = ch; + else if (ch == '\t') + tx_buf[tx_len++] = 040; + else if (ch == '\010' || ch == '\177') { + if (tx_len > 0) { + --tx_len; + sl_x -= sl_cwidth; + erase_cursor(); + pw_text (pw, sl_x, sl_y, + PIX_SRC, text_font->pixfont, " "); + } + } else { + if (tx_len > 0) { + tx_buf[tx_len] = '\0'; + erase_cursor(); + pw_text (pw, sl_x, sl_y, + PIX_NOT(PIX_SRC), text_font->pixfont, tx_buf); + } + + sl_x += tx_len * sl_cwidth; + if (sl_x > win_xres - sl_cwidth) + sl_x = win_xres - sl_cwidth; + tx_len = 0; + + if (ch == '\r' || ch == '\n') { + sl_x = sl_xoff; + sl_restore_rect(); + } else if (ch != 0) { + gio_mode = COMMAND_MODE; + goto again; + } + } + + /* Truncate long lines. */ + if (sl_x / sl_cwidth + tx_len >= MAX_TEXTCHARS) + if (tx_len > 0) + --tx_len; + else + sl_x -= sl_cwidth; + break; + + case VECTOR_MODE: + /* Following receipt of GS, accumulate encoded coordinate data + * until the buffer fills or a control code is received, then + * decode the encoded data to reconstruct the original data + * vector, and draw the vector. + */ + if (ch >= 040) + pl_text[pl_op++] = ch; + if (ch < 040 || pl_op >= MAX_PLPTS) + pl_decodepts(); + + if (ch < 040 || pl_npts >= MAX_PLPTS) { + if (pl_pointmode && pl_npts >= 1) { + pw_polypoint (pw, 0, 0, pl_npts, pl_p, + PIX_COLOR(1) | gio_rop()); + } else if (pl_npts >= 2) { + /* Must use clipping if dashed line. */ + pw_polyline (pw, 0, 0, pl_npts, pl_p, + POLY_DONTCLOSE, &brush, pl_texture(pl_linestyle), + (PIX_COLOR(1) | gio_rop()) & + ~(pl_linestyle ? PIX_DONTCLIP : 0)); + } + + if (pl_npts > 0) { + cur_x = pl_p[pl_npts-1].x; + cur_y = pl_p[pl_npts-1].y; + pl_npts = 0; + } + + if (ch < 040) { + gio_mode = COMMAND_MODE; + pl_op = 0; + goto again; + } + } + + break; + + case CURSOR_MODE: + if (wait_cursor++) { + g_ungetc (ch); + gio_mode = COMMAND_MODE; + } else + gio_readcursor(); + break; + } + } + +exit: + /* Flush any buffered text before exiting, as applications will assume + * that text appears on the screen as soon as chars are written to the + * terminal (any buffering must be hidden). + */ + if (tx_len > 0) { + ch = 0; + goto again; + } + + update_cursor(); + pw_unlock (pw); + + /* If XOFF is set and the buffer has emptied sufficiently, + * send XON to the terminal driver to accept more data. + */ + if (pty_stop && g_spaceleft > GB_BIGSPACE) { + ioctl (pty_fd, TIOCSTART, NULL); + pty_stop = 0; + } + + /* If there is still data in the buffer (other than a partially + * formed escape sequence) post another callback event before exiting + * to allow other event handlers to run. + */ + if (delay) + gio_pause (delay); + else if (g_havedata && !g_equal(ip_start) && ch != ESC && !wait_cursor) + notify_post_event (ev_gioprocessdata, NULL, NOTIFY_SAFE); + + return (NOTIFY_DONE); +} + + +/* PL_DECODEPTS -- Convert a sequence of textronix encoded polyline vertices + * into a simple array of [x,y] coordinate pairs. Each coordinate pair is + * encoded as a sequence of from 1 to 4 bytes, with bytes being optionally + * eliminated which do not change from one coordinate pair to the next. The + * possible coordinate pair encodings are as follows: + * + * HIY LOY HIX LOX + * 01xxxxx 11xxxxx 01xxxxx 10xxxxx + * 040 140 040 100 + * + * HIY LOX + * HIY LOY LOX + * HIY LOY HIX LOX + * LOY HIX LOX + * LOY LOX + * LOX + * + * In words, bytes which do not change need not be sent, except for the low-x + * byte (LOX). If the high-x byte changes, then the low-x byte must also be + * sent. The current position, stored as the 4 byte encoding, is cleared to + * zero when the screen is cleared. + */ +static +pl_decodepts() +{ + register char *ip, *itop; + int hiy, loy, hix, lox, type, data, nb; + char *ip_save; + + for (ip_save=ip=pl_text, itop = &pl_text[pl_op]; ip < itop; ) { + hiy = ohiy; loy = oloy; + hix = ohix; lox = olox; + + for (nb=0; nb < 99 && ip < itop; nb++) { + type = (*ip & 0140); + data = (*ip++ & 037); + + switch (type) { + case 040: /* HIY, HIX */ + if (nb == 0) + hiy = data; + else + hix = data; + break; + case 0140: /* LOY */ + loy = data; + break; + + case 0100: + /* Receipt of LOX marks the end of the variable length + * sequence of bytes required to form the next [x,y]. + */ + lox = data; + pl_p[pl_npts].x = X_TEK2WIN ((hix << 5) + lox); + pl_p[pl_npts].y = Y_TEK2WIN ((hiy << 5) + loy); + + /* Update current position. */ + ohiy = hiy; oloy = loy; + ohix = hix; olox = lox; + + ip_save = ip; + pl_npts++; + nb = 99; /* EXIT */ + break; + } + } + } + + /* If there is any data left over (too few bytes to form a coordinate + * pair) move these to the start of the buffer. + */ + for (pl_op=0, ip=ip_save; ip < itop; ) + pl_text[pl_op++] = *ip++; +} + + +/* GIO_PAUSE -- Suspend output for the indicated number of milliseconds, to + * allow other event processing to catch up. When the specified interval has + * passed an ev_gioprocessdata event is posted to resume output processing. + */ +gio_pause (msec) +int msec; +{ + static Notify_value ev_restart(); + static struct itimerval itimer_delay; + + gio_delay = msec; + + itimer_delay.it_interval.tv_usec = 0; + itimer_delay.it_interval.tv_sec = 0; + + itimer_delay.it_value.tv_usec = (msec % 1000) * 1000; + itimer_delay.it_value.tv_sec = (msec / 1000); + + notify_set_itimer_func (&itimer_delay, ev_restart, ITIMER_REAL, + &itimer_delay, NULL); +} + + +/* EV_RESTART -- Called when the specified interval has passed to restart + * output processing. + */ +static Notify_value +ev_restart() +{ + gio_delay = 0; + notify_post_event (ev_gioprocessdata, NULL, NOTIFY_SAFE); + + return (NOTIFY_DONE); +} + + +/* GIO_RETCURSOR -- Encode and return a cursor value to the pty (and thence + * to the program which initiated the cursor read). Clear the cursor read + * pending flag so that output processing can resume, and post an event to + * restart the output processing routine. + */ +gio_retcursor (key, x, y) +int key; /* key (or whatever) typed to trigger read */ +int x, y; /* pixwin coords of event */ +{ + register int mc_x, mc_y; + char curval[7]; + int len; + + /* Ignore cursor events unless requested via program control. + */ + if (!wait_cursor) + return (-1); + + mc_x = X_WIN2TEK (x); + mc_y = Y_WIN2TEK (y); + + curval[0] = key; + curval[1] = ((mc_x >> 5) & 037) | 040; + curval[2] = ((mc_x ) & 037) | 040; + curval[3] = ((mc_y >> 5) & 037) | 040; + curval[4] = ((mc_y ) & 037) | 040; + curval[5] = trailer1; + curval[6] = trailer2; + + len = 5; + if (trailer1 >= 0) len++; + if (trailer2 >= 0) len++; + write (pty_fd, curval, len); + + wait_cursor = 0; + gio_mode = COMMAND_MODE; + chcur_skip = -1; + + if (!gio_delay) + notify_post_event (ev_gioprocessdata, NULL, NOTIFY_SAFE); +} + + +/* GIO_RETENQ -- Respond to the ESC ENQ request. + */ +gio_retenq() +{ + register int mc_x, mc_y; + char curval[7]; + int len; + + /* Graphics status word. */ + curval[0] = (061 | ((gio_mode == ALPHA_MODE) << 2) + | ((tx_leftmargin != 0) << 1)); + + /* Alpha cursor position. */ + mc_x = X_WIN2TEK (cur_x); + mc_y = Y_WIN2TEK (cur_y); + + curval[1] = ((mc_x >> 5) & 037) | 040; + curval[2] = ((mc_x ) & 037) | 040; + curval[3] = ((mc_y >> 5) & 037) | 040; + curval[4] = ((mc_y ) & 037) | 040; + curval[5] = trailer1; + curval[6] = trailer2; + + len = 5; + if (trailer1 >= 0) len++; + if (trailer2 >= 0) len++; + write (pty_fd, curval, len); +} + + +/* Definitions and data structures for a fast table driven fixed pattern + * escape sequence recognizer. Given character I of the sequence there will + * be N candidate sequences that have matched the first I-1 chars. Examine + * each to produce the next list of candidate sequences. Continue until either + * a sequence is matched or there are no more candidates. Variable length + * sequences such as "ESC[Pl;PcH" are handled as a special case: the general + * form of these is ESC '[' <digits> [';' <digits>...] LET. + */ +#define MAX_CANDIDATES 32 /* max candidate escseq */ +#define MAX_FIELDS 6 /* max fields in an escseq */ + +struct _esc { + char e_tag; /* integer code for escseq */ + char e_seq[MAX_FIELDS+1]; /* the sequence itself */ +}; + +static struct _esc *e_cand1[MAX_CANDIDATES]; /* 1st candidates array */ +static struct _esc *e_cand2[MAX_CANDIDATES]; /* 2nd candidates array */ +static struct _esc **e_pcand, **e_acand; /* candidates arrays */ +static int e_npcand, e_nacand; /* number of candidates */ +static int e_charno; /* char being examined */ + +static struct _esc e_table[] = { +#include "gterm.esc" /* Gterm escape sequence table */ + { 0, 0,0,0,0,0,0,0 } +}; + + +/* GIO_ESCAPE -- Recognize and process graphics escape sequences, i.e., + * all multicharacter command codes beginning with ESC. The simple single + * character command codes are handled directly by the data processing code. + * The escapes have no well defined pattern to them, hence we must simply + * consume characters until a legal escape sequence is recognized or the + * sequence is found to not match any known sequence. It is possible that + * all of the characters forming a sequence will not yet have been deposited + * in the input buffer, in which case we return -1, indicating to our caller + * that we should be called back later to rescan the same input, when more + * data becomes available. Otherwise, we take whatever action is implied + * for the escape sequence and return the new mode to the interpreter code. + * If an unrecognized escape sequence is encountered it is discarded and we + * return in alpha mode so that subsequent input appears as garbage on the + * screen. + */ +gio_escape() +{ + register struct _esc *esc; + register int ch, i, j; + struct _esc **e_temp; + int tag; + + /* Discard the ESC and get the first char. */ + g_getc (ch); + if (g_getc (ch) < 0) + return (-1); + + /* Build the initial list of candidates. This is the most expensive + * step, since all sequences must be examined. + */ + for (esc=e_table, e_pcand=e_cand1, e_npcand=0; esc->e_tag; esc++) + if (ch == esc->e_seq[0]) { + if (esc->e_seq[1] == 0) { + tag = esc->e_tag; + goto action; + } + e_pcand[e_npcand++] = esc; + } + + /* If there were no candidates, we are done. */ + if (e_npcand == 0) { + g_ungetc (ch); + return (ALPHA_MODE); + } + + /* Examine successive characters from the input, building a new, + * shorter candidate list on each iteration. This should converge + * very rapidly one way or the other. + */ + for (j=1, e_acand=e_cand2; j < MAX_FIELDS && e_npcand > 0; j++) { + if (g_getc(ch) < 0) + return (-1); + + /* Examine the next character of each sequence in the list of + * candidate sequences. If we have a complete match, we are + * done, else if we have a single character match add the seq + * to the new candidates list. + */ + e_nacand = 0; + for (i=0; i < e_npcand; i++) { + esc = e_pcand[i]; + if (ch == esc->e_seq[j]) { + if (esc->e_seq[j+1] == 0) { + tag = esc->e_tag; + goto action; + } + e_acand[e_nacand++] = esc; + } + } + + e_temp = e_pcand; e_pcand = e_acand; e_acand = e_temp; + e_npcand = e_nacand; + } + + /* If the escape sequence was recognized the above code should have + * vectored off to the action marker below. If we fall through the + * loop it can only mean that we have an unrecognized escape sequence, + * so discard it and return in command mode. + */ + g_ungetc (ch); + return (ALPHA_MODE); + +action: + /* Process the escape sequence. */ + switch (tag) { + case ESC_SETTEXTMODE: + tx_len = 0; + sl_x = sl_xoff; + if (sl_rect_saved) + sl_restore_rect(); + else + sl_save_rect(); + return (TEXT_MODE); + + case ESC_ENQUIRE: + gio_retenq(); + break; + case ESC_READCURSOR: + return (CURSOR_MODE); + case ESC_SETCURSOR: + gio_setcursorpos (cur_x, cur_y); + break; + + case ESC_CLEARSCREEN: + pw_writebackground (pw, 0, 0, win_xres, win_yres, PIX_SRC); + tx_leftmargin = 0; + cur_x = tx_leftmargin; + cur_y = tx_charbase; + ohiy = 0; oloy = 0; + ohix = 0; olox = 0; + gio_datalevel = SET_BITS; + pl_linestyle = 0; + pl_linewidth = 1; + pl_pointmode = 0; + sl_rect_saved = 0; + chcur_on = 0; + chcur_skip = 0; + return (ALPHA_MODE); + + case ESC_SETCHARSIZE0: + case ESC_SETCHARSIZE1: + case ESC_SETCHARSIZE2: + case ESC_SETCHARSIZE3: + /* Ignore these for now. */ + break; + + case ESC_SETDATALEVEL0: + gio_datalevel = SET_BITS; + break; + case ESC_SETDATALEVEL1: + gio_datalevel = CLEAR_BITS; + break; + case ESC_SETDATALEVEL2: + gio_datalevel = TOGGLE_BITS; + break; + + case ESC_SETLINESTYLE0: + pl_linestyle = 0; + break; + case ESC_SETLINESTYLE1: + pl_linestyle = 1; + break; + case ESC_SETLINESTYLE2: + pl_linestyle = 2; + break; + case ESC_SETLINESTYLE3: + pl_linestyle = 3; + break; + case ESC_SETLINESTYLE4: + pl_linestyle = 4; + break; + + case ESC_SETLINEWIDTH0: + pl_linewidth = 1; + break; + case ESC_SETLINEWIDTH1: + pl_linewidth = 2; + break; + case ESC_SETLINEWIDTH2: + pl_linewidth = 3; + break; + default: + ; + } + + return (COMMAND_MODE); +} + + +/* UPDATE_CURSOR -- Update the state of the alpha mode cursor, used to mark + * the position of the next character on the screen when in alpha mode. + * In any other mode this cursor is turned off. + */ +update_cursor() +{ + erase_cursor(); + if (gio_mode == ALPHA_MODE && chcur_skip++ >= 0) { + /* Update the position of the alpha character cursor. + */ + pw_text (pw, cur_x, cur_y, + PIX_NOT(PIX_DST), alpha_font->pixfont, " "); + chcur_font = alpha_font; + chcur_x = cur_x; + chcur_y = cur_y; + chcur_on = 1; + + /* Turn the mouse cursor on too, if currently disabled. + */ + gio_setcursor (CURSOR_ON, 0); + } +} + + +/* ERASE_CURSOR -- If the character cursor is currently displayed, restore the + * character under the cursor to its former state. + */ +erase_cursor() +{ + if (chcur_on) { + pw_text (pw, chcur_x, chcur_y, + PIX_NOT(PIX_DST), chcur_font->pixfont, " "); + chcur_on = 0; + } +} + + +/* SL_SAVE_RECT -- Make a copy of the status line pixrect in a memory + * pixrect, so that we can later "erase" the status line by overwriting + * it with the saved data rect. + */ +sl_save_rect() +{ + if (sl_pr) { + pw_read (sl_pr, 0, 0, sl_width, sl_height, PIX_SRC, + pw, sl_xoff, sl_yoff - sl_cbase); + sl_rect_saved = 1; + } +} + + +/* SL_RESTORE_RECT -- Restore the saved status line data pixrect. + */ +sl_restore_rect() +{ + if (sl_pr) + pw_write (pw, sl_xoff, sl_yoff - sl_cbase, sl_width, sl_height, + PIX_SRC, sl_pr, 0, 0); +} + + +/* GIO_ROP -- Return the raster op appropriate for the datalevel control + * option set by the user, i.e, set, clear, or toggle bits. + */ +gio_rop() +{ + register int rop; + + switch (gio_datalevel) { + case SET_BITS: + rop = PIX_SRC | PIX_DST; + break; + case CLEAR_BITS: + rop = PIX_NOT(PIX_SRC) & PIX_DST; + break; + case TOGGLE_BITS: + rop = PIX_SRC ^ PIX_DST; + break; + default: + rop = PIX_SRC; + break; + } + + if (!clip_graphics) + rop |= PIX_DONTCLIP; + + return (rop); +} + + +#define NLINETYPES 5 +static short lt_dashed[] = { 8, 3, 8, 3, 8, 3, 8, 3, 0 }; +static short lt_dotted[] = { 2, 3, 2, 3, 2, 3, 2, 3, 0 }; +static short lt_dashdot[] = { 14, 3, 1, 3, 14, 3, 1, 3, 0 }; +static short lt_dash3dot[] = { 20, 3, 1, 3, 1, 3, 1, 3, 0 }; + +static short *lt_pattern[] = { + NULL, + lt_dashed, + lt_dotted, + lt_dashdot, + lt_dash3dot +}; + + +/* PL_TEXTURE -- Return a pointer to a texture descriptor (Breshingham + * dashed line drawing algorithm) to be used to draw a dashed polyline. + * The case linetype==0 is special, signifying a solid line. The descriptor + * must be initialized to a known state, i.e., zeroed, on each call or + * the pixrect polyline code will produce garbage. + */ +static Pr_texture * +pl_texture (linetype) +int linetype; +{ + register char *p; + register int n; + static Pr_texture tex; + short *pattern; + + if (linetype == 0) + return (NULL); /* solid line */ + else + pattern = lt_pattern[linetype % NLINETYPES]; + + for (p=(char *)(&tex), n=sizeof(tex); --n >= 0; ) + *p++ = NULL; + + tex.pattern = pattern; + tex.options.givenpattern = 1; + + return (&tex); +} diff --git a/unix/sun/halley.lut b/unix/sun/halley.lut new file mode 100644 index 00000000..ac00326a --- /dev/null +++ b/unix/sun/halley.lut @@ -0,0 +1,257 @@ +256, +0.00000, 0.00000, 0.00000, +0.00000, 0.00000, 0.00000, +0.00000, 0.00000, 0.00000, +0.00000, 0.00000, 0.70588, +0.00000, 0.00000, 0.70588, +0.00000, 0.00000, 0.86275, +0.00000, 0.00000, 0.86275, +0.47059, 0.00000, 0.86275, +0.47059, 0.00000, 0.86275, +0.47059, 0.00000, 0.86275, +0.70588, 0.00000, 0.90196, +0.70588, 0.00000, 0.90196, +1.00000, 0.00000, 1.00000, +1.00000, 0.00000, 1.00000, +1.00000, 0.00000, 0.70588, +1.00000, 0.00000, 0.70588, +1.00000, 0.00000, 0.51765, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.47059, 0.00000, +1.00000, 0.47059, 0.00000, +0.98824, 0.72549, 0.00000, +0.98824, 0.72549, 0.00000, +0.98431, 0.81176, 0.00000, +0.98431, 0.85098, 0.00000, +0.98431, 0.85098, 0.00000, +1.00000, 1.00000, 0.00000, +1.00000, 1.00000, 0.00000, +0.70588, 1.00000, 0.00000, +0.70588, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.70588, +0.00000, 1.00000, 0.70588, +0.00000, 1.00000, 1.00000, +0.00000, 1.00000, 1.00000, +0.47059, 0.78431, 1.00000, +0.47059, 0.78431, 1.00000, +0.47059, 0.78431, 1.00000, +0.62745, 0.62745, 1.00000, +0.62745, 0.62745, 1.00000, +0.78431, 0.47059, 1.00000, +0.78431, 0.47059, 1.00000, +1.00000, 0.70588, 1.00000, +1.00000, 0.70588, 1.00000, +1.00000, 0.76863, 1.00000, +1.00000, 0.86275, 1.00000, +1.00000, 0.86275, 1.00000, +1.00000, 1.00000, 1.00000, +1.00000, 1.00000, 1.00000, +1.00000, 1.00000, 1.00000, +1.00000, 1.00000, 1.00000, +1.00000, 0.89804, 1.00000, +1.00000, 0.86275, 1.00000, +1.00000, 0.86275, 1.00000, +1.00000, 0.86275, 1.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.92157, 0.61961, 1.00000, +0.78431, 0.47059, 1.00000, +0.78431, 0.47059, 1.00000, +0.78431, 0.47059, 1.00000, +0.78431, 0.47059, 1.00000, +0.78431, 0.47059, 1.00000, +0.78431, 0.47059, 1.00000, +0.78431, 0.47059, 1.00000, +0.78431, 0.47059, 1.00000, +0.78431, 0.47059, 1.00000, +0.65882, 0.59608, 1.00000, +0.62745, 0.62745, 1.00000, +0.62745, 0.62745, 1.00000, +0.00000, 0.00000, 1.00000, +0.00000, 0.00000, 1.00000, +0.00000, 0.00000, 1.00000, +0.00000, 0.00000, 1.00000, +0.00000, 0.00000, 1.00000, +0.00000, 0.00000, 1.00000, +0.00000, 0.00000, 1.00000, +0.00000, 0.00000, 1.00000, +0.00000, 0.00000, 1.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +0.00000, 1.00000, 0.70588, +0.00000, 1.00000, 0.70588, +0.00000, 1.00000, 0.70588, +0.00000, 1.00000, 0.70588, +0.00000, 1.00000, 0.70588, +0.00000, 1.00000, 0.70588, +0.00000, 1.00000, 0.65490, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.00000, 1.00000, 0.00000, +0.36078, 1.00000, 0.00000, +0.70588, 1.00000, 0.00000, +0.70588, 1.00000, 0.00000, +0.70588, 1.00000, 0.00000, +0.70588, 1.00000, 0.00000, +0.70588, 1.00000, 0.00000, +0.70588, 1.00000, 0.00000, +0.70588, 1.00000, 0.00000, +0.70588, 1.00000, 0.00000, +0.70588, 1.00000, 0.00000, +0.98431, 1.00000, 0.00000, +1.00000, 1.00000, 0.00000, +1.00000, 1.00000, 0.00000, +1.00000, 1.00000, 0.00000, +1.00000, 1.00000, 0.00000, +1.00000, 1.00000, 0.00000, +1.00000, 1.00000, 0.00000, +1.00000, 1.00000, 0.00000, +1.00000, 1.00000, 0.00000, +0.99608, 0.97647, 0.00000, +0.98431, 0.85098, 0.00000, +0.98431, 0.85098, 0.00000, +0.98431, 0.85098, 0.00000, +0.98431, 0.85098, 0.00000, +0.98431, 0.85098, 0.00000, +0.98431, 0.85098, 0.00000, +0.98431, 0.85098, 0.00000, +0.98431, 0.85098, 0.00000, +0.98431, 0.85098, 0.00000, +0.98824, 0.77647, 0.00000, +0.98824, 0.72549, 0.00000, +0.98824, 0.72549, 0.00000, +0.98824, 0.72549, 0.00000, +0.98824, 0.72549, 0.00000, +0.98824, 0.72549, 0.00000, +0.98824, 0.72549, 0.00000, +0.98824, 0.72549, 0.00000, +0.98824, 0.72549, 0.00000, +0.98824, 0.72549, 0.00000, +1.00000, 0.47059, 0.00000, +1.00000, 0.47059, 0.00000, +1.00000, 0.47059, 0.00000, +1.00000, 0.47059, 0.00000, +1.00000, 0.47059, 0.00000, +1.00000, 0.47059, 0.00000, +1.00000, 0.47059, 0.00000, +1.00000, 0.47059, 0.00000, +1.00000, 0.47059, 0.00000, +1.00000, 0.36863, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.00000, +1.00000, 0.00000, 0.46667, +1.00000, 0.00000, 0.70588, +1.00000, 0.00000, 0.70588, +1.00000, 0.00000, 0.70588, +1.00000, 0.00000, 0.70588, +1.00000, 0.00000, 0.70588, +1.00000, 0.00000, 0.70588, +1.00000, 0.00000, 0.70588, +1.00000, 0.00000, 0.70588, +1.00000, 0.00000, 0.70588, +1.00000, 0.00000, 1.00000, +1.00000, 0.00000, 1.00000, +1.00000, 0.00000, 1.00000, +1.00000, 0.00000, 1.00000, +1.00000, 0.00000, 1.00000, +1.00000, 0.00000, 1.00000, +1.00000, 0.00000, 1.00000, +1.00000, 0.00000, 1.00000, +1.00000, 0.00000, 1.00000, +0.91373, 0.00000, 0.97255, +0.70588, 0.00000, 0.90196, +0.70588, 0.00000, 0.90196, +0.70588, 0.00000, 0.90196, +0.70588, 0.00000, 0.90196, +0.70588, 0.00000, 0.90196, +0.70588, 0.00000, 0.90196, +0.70588, 0.00000, 0.90196, +0.70588, 0.00000, 0.90196, +0.70588, 0.00000, 0.90196, +0.53333, 0.00000, 0.87451, +0.47059, 0.00000, 0.86275, +0.47059, 0.00000, 0.86275, +0.47059, 0.00000, 0.86275, +0.47059, 0.00000, 0.86275, +0.47059, 0.00000, 0.86275, +0.47059, 0.00000, 0.86275, +0.47059, 0.00000, 0.86275, +0.47059, 0.00000, 0.86275, +0.47059, 0.00000, 0.86275, +1.00000, 1.00000, 1.00000, +1.00000, 1.00000, 1.00000, +1.00000, 1.00000, 1.00000, +1.00000, 1.00000, 1.00000, +1.00000, 1.00000, 1.00000, +0.00000, 0.00000, 0.86275, +0.00000, 0.00000, 0.86275, +0.00000, 0.00000, 0.86275, +0.00000, 0.00000, 0.86275, +0.00000, 0.00000, 0.80392, +0.00000, 0.00000, 0.70588, +0.00000, 0.00000, 0.70588, +0.00000, 0.00000, 0.70588, +0.00000, 0.00000, 0.70588, +0.00000, 0.00000, 0.70588, +0.00000, 0.00000, 0.70588, +0.00000, 0.00000, 0.70588, +0.00000, 0.00000, 0.70588, +0.00000, 0.00000, 0.70588, +0.00000, 0.00000, 0.13725, +0.00000, 0.00000, 0.00000, +0.00000, 0.00000, 0.00000, +0.00000, 0.00000, 0.00000, +0.00000, 0.00000, 0.00000, +0.00000, 0.00000, 0.00000, +0.00000, 0.00000, 0.00000, +0.00000, 0.00000, 0.00000, +0.00000, 0.00000, 0.00000, +0.00000, 0.00000, 0.00000 diff --git a/unix/sun/heat.lut b/unix/sun/heat.lut new file mode 100644 index 00000000..124a70f4 --- /dev/null +++ b/unix/sun/heat.lut @@ -0,0 +1,257 @@ +256, +0.00000, 0.00000, 0.00000, +0.01176, 0.00392, 0.00000, +0.02353, 0.00784, 0.00000, +0.03529, 0.01176, 0.00000, +0.04706, 0.01569, 0.00000, +0.05882, 0.01961, 0.00000, +0.07059, 0.02353, 0.00000, +0.08235, 0.02745, 0.00000, +0.09412, 0.03137, 0.00000, +0.10588, 0.03529, 0.00000, +0.11765, 0.03922, 0.00000, +0.12941, 0.04314, 0.00000, +0.14118, 0.04706, 0.00000, +0.15294, 0.05098, 0.00000, +0.16471, 0.05490, 0.00000, +0.17647, 0.05882, 0.00000, +0.18824, 0.06275, 0.00000, +0.20000, 0.06667, 0.00000, +0.21176, 0.07059, 0.00000, +0.22353, 0.07451, 0.00000, +0.23529, 0.07843, 0.00000, +0.24706, 0.08235, 0.00000, +0.25882, 0.08627, 0.00000, +0.27059, 0.09020, 0.00000, +0.28235, 0.09412, 0.00000, +0.29412, 0.09804, 0.00000, +0.30588, 0.10196, 0.00000, +0.31765, 0.10588, 0.00000, +0.32941, 0.10980, 0.00000, +0.34118, 0.11373, 0.00000, +0.35294, 0.11765, 0.00000, +0.36471, 0.12157, 0.00000, +0.37647, 0.12549, 0.00000, +0.38824, 0.12941, 0.00000, +0.40000, 0.13333, 0.00000, +0.41176, 0.13725, 0.00000, +0.42353, 0.14118, 0.00000, +0.43529, 0.14510, 0.00000, +0.44706, 0.14902, 0.00000, +0.45882, 0.15294, 0.00000, +0.47059, 0.15686, 0.00000, +0.48235, 0.16078, 0.00000, +0.49412, 0.16471, 0.00000, +0.50588, 0.16863, 0.00000, +0.51765, 0.17255, 0.00000, +0.52941, 0.17647, 0.00000, +0.54118, 0.18039, 0.00000, +0.55294, 0.18431, 0.00000, +0.56471, 0.18824, 0.00000, +0.57647, 0.19216, 0.00000, +0.58824, 0.19608, 0.00000, +0.60000, 0.20000, 0.00000, +0.61176, 0.20392, 0.00000, +0.62353, 0.20784, 0.00000, +0.63529, 0.21176, 0.00000, +0.64706, 0.21569, 0.00000, +0.65882, 0.21961, 0.00000, +0.67059, 0.22353, 0.00000, +0.68235, 0.22745, 0.00000, +0.69412, 0.23137, 0.00000, +0.70588, 0.23529, 0.00000, +0.71765, 0.23922, 0.00000, +0.72941, 0.24314, 0.00000, +0.74118, 0.24706, 0.00000, +0.75294, 0.25098, 0.00000, +0.76471, 0.25490, 0.00000, +0.77647, 0.25882, 0.00000, +0.78824, 0.26275, 0.00000, +0.80000, 0.26667, 0.00000, +0.81176, 0.27059, 0.00000, +0.82353, 0.27451, 0.00000, +0.83529, 0.27843, 0.00000, +0.84706, 0.28235, 0.00000, +0.85882, 0.28627, 0.00000, +0.87059, 0.29020, 0.00000, +0.88235, 0.29412, 0.00000, +0.89412, 0.29804, 0.00000, +0.90588, 0.30196, 0.00000, +0.91765, 0.30588, 0.00000, +0.92941, 0.30980, 0.00000, +0.94118, 0.31373, 0.00000, +0.95294, 0.31765, 0.00000, +0.96471, 0.32157, 0.00000, +0.97647, 0.32549, 0.00000, +0.98824, 0.32941, 0.00000, +1.00000, 0.33333, 0.00000, +1.00000, 0.33725, 0.00000, +1.00000, 0.34118, 0.00000, +1.00000, 0.34510, 0.00000, +1.00000, 0.34902, 0.00000, +1.00000, 0.35294, 0.00000, +1.00000, 0.35686, 0.00000, +1.00000, 0.36078, 0.00000, +1.00000, 0.36471, 0.00000, +1.00000, 0.36863, 0.00000, +1.00000, 0.37255, 0.00000, +1.00000, 0.37647, 0.00000, +1.00000, 0.38039, 0.00000, +1.00000, 0.38431, 0.00000, +1.00000, 0.38824, 0.00000, +1.00000, 0.39216, 0.00000, +1.00000, 0.39608, 0.00000, +1.00000, 0.40000, 0.00000, +1.00000, 0.40392, 0.00000, +1.00000, 0.40784, 0.00000, +1.00000, 0.41176, 0.00000, +1.00000, 0.41569, 0.00000, +1.00000, 0.41961, 0.00000, +1.00000, 0.42353, 0.00000, +1.00000, 0.42745, 0.00000, +1.00000, 0.43137, 0.00000, +1.00000, 0.43529, 0.00000, +1.00000, 0.43922, 0.00000, +1.00000, 0.44314, 0.00000, +1.00000, 0.44706, 0.00000, +1.00000, 0.45098, 0.00000, +1.00000, 0.45490, 0.00000, +1.00000, 0.45882, 0.00000, +1.00000, 0.46275, 0.00000, +1.00000, 0.46667, 0.00000, +1.00000, 0.47059, 0.00000, +1.00000, 0.47451, 0.00000, +1.00000, 0.47843, 0.00000, +1.00000, 0.48235, 0.00000, +1.00000, 0.48627, 0.00000, +1.00000, 0.49020, 0.00000, +1.00000, 0.49412, 0.00000, +1.00000, 0.49804, 0.00000, +1.00000, 0.50196, 0.00000, +1.00000, 0.50588, 0.00000, +1.00000, 0.50980, 0.00000, +1.00000, 0.51373, 0.00000, +1.00000, 0.51765, 0.00000, +1.00000, 0.52157, 0.00000, +1.00000, 0.52549, 0.00000, +1.00000, 0.52941, 0.00000, +1.00000, 0.53333, 0.00000, +1.00000, 0.53725, 0.00000, +1.00000, 0.54118, 0.00000, +1.00000, 0.54510, 0.00000, +1.00000, 0.54902, 0.00000, +1.00000, 0.55294, 0.00000, +1.00000, 0.55686, 0.00000, +1.00000, 0.56078, 0.00000, +1.00000, 0.56471, 0.00000, +1.00000, 0.56863, 0.00000, +1.00000, 0.57255, 0.00000, +1.00000, 0.57647, 0.00000, +1.00000, 0.58039, 0.00000, +1.00000, 0.58431, 0.00000, +1.00000, 0.58824, 0.00000, +1.00000, 0.59216, 0.00000, +1.00000, 0.59608, 0.00000, +1.00000, 0.60000, 0.00000, +1.00000, 0.60392, 0.00000, +1.00000, 0.60784, 0.00000, +1.00000, 0.61176, 0.00000, +1.00000, 0.61569, 0.00000, +1.00000, 0.61961, 0.00000, +1.00000, 0.62353, 0.00000, +1.00000, 0.62745, 0.00000, +1.00000, 0.63137, 0.00000, +1.00000, 0.63529, 0.00000, +1.00000, 0.63922, 0.00000, +1.00000, 0.64314, 0.00000, +1.00000, 0.64706, 0.00000, +1.00000, 0.65098, 0.01176, +1.00000, 0.65490, 0.02353, +1.00000, 0.65882, 0.03529, +1.00000, 0.66275, 0.04706, +1.00000, 0.66667, 0.05882, +1.00000, 0.67059, 0.07059, +1.00000, 0.67451, 0.08235, +1.00000, 0.67843, 0.09412, +1.00000, 0.68235, 0.10588, +1.00000, 0.68627, 0.11765, +1.00000, 0.69020, 0.12941, +1.00000, 0.69412, 0.14118, +1.00000, 0.69804, 0.15294, +1.00000, 0.70196, 0.16471, +1.00000, 0.70588, 0.17647, +1.00000, 0.70980, 0.18824, +1.00000, 0.71373, 0.20000, +1.00000, 0.71765, 0.21176, +1.00000, 0.72157, 0.22353, +1.00000, 0.72549, 0.23529, +1.00000, 0.72941, 0.24706, +1.00000, 0.73333, 0.25882, +1.00000, 0.73725, 0.27059, +1.00000, 0.74118, 0.28235, +1.00000, 0.74510, 0.29412, +1.00000, 0.74902, 0.30588, +1.00000, 0.75294, 0.31765, +1.00000, 0.75686, 0.32941, +1.00000, 0.76078, 0.34118, +1.00000, 0.76471, 0.35294, +1.00000, 0.76863, 0.36471, +1.00000, 0.77255, 0.37647, +1.00000, 0.77647, 0.38824, +1.00000, 0.78039, 0.40000, +1.00000, 0.78431, 0.41176, +1.00000, 0.78824, 0.42353, +1.00000, 0.79216, 0.43529, +1.00000, 0.79608, 0.44706, +1.00000, 0.80000, 0.45882, +1.00000, 0.80392, 0.47059, +1.00000, 0.80784, 0.48235, +1.00000, 0.81176, 0.49412, +1.00000, 0.81569, 0.50588, +1.00000, 0.81961, 0.51765, +1.00000, 0.82353, 0.52941, +1.00000, 0.82745, 0.54118, +1.00000, 0.83137, 0.55294, +1.00000, 0.83529, 0.56471, +1.00000, 0.83922, 0.57647, +1.00000, 0.84314, 0.58824, +1.00000, 0.84706, 0.60000, +1.00000, 0.85098, 0.61176, +1.00000, 0.85490, 0.62353, +1.00000, 0.85882, 0.63529, +1.00000, 0.86275, 0.64706, +1.00000, 0.86667, 0.65882, +1.00000, 0.87059, 0.67059, +1.00000, 0.87451, 0.68235, +1.00000, 0.87843, 0.69412, +1.00000, 0.88235, 0.70588, +1.00000, 0.88627, 0.71765, +1.00000, 0.89020, 0.72941, +1.00000, 0.89412, 0.74118, +1.00000, 0.89804, 0.75294, +1.00000, 0.90196, 0.76471, +1.00000, 0.90588, 0.77647, +1.00000, 0.90980, 0.78824, +1.00000, 0.91373, 0.80000, +1.00000, 0.91765, 0.81176, +1.00000, 0.92157, 0.82353, +1.00000, 0.92549, 0.83529, +1.00000, 0.92941, 0.84706, +1.00000, 0.93333, 0.85882, +1.00000, 0.93725, 0.87059, +1.00000, 0.94118, 0.88235, +1.00000, 0.94510, 0.89412, +1.00000, 0.94902, 0.90588, +1.00000, 0.95294, 0.91765, +1.00000, 0.95686, 0.92941, +1.00000, 0.96078, 0.94118, +1.00000, 0.96471, 0.95294, +1.00000, 0.96863, 0.96471, +1.00000, 0.97255, 0.97647, +1.00000, 0.97647, 0.98824, +1.00000, 0.98039, 1.00000, +1.00000, 0.98431, 1.00000, +1.00000, 0.98824, 1.00000, +1.00000, 0.99216, 1.00000, +1.00000, 0.99608, 1.00000, +1.00000, 1.00000, 1.00000 diff --git a/unix/sun/imtool.c b/unix/sun/imtool.c new file mode 100644 index 00000000..6c055610 --- /dev/null +++ b/unix/sun/imtool.c @@ -0,0 +1,4488 @@ +/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + */ + +#include <suntool/sunview.h> +#include <suntool/canvas.h> +#include <suntool/panel.h> +#include <suntool/walkmenu.h> +#include <suntool/tool_struct.h> +#include <sunwindow/win_cursor.h> +#include <sys/fcntl.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <stdio.h> +#include <ctype.h> +#include <math.h> +#include "imtool.h" + +/* + * IMTOOL -- Software image display for the Sun workstation under Sunview. + * A variable sized window is used to peer into a "fixed" size frame buffer + * at an arbitrary offset (pan) and scale (zoom/dezoom). The number of frames + * and the size of a frame buffer is arbitrary and is a setup option. The + * depth of a frame on an 8 bit display is 7 bits with a 1 bit graphics + * overlay plane; this leaves almost half of the color table space for use + * by other windows. A data stream command interface is provided for software + * control of the display server by other processes, not necessarily on the + * same node. + * + * D.Tody, April 1987 (NOAO/IRAF project) + * Extensively revised and extended December 1987. + * Zoom and further datastream mods (WCS) added May 1989. + * (but NeWS/X is coming soon and probably none of this will work anymore...) + */ + +#ifndef abs +#define abs(a) (((a)<0)?(-(a)):(a)) +#endif + +#ifndef min +#define min(a,b) ((a)<(b)?(a):(b)) +#endif +#ifndef max +#define max(a,b) ((a)<(b)?(b):(a)) +#endif + +/* Default values, size limiting values. + */ +#define MAX_ARGS 50 /* max command line arguments */ +#define MAX_FBCONFIG 128 /* max possible frame buf sizes */ +#define MAX_FRAMES 16 /* max number of frames */ +#define FRAME_CHOICES "1","2","3","4" /* nframes choices for setup */ +#define NGREY 256 /* max physical greylevels */ +#define CLOCK_INTERVAL 500 /* main clock tick, msec */ +#define DEF_NCONFIG 1 /* number of f.b. configs */ +#define DEF_NFRAMES 1 /* save memory; only one frame */ +#define DEF_FRAME_WIDTH 512 /* 512 square frame */ +#define DEF_FRAME_HEIGHT 512 /* 512 square frame */ +#define DEF_GIOWIN_SIZE 512 /* default size gio window */ +#define SZ_LABEL 256 /* main frame label string */ +#define SZ_IMTITLE 128 /* image title string */ +#define SZ_WCTEXT 80 /* WCS box text */ +#define SZ_WCSBUF 320 /* WCS text buffer size */ +#define SZ_PANTEXT 18 /* displayed chars in o_fname */ +#define SZ_COLORBAR 11 /* height of colorbar in pixels */ +#define SZ_FNAME 128 +#define SZ_LINE 256 +#define IO_TIMEOUT 30 /* i/o not getting anywhere */ +#define SZ_FIFOBUF 4000 /* transfer size for FIFO i/o */ +#define BKG_WHITE 0 +#define BKG_BLACK 1 +#define P_IMAGE 1 +#define P_GRAPHICS 2 +#define P_COLORBAR 4 +#define P_DONTCLIP 8 +#define PANNER_EVENT 99 +#define INTERRUPT 003 +#define NEXT_SCREEN 006 +#define PREV_SCREEN 022 +#define CYCLE_BLINK 002 + +/* Reserved colormap entries. + */ +#define CMS_DATASTART 1 /* first data greylevel */ +#define CMS_DATAEND 200 /* last data greylevel */ +#define CMS_DATARANGE 200 /* number of data greylevels */ +#define CMS_CURSOR 201 /* cursor color table entry */ +#define CMS_BACKGROUND 202 /* background color */ +#define CMS_GRAPHICSSTART 203 /* first graphics greylevel */ +#define CMS_GRAPHICSEND 217 /* last graphics greylevel */ +#define CMS_GRAPHICSRANGE 15 /* number of graphics greylevel */ +#define CMS_GCOLOR(c) (203+(c)) /* graphics color table entries */ +#define CMS_FIRST 1 /* first grey level used */ +#define CMS_NGREY 218 /* total number of grey levels */ + +/* Magic numbers. */ +#define BLINK_OFF 1 /* crosshair cursor off */ +#define BLINK_ON 2 /* turn crosshair cursor on */ +#define CMMAPNAME "imtool" /* color map segment name */ +#define OLD_DEVNAME "/dev/imt1" /* original pseudodevice name */ +#define I_DEVNAME "/dev/imt1o" /* pseudo device names */ +#define O_DEVNAME "/dev/imt1i" /* our IN is client's OUT */ +#define KEY_SETUP KEY_TOP(4) /* togglt the setup panel */ +#define KEY_REMARK KEY_TOP(5) /* remark list of objects */ +#define KEY_PCOORDS KEY_TOP(6) /* cont. coords display */ +#define KEY_SNAP KEY_TOP(7) /* image hardcopy key */ +#define TEXT_FONT "/usr/lib/fonts/fixedwidthfonts/screen.b.14" +#define MARK_FONT "/usr/lib/fonts/fixedwidthfonts/screen.r.11" +#define COORDFILE "frame.%d.%d" +#define FBCONFIG_1 ".imtoolrc" +#define FBCONFIG_2 "/usr/local/lib/imtoolrc" +#define FBCONFIG_ENV1 "imtoolrc" +#define FBCONFIG_ENV2 "IMTOOLRC" + +#define R_TYPE 0 /* 0=postscript, 1=rasterfile */ +#define R_DISPOSE "lpr -s %s" /* dispose command */ +#define R_FILENAME "" /* output filename */ + +/* Global state codes. */ +#define TRACK_CURSOR 0 +#define WINDOW 1 +#define ROAM 2 + +#define MONO 0 +#define HEAT 1 +#define RAMP1 2 +#define RAMP2 3 +#define HALLEY 4 +#define LINEARPS 5 +#define RANDOMPS 6 +#define CRANDOMPS 7 +#define ULUT1 8 +#define ULUT2 9 + +/* WCS definitions. */ +#define W_UNITARY 0 +#define W_LINEAR 1 +#define W_LOG 2 +#define W_DEFFORMAT " %7.2f %7.2f %7.1f%c" + +/* Internal variables. */ +static int snap_frame_too = 1; /* include frame in imcopy? */ +static int cursor_blink = -1; /* crosshair or small cursor */ +static int cursor_show = -1; /* cursor state; on/off */ +static int display_coords = 0; /* cont. display cursor coords */ +static int p_cursor_setback = 0; /* restore cursor pos after pan */ +static int panning = 0; /* smooth image pan in progress */ +static int maptype = MONO; /* initial mapping type */ +static char o_fname[SZ_FNAME]; /* name of coord output file */ +static char o_revtext=1; /* reverse video text? */ +static int setup_xoff = 4; /* offset to setup panel */ +static int setup_yoff = 18; /* " " */ +static int wc_xoff=0, wc_yoff=0; /* offset to WCS output box */ +static int wc_width, wc_height; /* size of WCS output box */ +static char wc_text[SZ_WCTEXT+1]; /* coordinate text */ +static struct pixfont *wc_font = NULL; /* WCS box font */ +static int cb_height = SZ_COLORBAR; +static int show_colorbar = 1; +static int black = 0; +static int white = NGREY - 1; +static int background = 0; /* background color index */ +static int state = TRACK_CURSOR; /* mouse button state */ +static int last_sx, last_sy; /* window x,y of last event */ +static int save_sx, save_sy; /* save absolute mouse position */ +static int last_bx, last_by; /* last button press */ +static int fb_bkgcolor_index = BKG_WHITE; +static int window_open = 1; +static int global_colortable = 1; /* globally manage colortable */ +static int fbconfig = 0; +static int last_x, last_y, last_key, key_left=0; +static int reading_imcursor = 0; +static int imcursor_wcs; +static char wcsbuf[MAX_FRAMES][SZ_WCSBUF]; + +#define CRANDOM_CHOICES "1", "2", "4", "8", "16", "32" +static int cr_msec[] = { 1000, 2000, 4000, 8000, 16000, 32000 }; +static int crandom_blink_rate = 1; /* rate for cont. random pseudo */ + +/* Blink parameters. */ +#define BLINKRATE_CHOICES "1/2","1","2","4","8","16","32" +static int blink_rate[] = { 1, 2, 4, 8, 16, 32, 64 }; +static int blink_rate_index = 1; /* current blink rate */ +static int blink_timer = 0; /* nticks left on clock */ +static int blink_frame = 0; /* current blink frame */ +static int blink = 0; /* blink enabled? */ +static int n_blink_frames = 8; /* number of frames to blink */ +static int blink_frames[MAX_FRAMES] = { 1, 2, 3, 4, 5, 6, 7, 8 }; +static char s_blinklist[SZ_FNAME+1] = "all"; /* list of frames to blink */ + +/* Logical image cursor parameters. */ +static int marktype = 0; /* mark cursor position */ + +/* The following is needed to provide sufficient precision to allow for + * zooming virtual pixrects (Rects use type short). + */ +typedef struct bigrect { + int r_left, r_top; + int r_width, r_height; +} BRect; + +/* Predefined lookup tables. */ +struct triplet { + float red, green, blue; +}; +struct lut { + int lutlen; + struct triplet hue[NGREY]; +}; + +struct lut heat = { +#include "heat.lut" +}; + +struct lut halley = { +#include "halley.lut" +}; + +/* User defined lookup tables. */ +static char u_lut1[SZ_FNAME+1] = "none"; +static char u_lut2[SZ_FNAME+1] = "none"; + +static BRect pw_rect; /* raw frame buffer */ +static int fb_depth = 8; +static int fb_ngrey = CMS_DATARANGE; +static int fb_nframes= DEF_NFRAMES; +static int Fb_width = DEF_FRAME_WIDTH; +static int Fb_height = DEF_FRAME_HEIGHT; + +static BRect fb_rect; /* zoomed frame buffer */ +static int fb_width = DEF_FRAME_WIDTH; +static int fb_height = DEF_FRAME_HEIGHT; + +#define MAX_ZOOMS 8 +#define ZOOM_CHOICES "1","2","4","8" +static int zoom = 1; +static int nzooms = 4; /* number of zoom factors */ +static int zoom_index = 0; +static int zooms[MAX_ZOOMS] = { 1, 2, 4, 8 }; +static char s_zoomslist[SZ_FNAME+1] = "1 2 4 8"; + +static int gio_xsize = DEF_GIOWIN_SIZE; +static int gio_ysize = DEF_GIOWIN_SIZE; +static int initial_gio_xsize, initial_gio_ysize; + +/* Rotation matrix defining world coordinate system (WCS) of a frame. + */ +struct ctran { + int valid; /* has WCS been set? */ + float a, b; /* x, y scale factors */ + float c, d; /* x, y cross factors */ + float tx, ty; /* x, y translation */ + float z1, z2; /* greyscale range */ + int zt; /* greyscale mapping */ + char format[32]; /* wcs output format */ + char imtitle[SZ_IMTITLE+1]; /* image title from WCS */ +}; + +/* The frame buffers. */ +struct framebuf { + struct pixrect *fb_pr; /* frame buffer pixrect */ + int fb_frameno; /* frame number */ + int fb_xoff, fb_yoff; /* fb coords of pixwin (0,0) */ + int fb_xzoom, fb_yzoom; /* zoom/dezoom factors */ + int fb_objno; /* object number */ + int fb_imageno; /* displayed frame counter */ + int fb_maptype; /* greyscale transformation */ + float fb_center, fb_slope; /* transfer function */ + struct ctran fb_ctran; /* world coordinate system */ + char fb_label[SZ_LABEL+1]; /* frame label string */ +}; + +/* Possible frame buffer sizes. */ +struct fbconfig { + int nframes; /* number of frames */ + int width; /* frame buffer width */ + int height; /* frame buffer height */ +}; + +static int display_frame; /* currently displayed frame */ +static int reference_frame; /* reference (cmd i/o) frame */ +static struct framebuf *frames=NULL; /* array of frame descriptors */ +static struct framebuf *df_p; /* display frame descriptor */ +static struct framebuf *rf_p; /* reference frame descriptor */ +static struct pixrect *cb_pr; /* colorbar pixrect */ +static int fb_nconfig = 0; +static int fb_config_index = 0; +static struct fbconfig fb_config[MAX_FBCONFIG]; +static char startfile[SZ_FNAME+1]; /* image read on startup */ +static char rasterfile[SZ_FNAME+1] = "raster.%d.%d"; + +/* Screendump stuff. */ +int r_type = R_TYPE; +char r_dispose[SZ_FNAME+1] = R_DISPOSE; +char r_filename[SZ_FNAME+1] = R_FILENAME; + +#define HEIGHTADJUST \ + (tool_headerheight((int)window_get(gio_frame, FRAME_SHOW_LABEL)) + \ + TOOL_BORDERWIDTH) + +static short iconimage[] = { +#include "imtool.icon" +}; +DEFINE_ICON_FROM_IMAGE (icon, iconimage); + +Window gio_frame, gio_canvas; +static int gio_frame_fd; +static int datain, dataout; +static Menu_item blink_item; +static Panel setup_panel; +static Window setup_frame; +static Panel_item pan_show_colorbar, pan_globalcolor; +static Panel_item pan_set_nframes, pan_blink_rate, pan_blink_list; +static Panel_item pan_set_maptype, pan_crandom_rate, pan_set_ofname; +static Panel_item pan_snapframetoo, pan_set_background, pan_set_rfname; +static Panel_item pan_set_rtype, pan_set_rdispose, pan_set_rfilename; +static Panel_item pan_set_marker, pan_zoom_list; +static Panel_item pan_set_ulut1, pan_set_ulut2; +static unsigned char red[NGREY], blue[NGREY], green[NGREY]; +static unsigned char m_red[NGREY], m_blue[NGREY], m_green[NGREY]; + +static struct pixwin *gio_pw; +static int main_argc, gio_argc; +static char **main_argv, *gio_argv[MAX_ARGS]; + +static Notify_value ev_gioframe(), set_colortable(); +static Notify_value ev_gioinput(), ev_cmdinput(), ev_panner(); +static char *getfname(), *framelabel(); +static struct ctran *wcs_update(); +static struct pixrect *get_screen_rect(); +static refresh_display(); +extern char *getenv(); + + +/* IMTOOL_MAIN -- Create the Imtool windows, i.e., the main display window, + * the region of interest or "cursor" subwindow, and the setup panel. There + * are two principal event handlers, the display window event handler, used + * to process cursor input and mouse button commands, and the command input + * event handler, used to communicate with the client process. + */ +#ifdef STANDALONE +main (argc, argv) +#else +imtool_main (argc, argv) +#endif +int argc; +char **argv; +{ + char *s; + + main_argc = argc; + main_argv = argv; + parse_args (argc, argv, &gio_argc, gio_argv); + + /* Screendump stuff. */ + if (s = getenv ("R_DISPOSE")) + strcpy (r_dispose, s); + if (s = getenv ("R_FILENAME")) + strcpy (r_filename, s); + if (s = getenv ("R_RASTERFILE")) { + strcpy (r_filename, s); + r_type = 1; + } + + gio_frame = window_create (NULL, FRAME, + FRAME_ICON, &icon, + FRAME_LABEL, + "imtool - NOAO/IRAF Sunview Image Display V1.1", + FRAME_ARGS, gio_argc, gio_argv, + FRAME_NO_CONFIRM, FALSE, + 0); + if (gio_frame == NULL) + exit (1); + + gio_frame_fd = (int) window_get (gio_frame, WIN_FD); + parse_args (argc, argv, &gio_argc, gio_argv); + create_gio_canvas (gio_argc, gio_argv); + create_frame_menu (gio_frame); + create_setup_popup(); + notify_interpose_event_func (gio_frame, ev_gioframe, NOTIFY_SAFE); + notify_interpose_event_func (gio_canvas, ev_gioinput, NOTIFY_SAFE); + + get_fbconfig(); + set_fbconfig (fbconfig, 0); + load_testpattern (0); + set_colortable(); + gio_setcursor (CURSOR_ON, BLINK_OFF); + set_transfer_function (gio_pw, df_p->fb_center, df_p->fb_slope); + + Bpw_get_region_rect (gio_pw, &pw_rect); + pw_rect.r_left = df_p->fb_xoff; + pw_rect.r_top = df_p->fb_yoff; + init_colorbar (pw_rect.r_width); + + if (startfile[0]) + load_raster (rf_p->fb_pr, startfile); + + initial_gio_xsize = gio_xsize; + initial_gio_ysize = gio_ysize; + + /* Open the output fifo. We have to open it ourselves first as a + * client to get around the fifo open-no-client error. + */ + if ((datain = open (O_DEVNAME, O_RDONLY|O_NDELAY)) != -1) { + if ((dataout = open (O_DEVNAME, O_WRONLY|O_NDELAY)) != -1) + fcntl (dataout, F_SETFL, O_WRONLY); + close (datain); + } + + /* Open the input stream, a FIFO pseudodevice file used by + * applications to send us commands and data. + */ + if ((datain = open (I_DEVNAME, O_RDONLY|O_NDELAY)) == -1) { + if ((datain = open (OLD_DEVNAME, O_RDONLY|O_NDELAY)) == -1) + fprintf (stderr, "Warning: cannot open %s\n", I_DEVNAME); + } else { + /* Clear O_NDELAY for reading. */ + fcntl (datain, F_SETFL, O_RDONLY); + notify_set_input_func (gio_frame, ev_cmdinput, datain); + } + + imtool_clock(); + window_main_loop (gio_frame); + close (datain); + exit (0); +} + + +/* PARSE_ARGS -- Parse the argument list into the arguments for the main frame + * and the global arguments for the server. + */ +static +parse_args (argc, argv, gio_argc, gio_argv) +int argc; +char *argv[]; +int *gio_argc; +char *gio_argv[]; +{ + register char *argp; + register int arg; + static int ncalls = 0; + + gio_argv[0] = argv[0]; + *gio_argc = 1; + + for (arg=1; arg <= argc && (argp = argv[arg]) != NULL; arg++) { + if (strncmp (argp, "-fbconfig", 3) == 0) { + /* Set the frame buffer configuration. */ + if ((argp = argv[arg+1]) && isdigit(*argp)) { + fbconfig = max (0, atoi(argp) - 1); + arg++; + } else if (ncalls == 0) + fprintf (stderr, "-fbconfig argument missing\n"); + } else if (strncmp (argp, "-raster", 4) == 0) { + if ((argp = argv[arg+1])) { + strcpy (startfile, argp); + arg++; + } + } else + gio_argv[(*gio_argc)++] = argp; + } + + gio_argv[(*gio_argc)] = NULL; + ncalls++; +} + + +/* GET_FBCONFIG -- Read the IMTOOL startup file to get the set of possible + * frame buffer sizes. + * + * File format: configno nframes width height [extra fields] + * e.g., 1 2 512 512 + * 2 2 800 800 + * 3 1 1024 1024 # comment + */ +static +get_fbconfig() +{ + register char *ip; + register FILE *fp; + int config, nframes, width, height, i; + char lbuf[SZ_LINE+1], *fname; + + /* Initialize the config table. */ + for (i=0; i < MAX_FBCONFIG; i++) + fb_config[i].nframes = 0; + + /* Attempt to open the config file. */ + fp = NULL; + if ((fname=getenv(FBCONFIG_ENV1)) || (fname=getenv(FBCONFIG_ENV2))) + fp = fopen (fname, "r"); + if (!fp && (fname = getenv ("HOME"))) { + sprintf (lbuf, "%s/%s", fname, FBCONFIG_1); + fp = fopen (fname = lbuf, "r"); + } + if (!fp) + fp = fopen (fname = FBCONFIG_2, "r"); + + /* If cannot find a config file, set up the default configuration. */ + if (!fp) { + fb_config_index = fbconfig = 0; + fb_nconfig = DEF_NCONFIG; + fb_config[0].nframes = DEF_NFRAMES; + fb_config[0].width = DEF_FRAME_WIDTH; + fb_config[0].height = DEF_FRAME_HEIGHT; + return; + } + + /* Scan the frame buffer configuration file. + */ + fb_nconfig = 0; + while (fgets (lbuf, SZ_LINE, fp) != NULL) { + /* Skip comment lines and blank lines. */ + for (ip=lbuf; *ip == ' ' || *ip == '\t'; ip++) + ; + if (*ip == '\n' || *ip == '#') + continue; + if (!isdigit (*ip)) + continue; + switch (sscanf (ip, "%d%d%d%d", &config,&nframes,&width,&height)) { + case 4: + break; /* normal case */ + case 3: + height = width; /* default to square format */ + break; + default: + fprintf (stderr, "imtool: bad config `%s'\n", ip); + continue; + } + + nframes = max (1, nframes); + width = max (1, width); + height = max (1, height); + + /* Since the frame buffer is stored in a memory pixrect + * (effectively), the line length should be an integral number + * of 16 bit words. + */ + if (width & 1) { + fprintf (stderr, "imtool warning: fb config %d [%d-%dx%d] - ", + config, nframes, width, height); + fprintf (stderr, "frame width should be even, reset to %d\n", + --width); + } + + config = max(1, min(MAX_FBCONFIG, config)) - 1; + fb_config[config].nframes = nframes; + fb_config[config].width = width; + fb_config[config].height = height; + fb_nconfig = max (fb_nconfig, config+1); + } + + fclose (fp); +} + + +/* SET_FBCONFIG -- Setup a frame buffer configuration. + */ +static +set_fbconfig (config, nframes) +int config; +int nframes; +{ + register struct pixrect *pr = get_screen_rect(); + int old_config = fb_config_index; + int old_nframes = fb_nframes; + char text[SZ_LINE]; + + if (config < 0 || config >= fb_nconfig) { + fprintf (stderr, + "imtool: no such frame buffer configuration - %d\n", config+1); + return; + } else if (nframes <= 0) + nframes = fb_config[config].nframes; + + if (init_framebuffers (config, nframes) == -1) { + fprintf (stderr, "restore configuration %d\n", old_config + 1); + if (init_framebuffers (old_config, old_nframes) == -1) { + fprintf (stderr, + "cannot restore frame buffer configuration - imtool dies\n"); + exit (1); + } + } + + if (gio_xsize <= 0 || gio_xsize > Fb_width) + gio_xsize = Fb_width; + if (gio_ysize <= 0 || gio_ysize > (Fb_height + cb_height)) + gio_ysize = Fb_height + cb_height; + + gio_xsize = min (pr->pr_width - TOOL_BORDERWIDTH * 2, gio_xsize); + gio_ysize = min (pr->pr_height + - tool_headerheight ((int)window_get(gio_frame,FRAME_SHOW_LABEL)) + - TOOL_BORDERWIDTH, gio_ysize); + + window_set (gio_canvas, + WIN_WIDTH, gio_xsize, + WIN_HEIGHT, gio_ysize, + 0); + + window_fit (gio_canvas); + window_fit (gio_frame); + + Bpw_get_region_rect (gio_pw, &pw_rect); + pw_rect.r_left = df_p->fb_xoff; + pw_rect.r_top = df_p->fb_yoff; + + sprintf (text, "Frame buffer configuration %d: %d %dx%d frame%c", + fb_config_index + 1, fb_nframes, Fb_width, Fb_height, + fb_nframes > 1 ? 's' : ' '); + + window_set (gio_frame, FRAME_LABEL, text, 0); + panel_set_value (pan_set_maptype, df_p->fb_maptype); + panel_set_value (pan_set_nframes, fb_nframes - 1); +} + + +/* LOAD_RASTER -- Load a rasterfile into the display. + */ +static +load_raster (o_pr, fname) +Pixrect *o_pr; +char *fname; +{ + FILE *fp; + Pixrect *i_pr; + int width, height; + + if ((fp = fopen (fname, "r")) == NULL) + fprintf (stderr, "cannot open rasterfile %s\n", fname); + else { + if (i_pr = pr_load (fp, NULL)) { + width = min (Fb_width, i_pr->pr_width); + height = min (Fb_height, i_pr->pr_height); + pr_rop (o_pr, 0, 0, width, height, PIX_SRC, i_pr, 0, 0); + pr_close (i_pr); + repaint (P_IMAGE|P_COLORBAR|P_GRAPHICS); + } + fclose (fp); + } +} + + +/* SAVE_RASTER -- Save a frame buffer in a file. + */ +static +save_raster (i_pr, fname) +Pixrect *i_pr; +char *fname; +{ + FILE *fp; + + if ((fp = fopen (fname, "w")) == NULL) + fprintf (stderr, "cannot create rasterfile %s\n", fname); + else { + if (pr_dump (i_pr, fp, RMT_NONE, RT_STANDARD, 0) == PIX_ERR) + fprintf (stderr, "error writing rasterfile %s\n", fname); + fclose (fp); + } +} + + +/* CREATE_GIO_CANVAS -- Set up the canvas for the main display window. + */ +static +create_gio_canvas (argc, argv) +int argc; +char **argv; +{ + register char *argp; + register int arg; + char pathname[NGREY]; + struct pixwin *pw; + int name; + + /* Override the builtin defaults with the values given by the user + * on the command line, if any. + */ + for (arg=1; arg <= argc && (argp = argv[arg]) != NULL; arg++) { + if (!strcmp (argp, "-Ws") || !strncmp (argp, "-size", 5)) { + gio_xsize = atoi (argv[++arg]) - (TOOL_BORDERWIDTH * 2); + gio_ysize = atoi (argv[++arg]) - + (tool_headerheight ((int) window_get (gio_frame, + FRAME_SHOW_LABEL)) + TOOL_BORDERWIDTH); + } else if (!strncmp (argp, "-maptype", 4)) { + argp = argv[++arg]; + if (!strncmp (argp, "mono", 1)) + maptype = MONO; + else if (!strncmp (argp, "heat", 1)) + maptype = HEAT; + else if (!strncmp (argp, "ramp1", 1)) + maptype = RAMP1; + else if (!strncmp (argp, "ramp2", 1)) + maptype = RAMP2; + else if (!strncmp (argp, "halley", 1)) + maptype = HALLEY; + else if (!strncmp (argp, "linear", 1)) + maptype = LINEARPS; + else if (!strncmp (argp, "random", 1)) + maptype = RANDOMPS; + else if (!strncmp (argp, "crandom", 1)) + maptype = CRANDOMPS; + else if (!strncmp (argp, "ulut1", 1)) + maptype = ULUT1; + else if (!strncmp (argp, "ulut2", 1)) + maptype = ULUT2; + else + fprintf (stderr, "unknown arg `%s' to -maptype\n", argp); + } else if (!strncmp (argp, "-nocolorbar", 9)) { + cb_height = 0; + show_colorbar = 0; + } else if (!strncmp (argp, "-colorbar", 7)) { + cb_height = SZ_COLORBAR; + show_colorbar = 1; + } else if (!strncmp (argp, "-black", 3)) { + background = CMS_BACKGROUND; + fb_bkgcolor_index = BKG_BLACK; + } else if (!strncmp (argp, "-white", 3)) { + background = 0; + fb_bkgcolor_index = BKG_WHITE; + + } else if (!strncmp (argp, "-rtype", 3)) { + argp = argv[++arg]; + r_type = (argp[0] == 'r'); + } else if (!strncmp (argp, "-rdispose", 3)) { + argp = argv[++arg]; + strcpy (r_dispose, argp); + } else if (!strncmp (argp, "-rfilename", 3)) { + argp = argv[++arg]; + strcpy (r_filename, argp); + } else if (!strncmp (argp, "-ulut1", 6)) { + argp = argv[++arg]; + strcpy (u_lut1, argp); + } else if (!strncmp (argp, "-ulut2", 6)) { + argp = argv[++arg]; + strcpy (u_lut2, argp); + } + } + + /* Open display canvas. The display canvas is never retained at the + * pixwin level since we can easily refresh it from the frame buffer. + */ + gio_canvas = window_create (gio_frame, CANVAS, + WIN_WIDTH, gio_xsize, + WIN_HEIGHT, gio_ysize, + CANVAS_RETAINED, FALSE, + CANVAS_AUTO_CLEAR, FALSE, + CANVAS_REPAINT_PROC, refresh_display, + 0); + if (gio_canvas == NULL) + exit (1); + + /* Initialize the frame and lut parameters and the canvax pixwin + * color map. + */ + pw = (struct pixwin *) window_get (gio_canvas, WIN_PIXWIN); + fb_depth = pw->pw_pixrect->pr_depth; + if (fb_depth < 8) { + fprintf (stderr, "imtool cannot be used on monochrome displays\n"); + exit (1); + } + + white = (1 << fb_depth) - 1; + if ((fb_ngrey = CMS_DATARANGE) > (white + 1)) + fb_ngrey = 1; + init_colormap (pw); + init_colormap (gio_pw = canvas_pixwin (gio_canvas)); + + /* Set input event flags. */ + window_set (gio_canvas, + WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS, + WIN_MOUSE_BUTTONS, WIN_UP_EVENTS, LOC_DRAG, LOC_WINEXIT, 0, + WIN_CONSUME_KBD_EVENTS, WIN_NO_EVENTS, + WIN_ASCII_EVENTS, WIN_LEFT_KEYS, WIN_RIGHT_KEYS, + KEY_SETUP, KEY_REMARK, KEY_SNAP, KEY_PCOORDS, KBD_DONE, 0, + 0); + + notify_set_event_func (ev_panner, ev_panner, NOTIFY_SAFE); +} + + +/* CREATE_SETUP_POPUP -- Create the popup menu used to set the terminal + * setup options. + */ +static +create_setup_popup () +{ + extern loadframe_proc(), saveframe_proc(), fitframe_proc(); + extern reset_proc(), iclear_proc(), gclear_proc(); + extern setup_proc(), toggle_graphics(), set_background(); + extern setframe_proc(), blinkenable_proc(), register_proc(); + static Panel_setting set_ofname(), set_rfname(); + static Panel_setting set_rtype(), set_rdispose(), set_rfilename(); + static Panel_setting set_ulut1(), set_ulut2(); + static Panel_setting set_blinklist(), set_zoomslist(); + static panel_set_item(); + + setup_frame = window_create (gio_frame, FRAME, + FRAME_NO_CONFIRM, TRUE, + WIN_X, setup_xoff, + WIN_Y, setup_yoff, + 0); + if (setup_frame == NULL) + exit (1); + setup_panel = window_create (setup_frame, PANEL, 0); + if (setup_panel == NULL) + exit (1); + + panel_create_item (setup_panel, PANEL_MESSAGE, + PANEL_ITEM_X, ATTR_COL(10), + PANEL_ITEM_Y, ATTR_ROW(0), + PANEL_LABEL_STRING, "Image Display Setup and Control", + 0); + + pan_set_nframes = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(1) + 5, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Number of frame buffers: ", + PANEL_CHOICE_STRINGS, FRAME_CHOICES, 0, + PANEL_VALUE, fb_nframes - 1, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_set_maptype = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(2) + 5, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Greyscale mapping: ", + PANEL_CHOICE_STRINGS, "Mono", + "ESO-Heat", + "Ramp1", + "Ramp2", + "Halley", + "Linear-pseudo", + "Random-pseudo", + "Crandom-pseudo", + "User 1", + "User 2", + 0, + PANEL_VALUE, maptype, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_set_ulut1 = panel_create_item (setup_panel, PANEL_TEXT, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(3) + 8, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "User lookup table 1: ", + PANEL_VALUE, u_lut1, + PANEL_VALUE_STORED_LENGTH, SZ_FNAME, + PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, + PANEL_NOTIFY_PROC, set_ulut1, + 0); + + pan_set_ulut2 = panel_create_item (setup_panel, PANEL_TEXT, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(4) + 8, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "User lookup table 2: ", + PANEL_VALUE, u_lut2, + PANEL_VALUE_STORED_LENGTH, SZ_FNAME, + PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, + PANEL_NOTIFY_PROC, set_ulut2, + 0); + + pan_globalcolor = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(5) + 8, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Globally manage colortable: ", + PANEL_CHOICE_STRINGS, "No", "Yes", 0, + PANEL_VALUE, global_colortable, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_crandom_rate = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(6) + 8, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Rate (sec) for crandom option: ", + PANEL_CHOICE_STRINGS, CRANDOM_CHOICES, 0, + PANEL_VALUE, crandom_blink_rate, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_set_background = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(7) + 8, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Background color: ", + PANEL_CHOICE_STRINGS, "white", "black", 0, + PANEL_VALUE, fb_bkgcolor_index, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_snapframetoo = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(8) + 8, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Include frame border in imcopy: ", + PANEL_CHOICE_STRINGS, "No", "Yes", 0, + PANEL_VALUE, snap_frame_too, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_show_colorbar = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(9) + 8, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Show colorbar: ", + PANEL_CHOICE_STRINGS, "No", "Yes", 0, + PANEL_VALUE, show_colorbar, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_set_marker = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(10) + 8, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Cursor marker: ", + PANEL_CHOICE_STRINGS, "None", "Circle", "Cross", "Square", 0, + PANEL_VALUE, marktype, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_blink_rate = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(11) + 8, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Blink rate (sec): ", + PANEL_CHOICE_STRINGS, BLINKRATE_CHOICES, 0, + PANEL_VALUE, blink_rate_index, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + pan_blink_list = panel_create_item (setup_panel, PANEL_TEXT, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(12) + 11, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Frames to be blinked: ", + PANEL_VALUE, s_blinklist, + PANEL_VALUE_STORED_LENGTH, SZ_FNAME, + PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, + PANEL_NOTIFY_PROC, set_blinklist, + 0); + + pan_zoom_list = panel_create_item (setup_panel, PANEL_TEXT, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(13) + 11, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Zoom factors: ", + PANEL_VALUE, s_zoomslist, + PANEL_VALUE_STORED_LENGTH, SZ_FNAME, + PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, + PANEL_NOTIFY_PROC, set_zoomslist, + 0); + + strcpy (o_fname, COORDFILE); + pan_set_ofname = panel_create_item (setup_panel, PANEL_TEXT, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(14) + 11, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Coordinate list output file: ", + PANEL_VALUE, o_fname, + PANEL_VALUE_STORED_LENGTH, SZ_FNAME, + PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, + PANEL_NOTIFY_PROC, set_ofname, + 0); + + pan_set_rfname = panel_create_item (setup_panel, PANEL_TEXT, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(15) + 11, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Rasterfile name (load/save): ", + PANEL_VALUE, rasterfile, + PANEL_VALUE_STORED_LENGTH, SZ_FNAME, + PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, + PANEL_NOTIFY_PROC, set_rfname, + 0); + + pan_set_rtype = panel_create_item (setup_panel, PANEL_CYCLE, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(16) + 13, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Screendump output type: ", + PANEL_CHOICE_STRINGS, "postscript", "rasterfile", 0, + PANEL_VALUE, r_type, + PANEL_NOTIFY_PROC, panel_set_item, + 0); + + + pan_set_rdispose = panel_create_item (setup_panel, PANEL_TEXT, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(17) + 13, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Screendump dispose command: ", + PANEL_VALUE, r_dispose, + PANEL_VALUE_STORED_LENGTH, SZ_FNAME, + PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, + PANEL_NOTIFY_PROC, set_rdispose, + 0); + + pan_set_rfilename = panel_create_item (setup_panel, PANEL_TEXT, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(18) + 11, + PANEL_DISPLAY_LEVEL, PANEL_CURRENT, + PANEL_LABEL_STRING, "Screendump output file: ", + PANEL_VALUE, r_filename, + PANEL_VALUE_STORED_LENGTH, SZ_FNAME, + PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, + PANEL_NOTIFY_PROC, set_rfilename, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(19) + 15, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel,"Register Frames",0,0), + PANEL_NOTIFY_PROC, register_proc, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Fit Window", 0,0), + PANEL_NOTIFY_PROC, fitframe_proc, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Blink", 0,0), + PANEL_NOTIFY_PROC, blinkenable_proc, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Frame", 0,0), + PANEL_NOTIFY_PROC, setframe_proc, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_ITEM_X, ATTR_COL(0), + PANEL_ITEM_Y, ATTR_ROW(20) + 15, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Reset", 0,0), + PANEL_NOTIFY_PROC, reset_proc, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Iclear", 0,0), + PANEL_NOTIFY_PROC, iclear_proc, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Gclear", 0,0), + PANEL_NOTIFY_PROC, gclear_proc, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Load", 0,0), + PANEL_NOTIFY_PROC, loadframe_proc, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "Save", 0,0), + PANEL_NOTIFY_PROC, saveframe_proc, + 0); + + panel_create_item (setup_panel, PANEL_BUTTON, + PANEL_LABEL_IMAGE, + panel_button_image (setup_panel, "DISMISS", 0,0), + PANEL_NOTIFY_PROC, setup_proc, + 0); + + window_fit (setup_panel); + window_fit (setup_frame); +} + + +/* PANEL_SET_ITEM -- Called when an item is seleted in the setup panel to + * set the associated global variable and possibly take some action. + */ +static +panel_set_item (item, value) +Panel_item item; +int value; +{ + if (item == pan_set_nframes) { + set_fbconfig (fb_config_index, value + 1); + } else if (item == pan_set_maptype) { + df_p->fb_maptype = maptype = value; + set_colortable(); + set_transfer_function (gio_pw, df_p->fb_center, df_p->fb_slope); + } else if (item == pan_crandom_rate) { + crandom_blink_rate = value; + } else if (item == pan_set_marker) { + marktype = value; + } else if (item == pan_blink_rate) { + blink_rate_index = value; + } else if (item == pan_set_rtype) { + r_type = value; + } else if (item == pan_globalcolor) { + global_colortable = value; + + } else if (item == pan_set_background) { + /* Set the background color. + */ + if (fb_bkgcolor_index != value) { + register unsigned char *fb, *op; + register int n = Fb_height * Fb_width; + fb = (unsigned char *) mpr_d(df_p->fb_pr)->md_image; + + switch (fb_bkgcolor_index = value) { + case BKG_BLACK: + background = CMS_BACKGROUND; + for (op=fb; --n >= 0; op++) + if (!*op) + *op = background; + break; + case BKG_WHITE: + background = 0; + for (op=fb; --n >= 0; op++) + if (*op == CMS_BACKGROUND) + *op = 0; + break; + } + gclear_proc(); + } + + } else if (item == pan_show_colorbar) { + if (show_colorbar != value) { + struct pixrect *pr = get_screen_rect(); + + show_colorbar = value; + if (show_colorbar) { + cb_height = SZ_COLORBAR; + gio_ysize += cb_height; + gio_ysize = min (Fb_height + cb_height, gio_ysize); + } else { + cb_height = 0; + gio_ysize -= SZ_COLORBAR; + } + + gio_xsize = + min (pr->pr_width - TOOL_BORDERWIDTH * 2, gio_xsize); + gio_ysize = + min (pr->pr_height - + tool_headerheight ((int) window_get (gio_frame, + FRAME_SHOW_LABEL)) - TOOL_BORDERWIDTH, + gio_ysize); + + window_set (gio_canvas, + WIN_WIDTH,gio_xsize, WIN_HEIGHT,gio_ysize, 0); + + window_fit (gio_canvas); + window_fit (gio_frame); + } + + } else if (item == pan_snapframetoo) + snap_frame_too = value; +} + + +/* SET_ZOOMSLIST -- Set the list of zoom factors. + */ +static Panel_setting +set_zoomslist (item, event) +Panel_item item; +Event *event; +{ + register char *ip; + register int i; + + strcpy (s_zoomslist, (char *) panel_get_value (item)); + for (ip=s_zoomslist; isspace (*ip); ip++) + ; + + nzooms = 0; + while (*ip && isdigit (*ip)) { + zooms[nzooms++] = max (1, atoi(ip)); + while (isdigit (*ip)) + ip++; + while (isspace (*ip)) + ip++; + if (nzooms >= MAX_ZOOMS) + break; + } + + return (panel_text_notify (item,event)); +} + + +/* SET_BLINKLIST -- Set the list of frames to be blinked. + */ +static Panel_setting +set_blinklist (item, event) +Panel_item item; +Event *event; +{ + register char *ip; + register int i; + + strcpy (s_blinklist, (char *) panel_get_value (item)); + for (ip=s_blinklist; isspace (*ip); ip++) + ; + + n_blink_frames = 0; + if (strncmp (ip, "all", 3) == 0) { + n_blink_frames = MAX_FRAMES; + for (i=0; i < MAX_FRAMES; i++) + blink_frames[i] = i + 1; + } else { + while (*ip && isdigit (*ip)) { + blink_frames[n_blink_frames++] = atoi(ip); + while (isdigit (*ip)) + ip++; + while (isspace (*ip)) + ip++; + } + } + + return (panel_text_notify (item,event)); +} + + +/* BLINKENABLE_PROC -- Turn frame blink on or off. + */ +static +blinkenable_proc() +{ + blink = !blink; + menu_set (blink_item, MENU_STRING, blink ? "Blink off" : "Blink on", 0); + blink_frame = n_blink_frames - 1; + blink_timer = 0; +} + + +/* REGISTER_PROC -- Register all frames with the current frame. + */ +static +register_proc() +{ + register struct framebuf *fr_p; + register int i; + + for (i=0, fr_p=frames; i < fb_nframes; i++, fr_p++) + if (fr_p != df_p) + set_zoom (fr_p, df_p->fb_xoff, df_p->fb_yoff, df_p->fb_xzoom); +} + + +/* SET_OFNAME -- Set the file name for coordinate output. + */ +static Panel_setting +set_ofname (item, event) +Panel_item item; +Event *event; +{ + char *s; + + s = (char *) panel_get_value (item); + if (strcmp (s, o_fname)) { + strcpy (o_fname, s); + df_p->fb_imageno = 0; + df_p->fb_objno = 1; + window_set (gio_frame, FRAME_LABEL, framelabel(), 0); + } + + return (panel_text_notify (item,event)); +} + + +/* SET_ULUT1 -- Set the file name for user lookup table 1. + */ +static Panel_setting +set_ulut1 (item, event) +Panel_item item; +Event *event; +{ + char *s; + + strcpy (u_lut1, (char *) panel_get_value (item)); + return (panel_text_notify (item,event)); +} + + +/* SET_ULUT2 -- Set the file name for user lookup table 2. + */ +static Panel_setting +set_ulut2 (item, event) +Panel_item item; +Event *event; +{ + char *s; + + strcpy (u_lut2, (char *) panel_get_value (item)); + return (panel_text_notify (item,event)); +} + + +/* SET_RFNAME -- Set the file name for rasterfile load/save. + */ +static Panel_setting +set_rfname (item, event) +Panel_item item; +Event *event; +{ + char *s; + + strcpy (rasterfile, (char *) panel_get_value (item)); + return (panel_text_notify (item,event)); +} + + +/* SET_RDISPOSE -- Set the raster file dispose command. + */ +static Panel_setting +set_rdispose (item, event) +Panel_item item; +Event *event; +{ + char *s; + + strcpy (r_dispose, (char *) panel_get_value (item)); + return (panel_text_notify (item,event)); +} + + +/* SET_RFILENAME -- Set the screendump filename template. + */ +static Panel_setting +set_rfilename (item, event) +Panel_item item; +Event *event; +{ + char *s; + + strcpy (r_filename, (char *) panel_get_value (item)); + return (panel_text_notify (item,event)); +} + + +/* LOADFRAME_PROC -- Load the named rasterfile into the current frame. + */ +static +loadframe_proc() +{ + char fname[SZ_FNAME+1]; + char buf[SZ_FNAME+1]; + + sprintf (buf, rasterfile, df_p->fb_frameno, df_p->fb_imageno); + strcpy (fname, getfname(buf, 0)); + load_raster (df_p->fb_pr, fname); +} + + +/* SAVEFRAME_PROC -- Save the current frame in the named rasterfile. + */ +static +saveframe_proc() +{ + char fname[SZ_FNAME+1]; + char buf[SZ_FNAME+1]; + + sprintf (buf, rasterfile, df_p->fb_frameno, df_p->fb_imageno); + strcpy (fname, getfname(buf, 0)); + save_raster (df_p->fb_pr, fname); +} + + +/* FITFRAME_PROC -- Fit the display window to the current frame buffer size. + */ +static +fitframe_proc() +{ + register struct pixrect *pr = get_screen_rect(); + + gio_xsize = min (pr->pr_width - TOOL_BORDERWIDTH * 2, Fb_width); + gio_ysize = min (pr->pr_height + - tool_headerheight ((int)window_get(gio_frame,FRAME_SHOW_LABEL)) + - TOOL_BORDERWIDTH, + Fb_height + cb_height); + + window_set (gio_canvas, + WIN_WIDTH, gio_xsize, + WIN_HEIGHT, gio_ysize, + 0); + + window_fit (gio_canvas); + window_fit (gio_frame); +} + + +/* GET_SCREEN_RECT -- Determine the size of the workstation screen. + */ +static struct pixrect * +get_screen_rect() +{ + static struct pixrect screen; + struct pixrect *pr; + + if (!screen.pr_width) + if (pr = pr_open ("/dev/fb")) { + screen = *pr; + pr_close (pr); + } else { + screen.pr_width = 1152; + screen.pr_width = 900; + } + + return (&screen); +} + + +/* SETUP_PROC -- Toggle whether or not the setup panel is shown. + */ +static +setup_proc() +{ + if ((int) window_get (setup_frame, WIN_SHOW) == TRUE) { + setup_xoff = (int) window_get (setup_frame, WIN_X, 0); + setup_yoff = (int) window_get (setup_frame, WIN_Y, 0); + window_set (setup_frame, WIN_SHOW, FALSE, 0); + } else { + window_set (setup_frame, + WIN_X, setup_xoff, + WIN_Y, setup_yoff, + 0); + window_set (setup_frame, WIN_SHOW, TRUE, 0); + } +} + + +/* CREATE_FRAME_MENU -- Imtool uses a special frame menu which provides the + * standard frame menu as a submenu. + */ +static +create_frame_menu (frame) +Frame frame; +{ + extern imagecopy_proc(), register_proc(); + extern setup_proc(), setframe_proc(), fitframe_proc(); + extern iclear_proc(), gclear_proc(), blinkenable_proc(); + Menu new_menu, old_menu; + + /* Get the standard frame menu. */ + old_menu = (Menu) window_get (frame, WIN_MENU); + + /* Create the new frame root menu */ + new_menu = menu_create ( + MENU_PULLRIGHT_ITEM, + "Frame", + old_menu, + MENU_ACTION_ITEM, + "Setup", + setup_proc, + MENU_ACTION_ITEM, + "Register", + register_proc, + MENU_ACTION_ITEM, + "Blink on", + blinkenable_proc, + MENU_ACTION_ITEM, + "FitFrame", + fitframe_proc, + MENU_ACTION_ITEM, + "NextFrame", + setframe_proc, + MENU_ACTION_ITEM, + "Gclear", + gclear_proc, + MENU_ACTION_ITEM, + "Iclear", + iclear_proc, + MENU_ACTION_ITEM, + "Imcopy", + imagecopy_proc, + 0); + + blink_item = menu_find (new_menu, MENU_STRING, "Blink on", 0); + + /* Install the new menu. */ + window_set (frame, WIN_MENU, new_menu, 0); +} + + +/* INIT_FRAMEBUFFERS -- Allocate space for the indicated number and size of + * framebuffers, initializing the framebuffer data structures accordingly. + * If at least one frame buffer of the desired size can be allocated we + * consider it a success, but set fb_nframes accordingly. -1 is returned + * if no frames of the desired size can be allocated. + */ +static +init_framebuffers (config, nframes) +int config; /* new frame buffer configuration */ +int nframes; /* desired number of frames */ +{ + register struct framebuf *fb; + register int i; + char *calloc(); + + nframes = min (MAX_FRAMES, nframes); + + /* If we are only changing the number of frames in the current + * configuration, keep the old frames. + */ + if (frames && config == fb_config_index) { + if (nframes == fb_config[config].nframes) { + fb_nframes = nframes; + return (nframes); + + } else if (nframes < fb_config[config].nframes) { + for (i=nframes; i < fb_nframes; i++) + pr_close (frames[i].fb_pr); + fb_config[config].nframes = fb_nframes = nframes; + if (reference_frame > nframes) { + reference_frame = nframes; + rf_p = frames + (reference_frame - 1); + } + if (display_frame > nframes) + set_frame (nframes); + return (nframes); + + } else if (nframes > fb_config[config].nframes) + ; /* fall through and add more frames */ + + } else { + /* Deallocate old frame buffers, if any. */ + if (frames) { + pr_close (cb_pr); + for (i=0; i < fb_nframes; i++) + pr_close (frames[i].fb_pr); + free (frames); + } + + fb_nframes = 0; + frames = (struct framebuf *) calloc (MAX_FRAMES, + sizeof(struct framebuf)); + + df_p = rf_p = frames; + display_frame = reference_frame = 1; + strcpy (o_fname, COORDFILE); + wc_xoff = wc_yoff = 0; + } + + /* Allocate and initialize the new frame buffers. */ + fb_config_index = config; + Fb_width = fb_config[config].width; + Fb_height = fb_config[config].height; + + for (i=fb_nframes; i < nframes; i++) { + fb = frames + i; + fb->fb_pr = mem_create (Fb_width, Fb_height, fb_depth); + if (fb->fb_pr == NULL) { + fprintf (stderr, + "attempt to allocate frame buffer %d (%dx%d) fails\n", + i + 1, Fb_width, Fb_height); + if (i) + break; + else + return (-1); + } else if (!fb_nframes++) { + cb_pr = mem_create (Fb_width, cb_height, fb_depth); + if (pw_rect.r_width) + init_colorbar (pw_rect.r_width); + } + + fb->fb_xoff = 0; + fb->fb_yoff = 0; + fb->fb_xzoom = fb->fb_yzoom = 1; + fb->fb_center = fb_ngrey / 2.0; + fb->fb_slope = (float)white / (float)(fb_ngrey - 1); + fb->fb_maptype = maptype; + fb->fb_objno = 1; + fb->fb_imageno = 0; + fb->fb_frameno = i + 1; + fb->fb_ctran.valid = 0; + fb->fb_ctran.imtitle[0] = '\0'; + strcpy (fb->fb_ctran.format, W_DEFFORMAT); + } + + set_zoom (df_p, 0, 0, 1); + return (fb_config[config].nframes = fb_nframes); +} + + +/* INIT_COLORBAR -- Write the colorbar into the frame buffer. The length of + * the colorbar should correspond to the current width of the display window, + * but must not exceed the width of the frame buffer. + */ +init_colorbar (cb_width) +int cb_width; +{ + register int i; + unsigned char *lp; + Pixrect *pr; + + if (cb_height <= 0) + return; + + if ((pr = mem_create (cb_width, 1, fb_depth)) != NULL) { + lp = (unsigned char *) mpr_d(pr)->md_image; + /* Write colorbar. */ + for (i=0; i < cb_width; i++) + lp[i] = (CMS_DATARANGE-1) * i / (cb_width-1) + + CMS_DATASTART; + for (i=3; i < cb_height; i++) + pr_rop (cb_pr, 0, i, cb_width, 1, PIX_SRC, pr, 0, 0); + + /* Add a border between image and colorbar. */ + for (i=0; i < cb_width; i++) + lp[i] = NGREY-1; + for (i=0; i < 3; i++) + pr_rop (cb_pr, 0, i, cb_width, 1, PIX_SRC, pr, 0, 0); + + for (i=0; i < cb_width; i++) + lp[i] = 0; + for (i=1; i < 2; i++) + pr_rop (cb_pr, 0, i, cb_width, 1, PIX_SRC, pr, 0, 0); + + pr_close (pr); + } +} + + +/* INIT_COLORMAP -- Initialize the IMTOOL color map. + */ +static +init_colormap (pw) +struct pixwin *pw; +{ + register unsigned char *r = red; + register unsigned char *g = green; + register unsigned char *b = blue; + int planes = NGREY-1, i; + + /* Initialize the IMTOOL colormap from the current fullscreen + * colormap, so that the (small) colormap entries of the other + * windows will be preserved, as far as possible. + */ + grab_colormap (r, g, b); + + /* Set a linear transfer function for the main part of the table. */ + for (i=CMS_DATASTART; i <= CMS_DATAEND; i++) + r[i] = g[i] = b[i] = i * (white + 1) / CMS_DATARANGE; + + /* Color table entry for the cursor. */ + r[CMS_CURSOR] = white; + g[CMS_CURSOR] = white; + b[CMS_CURSOR] = white; + + /* Set the background and graphics colors. + */ + i = CMS_BACKGROUND; + r[i] = 0; g[i] = 0; b[i] = 0; i++; /* 202=black */ + + i = CMS_GRAPHICSSTART; + r[i] = 255; g[i] = 255; b[i] = 255; i++; /* 203=white */ + + r[i] = 255; g[i] = 0; b[i] = 0; i++; /* 204=red */ + r[i] = 0; g[i] = 255; b[i] = 0; i++; /* 205=green */ + r[i] = 0; g[i] = 0; b[i] = 255; i++; /* 206=blue */ + r[i] = 255; g[i] = 255; b[i] = 0; i++; /* 207=yellow */ + r[i] = 0; g[i] = 255; b[i] = 255; i++; /* 208=cyan */ + r[i] = 255; g[i] = 0; b[i] = 255; i++; /* 209=magenta */ + r[i] = 255; g[i] = 127; b[i] = 0; i++; /* 210=coral */ + r[i] = 142; g[i] = 35; b[i] = 107; i++; /* 211=maroon */ + r[i] = 204; g[i] = 50; b[i] = 50; i++; /* 212=orange */ + r[i] = 159; g[i] = 159; b[i] = 95; i++; /* 213=khaki */ + r[i] = 219; g[i] = 112; b[i] = 219; i++; /* 214=orchid */ + r[i] = 112; g[i] = 219; b[i] = 219; i++; /* 215=turquoise */ + r[i] = 159; g[i] = 95; b[i] = 159; i++; /* 216=violet */ + r[i] = 216; g[i] = 216; b[i] = 191; i++; /* 217=wheat */ + + pw_setcmsname (pw, CMMAPNAME); + pw_putcolormap (pw, 0, NGREY, r, g, b); + pw_putattributes (pw, &planes); +} + + +/* COMPUTE_TRANSFER_FUNCTION -- Compute the slope and offset of the transfer + * function for the current display frame, given the coordinates of the + * mouse in the frame. + */ +static +compute_transfer_function (event) +Event *event; +{ + float xsize, ysize; + float y, slope; + int neg; + + xsize = pw_rect.r_width; + ysize = pw_rect.r_height; + + /* Compute the slope of the transfer function. */ + y = event_y(event) / ysize * 2.0 - 1.0; + if (neg = (y < 0.0)) + y = -y; + if (y > 0.99) + y = 0.99; + if ((slope = tan (y * M_PI_2)) > white) + slope = white; + + /* Record new transfer function in frame buffer descriptor. */ + df_p->fb_center = event_x(event) / xsize * (fb_ngrey-1); + df_p->fb_slope = neg ? -slope : slope; +} + + +/* SET_TRANSFER_FUNCTION -- Load the color map as necessary to implement the + * given linear transfer function. + */ +static +set_transfer_function (pw, center, slope) +struct pixwin *pw; /* reference pixwin */ +float center; /* greyscale value at half intensity */ +float slope; /* delta-intensity per greyscale unit */ +{ + register int i; + register float z, zmin, zmax; + unsigned char o_red[NGREY], o_green[NGREY], o_blue[NGREY]; + unsigned char *p_r, *p_g, *p_b; + + if (center < CMS_DATASTART) + center = CMS_DATASTART; + else if (center > CMS_DATAEND) + center = CMS_DATAEND; + + zmin = 0.0; + zmax = white; + + z = white / 2; + for (i=center; i <= CMS_DATAEND; i++) { + o_red[i] = m_red[(unsigned char)(int)z]; + o_green[i] = m_green[(unsigned char)(int)z]; + o_blue[i] = m_blue[(unsigned char)(int)z]; + z += slope; + if (z <= zmin) + z = zmin; + else if (z >= zmax) + z = zmax; + } + + z = white / 2; + for (i=center; i >= CMS_DATASTART; i--) { + o_red[i] = m_red[(unsigned char)(int)z]; + o_green[i] = m_green[(unsigned char)(int)z]; + o_blue[i] = m_blue[(unsigned char)(int)z]; + z -= slope; + if (z <= zmin) + z = zmin; + else if (z >= zmax) + z = zmax; + } + + p_r = &o_red[CMS_DATASTART]; + p_g = &o_green[CMS_DATASTART]; + p_b = &o_blue[CMS_DATASTART]; + + /*pw_putcolormap (pw, CMS_DATASTART, CMS_DATARANGE, p_r, p_g, p_b);*/ + + bcopy (p_r, &red[CMS_DATASTART], CMS_DATARANGE); + bcopy (p_g, &green[CMS_DATASTART], CMS_DATARANGE); + bcopy (p_b, &blue[CMS_DATASTART], CMS_DATARANGE); + + /* Reset the full 8 bit colormap for the pixwin, to pick up any + * changes made in the unused regions for other windows, picked up + * by edit_colortable below. + */ + pw_putcolormap (pw, 0, NGREY, red, green, blue); +} + + +/* SET_COLORTABLE -- Set up the RGB lookup tables used to map the windowed + * monochrome output of a frame buffer into the hardware colormap. + */ +static Notify_value +set_colortable() +{ + register int v, vsat, step, i; + static int seed = 0; + int knot[7]; + + vsat = NGREY - 1; + step = NGREY / 6; + for (i=0; i < 7; i++) + knot[i] = i * step; + knot[6] = vsat; + + switch (df_p->fb_maptype) { + case MONO: + for (i=0; i < NGREY; i++) + m_red[i] = m_green[i] = m_blue[i] = i; + break; + + case HEAT: + for (i=0; i < NGREY; i++) { + m_red[i] = heat.hue[i].red * (NGREY - 1); + m_green[i] = heat.hue[i].green * (NGREY - 1); + m_blue[i] = heat.hue[i].blue * (NGREY - 1); + } + break; + + case RAMP1: + for (i=0; i < NGREY; i++) { + m_red[i] = heat.hue[i].red * NGREY; + m_green[i] = heat.hue[i].green * NGREY; + m_blue[i] = heat.hue[i].blue * NGREY; + } + break; + + case RAMP2: + for (i=0; i < NGREY; i++) { + m_red[i] = heat.hue[i].red * ((NGREY - 1) * 2); + m_green[i] = heat.hue[i].green * ((NGREY - 1) * 2); + m_blue[i] = heat.hue[i].blue * ((NGREY - 1) * 2); + } + break; + + case HALLEY: + for (i=0; i < NGREY; i++) { + m_red[i] = halley.hue[i].red * (NGREY - 1); + m_green[i] = halley.hue[i].green * (NGREY - 1); + m_blue[i] = halley.hue[i].blue * (NGREY - 1); + } + break; + + case ULUT1: + case ULUT2: + { struct lut user; + struct triplet *p; + int i, j; + FILE *fp; + char *s; + + s = (df_p->fb_maptype == ULUT1) ? u_lut1 : u_lut2; + if ((fp = fopen (getfname(s,0), "r")) == NULL) { + fprintf (stderr, "cannot open %s\n", s); + return; + } + + for (user.lutlen=0; user.lutlen < NGREY; user.lutlen++) { + p = &user.hue[user.lutlen]; + if (fscanf (fp, " %f %f %f", + &p->red, &p->green, &p->blue) == EOF) + break; + } + + for (i=0; i < NGREY; i++) { + j = max(0, min(NGREY-1, (i * user.lutlen / NGREY))); + m_red[i] = user.hue[j].red * (NGREY - 1); + m_green[i] = user.hue[j].green * (NGREY - 1); + m_blue[i] = user.hue[j].blue * (NGREY - 1); + } + + fclose (fp); + } + break; + + case LINEARPS: + for (i=0; i < NGREY; i++) + m_red[i] = m_green[i] = m_blue[i] = 0; + + for (i=knot[0]; i <= knot[1]; i++) + m_blue[i] = vsat * (i - knot[0]) / step; + for (i=knot[1]; i <= knot[2]; i++) + m_blue[i] = vsat; + for (i=knot[2]; i <= knot[3]; i++) + m_blue[i] = vsat * (knot[3] - i) / step; + + for (i=knot[1]; i <= knot[2]; i++) + m_green[i] = vsat * (i - knot[1]) / step; + for (i=knot[2]; i <= knot[4]; i++) + m_green[i] = vsat; + for (i=knot[4]; i <= knot[5]; i++) + m_green[i] = vsat * (knot[5] - i) / step; + + for (i=knot[3]; i <= knot[4]; i++) + m_red[i] = vsat * (i - knot[3]) / step; + for (i=knot[4]; i <= knot[6]; i++) + m_red[i] = vsat; + + for (i=knot[5]; i <= knot[6]; i++) { + if ((v = vsat * (i - knot[5]) / step) > vsat) + v = vsat; + m_green[i] = m_blue[i] = v; + } + break; + + case CRANDOMPS: + set_transfer_function (gio_pw, df_p->fb_center, df_p->fb_slope); + imt_pause (cr_msec[crandom_blink_rate], set_colortable); + /* fall through */ + + case RANDOMPS: + if (!seed) + seed = time(0); + srand (seed++); + for (i=0; i < NGREY; i++) { + m_red[i] = ((rand() >> 4) % NGREY); + m_green[i] = ((rand() >> 4) % NGREY); + m_blue[i] = ((rand() >> 4) % NGREY); + } + break; + } +} + + +/* GRAB_COLORMAP -- Read the current physical full screen colormap. + */ +static +grab_colormap (red, green, blue) +unsigned char red[], green[], blue[]; +{ + struct pixrect *screen; + + if (window_open) { + screen = pr_open ("/dev/fb"); + pr_getcolormap (screen, 0, NGREY, red, green, blue); + pr_close (screen); + } +} + + +/* IMTOOL_CLOCK -- The main imtool clock. + */ +static +imtool_clock (client, event, arg) +Notify_client client; +Notify_event event; +Notify_arg arg; +{ + static int delay=0, interval=0, toggle=0; + Cursor cursor; + int frame, n; + + /* Blink cursor (variable rate). */ + cursor = window_get (gio_canvas, WIN_CURSOR); + toggle = !toggle; + if (reading_imcursor) { + cursor_set (cursor, + CURSOR_OP, toggle + ? PIX_NOT(PIX_SRC) & PIX_DST + : PIX_SRC | PIX_DST | PIX_COLOR(NGREY-1), + 0); + } else { + cursor_set (cursor, + CURSOR_CROSSHAIR_COLOR, + toggle ? CMS_BACKGROUND : CMS_CURSOR, + 0); + } + window_set (gio_canvas, WIN_CURSOR, cursor, 0); + + /* Things that happen at a fixed interval. */ + if ((delay += interval) >= CLOCK_INTERVAL) { + /* Keep imtool visible (if window open). */ + edit_colormap(); + + /* Frame blink. The frames in the blink frame list do not have to + * exist; if not, then advance through the list until either a valid + * frame is found, or the list has been traversed once. + */ + if (blink && n_blink_frames > 0 && state != WINDOW && window_open) { + if (--blink_timer <= 0) { + for (n=n_blink_frames; --n >= 0; ) { + if (++blink_frame >= n_blink_frames) + blink_frame = 0; + frame = blink_frames[blink_frame]; + if (frame >= 1 && frame <= fb_nframes) { + set_frame (frame); + if (display_coords && state == TRACK_CURSOR) + update_coords (NULL); + break; + } + } + blink_timer = blink_rate[blink_rate_index]; + } + } + + delay = 0; + } + + interval = reading_imcursor ? CLOCK_INTERVAL/4 : CLOCK_INTERVAL; + imt_pause (interval, imtool_clock); +} + + +/* EDIT_COLORMAP -- Overwrite the portion of the full screen colormap used + * by the display server. This must be done in such a way that changes to + * the region of the screen colortable used by other windows are preserved. + */ +static +edit_colormap() +{ + struct pixrect *screen; + unsigned char r[NGREY], g[NGREY], b[NGREY]; + + if (state != WINDOW && window_open) { + /* Edit the physical colortable. */ + screen = pr_open ("/dev/fb"); + pr_getcolormap (screen, 0, NGREY, r, g, b); + + /* Make the cursor blink between black and white for better vis. + * (>> now done with set_cursor in imtool_clock()) + if (green[CMS_CURSOR] == white) { + red[CMS_CURSOR] = black; + green[CMS_CURSOR] = black; + blue[CMS_CURSOR] = black; + } else { + red[CMS_CURSOR] = white; + green[CMS_CURSOR] = white; + blue[CMS_CURSOR] = white; + } + */ + + bcopy (&red[CMS_FIRST], &r[CMS_FIRST], CMS_NGREY); + bcopy (&green[CMS_FIRST], &g[CMS_FIRST], CMS_NGREY); + bcopy (&blue[CMS_FIRST], &b[CMS_FIRST], CMS_NGREY); + + pw_putcolormap (gio_pw, 0, NGREY, r, g, b); + if (global_colortable) + pr_putcolormap (screen, 0, NGREY, r, g, b); + pr_close (screen); + + /* Update the canvas pixwin colortable. */ + bcopy (r, red, NGREY); + bcopy (g, green, NGREY); + bcopy (b, blue, NGREY); + } +} + + +/* SHOW_COLORMAP -- Print the contents of the color map for a pixwin. + */ +static +show_colormap (pw, first, last) +struct pixwin *pw; +int first, last; +{ + unsigned char r[NGREY], g[NGREY], b[NGREY]; + char cmsname[CMS_NAMESIZE]; + int i, n; + + pw_getcmsname (pw, cmsname); + pw_getcolormap (pw, 0, NGREY, r, g, b); + + printf ("color map segment = '%s'\n", cmsname); + for (i=first, n=0; i <= last; i++) { + printf ("%3d %3d %3d", r[i], g[i], b[i]); + printf ((++n % 5) ? " " : "\n"); + } + printf ("\n"); +} + + +/* LOAD_TESTPATTERN -- Load a test pattern into the reference frame buffer. + */ +static +load_testpattern (type) +int type; /* pattern type desired */ +{ + register unsigned char *line; + register int i, j, color; + unsigned char *fb, *oline; + + fb = (unsigned char *) mpr_d(df_p->fb_pr)->md_image; + + switch (type) { + case 0: + /* Compute first line. */ + oline = line = fb; + for (i=0, color=0; i < Fb_width; i++) + if (((i+16) % 32) == 0) { + line[i] = 0; + color = ((i+j) % CMS_DATARANGE) / 32 * 32; + } else + line[i] = color; + + /* Compute remaining lines. */ + for (j=1; j < Fb_height; j++) { + line = fb + j * Fb_width; + if (((j+16) % 32) == 0) { + for (i=0; i < Fb_width; i++) + line[i] = 0; + if (++j >= Fb_height) + break; + line = fb + j * Fb_width; + color = (j % CMS_DATARANGE) / 32 * 32; + for (i=0; i < Fb_width; i++) + if (((i+16) % 32) == 0) { + line[i] = 0; + color = ((i+j) % CMS_DATARANGE) / 32 * 32; + } else + line[i] = color; + oline = line; + } else + bcopy (oline, line, Fb_width); + } + break; + + case 1: + for (j=1; j < Fb_height; j++) { + line = fb + j * Fb_width; + for (i=0; i < Fb_width; i++) + line[i] = (i % CMS_DATARANGE); + } + break; + + case 2: + for (j=1; j < Fb_height; j++) { + line = fb + j * Fb_width; + for (i=0; i < Fb_width; i++) + line[i] = ((i+j) % CMS_DATARANGE); + } + break; + } +} + + +/* For the moment we take an IIS model 70 command/data stream as input; this + * is used to load images into the image display. This is a kludge interface + * for the prototype, convenient since the high level software is written for + * the IIS. + */ +#define MEMORY 01 /* frame buffer i/o */ +#define LUT 02 /* lut i/o */ +#define FEEDBACK 05 /* used for frame clears */ +#define IMCURSOR 020 /* logical image cursor */ +#define WCS 021 /* used to set WCS */ + +#define SZ_IMCURVAL 160 +#define PACKED 0040000 +#define COMMAND 0100000 +#define IIS_READ 0100000 +#define IMC_SAMPLE 0040000 +#define IMT_FBCONFIG 077 +#define XYMASK 077777 + +struct iism70 { + short tid; + short thingct; + short subunit; + short checksum; + short x, y, z; + short t; +}; + +/* EV_CMDINPUT -- Called when command or data input has arrived via the + * pseudodevice input stream from some applications process. + */ +static Notify_value +ev_cmdinput (frame, event, arg, type) +Frame frame; +Event *event; +Notify_arg arg; +Notify_event_type type; +{ + register unsigned char *cp; + register int sum, i; + register short *p; + int ndatabytes, nbytes, n, ntrys=0; + static int errmsg=0, bswap=0; + struct iism70 iis; + char buf[SZ_FIFOBUF]; + int fb_index; + + /* Get the IIS header. */ + if (read (datain, (char *)&iis, sizeof(iis)) < sizeof(iis)) { + fprintf (stderr, "imtool: command input read error\n"); + return (NOTIFY_DONE); + } else if (bswap) + bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); + + /* Verify the checksum. If it fails swap the bytes and try again. + */ + for (;;) { + for (i=0, sum=0, p=(short *)&iis; i < 8; i++) + sum += *p++; + if ((sum & 0177777) == 0177777) + break; + + if (ntrys++) { + if (!errmsg++) { + fprintf (stderr, "imtool: bad data header checksum\n"); + if (bswap) + bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); + fprintf (stderr, "noswap:"); + for (i=0, p=(short *)&iis; i < 8; i++) + fprintf (stderr, " %6o", p[i]); + fprintf (stderr, "\n"); + + bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); + fprintf (stderr, " swap:"); + for (i=0, p=(short *)&iis; i < 8; i++) + fprintf (stderr, " %6o", p[i]); + fprintf (stderr, "\n"); + } + break; + + } else { + bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); + bswap = !bswap; + } + } + + ndatabytes = -iis.thingct; + if (!(iis.tid & PACKED)) + ndatabytes *= 2; + + switch (iis.subunit & 077) { + case FEEDBACK: + /* The feedback unit is used only to clear a frame. + */ + set_reference_frame (decode_frameno (iis.z & 07777)); + erase (rf_p); + break; + + case LUT: + /* Data mode writes to the frame lookup tables are not implemented. + * A command mode write to the LUT subunit is used to connect + * image memories up to the RGB channels, i.e., to select the frame + * to be displayed. We ignore any attempt to assign multiple + * frames to multiple color channels, and just do a simple frame + * select. + */ + if (iis.subunit & COMMAND) { + int frame, z, n; + short x[14]; + + if (read (datain, (char *)x, ndatabytes) == ndatabytes) { + if (bswap) + bswap2 ((char *)x, (char *)x, ndatabytes); + + z = x[0]; + if (!z) z = 1; + for (n=0; !(z & 1); z >>= 1) + n++; + + frame = max (1, n + 1); + if (frame > fb_nframes) { + if (frame < MAX_FRAMES) + set_fbconfig (fb_config_index, frame); + else { + fprintf (stderr, "imtool warning: "); + fprintf (stderr, + "attempt to display nonexistent frame %d\n", frame); + frame = fb_nframes - 1; + } + } + + set_frame (frame); + return (NOTIFY_DONE); + } + } + + case MEMORY: + /* Load data into the frame buffer. Data is assumed to be byte + * packed. + */ + if (iis.tid & IIS_READ) { + /* Read from the display. + */ + unsigned char *fb, *ip; + int nbytes, nleft, n, x, y; + long starttime; + + /* Get the frame to be read from. */ + set_reference_frame (decode_frameno (iis.z & 07777)); + + fb = (unsigned char *) mpr_d(rf_p->fb_pr)->md_image; + nbytes = ndatabytes; + x = iis.x & XYMASK; + y = iis.y & XYMASK; + + ip = max (fb, min (fb + Fb_width * Fb_height - nbytes, + fb + y * Fb_width + x)); + if (ip != fb + y * Fb_width + x) { + fprintf (stderr, + "imtool: attempted read out of bounds on framebuf\n"); + fprintf (stderr, + "read %d bytes at [%d,%d]\n", nbytes, x, y); + } + + /* Return the data from the frame buffer. */ + starttime = time(0); + for (nleft = nbytes; nleft > 0; nleft -= n) { + n = (nleft < SZ_FIFOBUF) ? nleft : SZ_FIFOBUF; + if ((n = write (dataout, ip, n)) <= 0) { + if (n < 0 || (time(0) - starttime > IO_TIMEOUT)) { + fprintf (stderr, "IMTOOL: timeout on write\n"); + break; + } + } else + ip += n; + } + + return (NOTIFY_DONE); + + } else { + /* Write to the display. + */ + unsigned char *fb, *op; + int nbytes, nleft, n, x, y; + long starttime; + + /* Get the frame to be written into (encoded with a bit for + * each frame, 01 is frame 1, 02 is frame 2, 04 is frame 3, + * and so on). + */ + set_reference_frame (decode_frameno (iis.z & 07777)); + + /* Get a pointer into the frame buffer where the data will + * be put. + */ + fb = (unsigned char *) mpr_d(rf_p->fb_pr)->md_image; + nbytes = ndatabytes; + x = iis.x & XYMASK; + y = iis.y & XYMASK; + + op = max (fb, min (fb + Fb_width * Fb_height - nbytes, + fb + y * Fb_width + x)); + if (op != fb + y * Fb_width + x) { + fprintf (stderr, + "imtool: attempted write out of bounds on framebuf\n"); + fprintf (stderr, + "write %d bytes to [%d,%d]\n", nbytes, x, y); + } + + /* Read the data into the frame buffer. + */ + starttime = time(0); + for (nleft = nbytes; nleft > 0; nleft -= n) { + n = (nleft < SZ_FIFOBUF) ? nleft : SZ_FIFOBUF; + if ((n = read (datain, op, n)) <= 0) { + if (n < 0 || (time(0) - starttime > IO_TIMEOUT)) + break; + } else { + /* Set any zeroed pixels to the background color, + * if a special background color is specified. + */ + if (background) + for (cp=op, i=n; --i >= 0; cp++) + if (!*cp) + *cp = background; + op += n; + } + } + + /* Refresh the display, if the current display frame is the + * same as the reference frame. + */ + if (rf_p == df_p) { + BRect fb_r, pw_r; + + fb_r.r_left = x * zoom; + fb_r.r_top = y * zoom; + fb_r.r_width = min (nbytes * zoom, fb_width); + fb_r.r_height = ((nbytes*zoom*zoom + fb_width-1)/fb_width); + + Bpw_get_region_rect (gio_pw, &pw_rect); + Bpw_lock (gio_pw, &pw_rect); + + pw_rect.r_left = df_p->fb_xoff; + pw_rect.r_top = df_p->fb_yoff; + + if (maprect (&fb_rect, &fb_r, &pw_rect, &pw_r)) + if (maprect (&pw_rect, &pw_r, &fb_rect, &fb_r)) { + ds_write (gio_pw, + pw_r.r_left, pw_r.r_top, + pw_r.r_width, pw_r.r_height, + PIX_SRC | PIX_COLOR(NGREY-1), + df_p->fb_pr, fb_r.r_left, fb_r.r_top); + + if (pw_r.r_top + pw_r.r_height >= pw_rect.r_height + - cb_height) + put_colorbar(); + } + + Bpw_unlock (gio_pw); + } + + return (NOTIFY_DONE); + } + break; + + case WCS: + /* Read or write the WCS for a frame. The frame number to + * which the WCS applies is passed in Z and the frame buffer + * configuration in T. The client changes the frame buffer + * configuration in a WCS set. The WCS text follows the header + * as byte packed ASCII data. + */ + if (iis.tid & IIS_READ) { + /* Return the WCS for the referenced frame. + */ + char emsg[SZ_FNAME]; + char *text; + int frame; + + frame = decode_frameno (iis.z & 07777); + if (frame > fb_nframes) + strcpy (text=emsg, "[NOSUCHFRAME]\n"); + else { + set_reference_frame (frame); + text = wcsbuf[reference_frame-1]; + } + + write (dataout, text, SZ_WCSBUF); + + } else { + /* Set the WCS for the referenced frame. + */ + char buf[1024]; + int fb_config, frame; + + frame = decode_frameno (iis.z & 07777); + if (frame > fb_nframes) + if (frame < MAX_FRAMES) + set_fbconfig (fb_config_index, frame); + + set_reference_frame (frame); + if ((fb_config = iis.t & 077) != fb_config_index) + set_fbconfig (fb_config, reference_frame); + + /* Read in and set up the WCS. */ + if (read (datain, buf, ndatabytes) == ndatabytes) + strncpy (wcsbuf[reference_frame-1], buf, SZ_WCSBUF); + + strcpy (rf_p->fb_ctran.format, W_DEFFORMAT); + rf_p->fb_ctran.imtitle[0] = '\0'; + rf_p->fb_ctran.valid = 0; + rf_p->fb_imageno++; + rf_p->fb_objno = 1; + + wcs_update (rf_p); + if (rf_p == df_p) + window_set (gio_frame, FRAME_LABEL, framelabel(), 0); + } + + return (NOTIFY_DONE); + break; + + case IMCURSOR: + /* Read or write the logical image cursor. This is an extension + * added to provide a high level cursor read facility; this is + * not the same as a low level access to the IIS cursor subunit. + * Cursor reads may be either nonblocking (immediate) or blocking, + * using the keyboard or mouse to terminate the read, and + * coordinates may be returned in either image (world) or frame + * buffer pixel coordinates. + */ + if (iis.tid & IIS_READ) { + /* Read the logical image cursor. In the case of a blocking + * read all we do is initiate a cursor read; completion occurs + * when the user hits a key or button. + */ + if (iis.tid & IMC_SAMPLE) { + /* Sample the cursor position. */ + register struct ctran *ct; + int wcs = iis.z; + int sx, sy; + float wx, wy; + + wx = sx = last_sx + pw_rect.r_left; + wy = sy = last_sy + pw_rect.r_top; + + if (wcs) { + ct = wcs_update (df_p); + if (ct->valid) { + if (abs(ct->a) > .001) + wx = ct->a * sx + ct->c * sy + ct->tx; + if (abs(ct->d) > .001) + wy = ct->b * sx + ct->d * sy + ct->ty; + } + } + + /* Return the cursor value on the output datastream encoded + * in a fixed size ascii buffer. + */ + gio_retcursorval (wx, wy, display_frame*100+wcs, 0, ""); + + } else { + /* Initiate a user triggered cursor read. */ + gio_readcursor (iis.z); + } + + } else { + /* Write (set) the logical image cursor position. */ + register struct ctran *ct; + int sx = iis.x, sy = iis.y; + float wx = sx, wy = sy; + int wcs = iis.z; + + if (wcs) { + ct = wcs_update (df_p); + if (ct->valid) { + if (abs(ct->a) > .001) + sx = (wx - ct->tx) / ct->a; + if (abs(ct->d) > .001) + sy = (wy - ct->ty) / ct->d; + } + } + + gio_setcursorpos (sx - pw_rect.r_left, sy - pw_rect.r_top); + } + + return (NOTIFY_DONE); + break; + + default: + /* Ignore unsupported command input. + */ + break; + } + + /* Discard any data following the header. */ + if (!(iis.tid & IIS_READ)) + for (nbytes = ndatabytes; nbytes > 0; nbytes -= n) { + n = (nbytes < SZ_FIFOBUF) ? nbytes : SZ_FIFOBUF; + if ((n = read (datain, buf, n)) <= 0) + break; + } + + return (NOTIFY_DONE); +} + + +/* SET_REFERENCE_FRAME -- Set reference frame. If the frame referenced is + * greater than the current number of frames, attempt to increase the number + * of frames. + */ +static +set_reference_frame (n) +register int n; +{ + reference_frame = max (1, n); + if (reference_frame > fb_nframes) { + if (reference_frame < MAX_FRAMES) + set_fbconfig (fb_config_index, reference_frame); + else { + fprintf (stderr, "imtool warning: "); + fprintf (stderr, + "attempt to reference nonexistent frame %d\n", + reference_frame); + reference_frame = fb_nframes; + } + } + + rf_p = frames + (reference_frame - 1); +} + + +/* DECODE_FRAMENO -- Decode encoded IIS register frame number. + */ +static +decode_frameno (z) +register int z; +{ + register int n; + + /* Get the frame number, encoded with a bit for each frame, 01 is + * frame 1, 02 is frame 2, 04 is frame 3, and so on. + */ + if (!z) z = 1; + for (n=0; !(z & 1); z >>= 1) + n++; + + return (max (1, n + 1)); +} + + +/* BSWAP2 - Move bytes from array "a" to array "b", swapping successive + * pairs of bytes. The two arrays may be the same but may not be offset + * and overlapping. + */ +static +bswap2 (a, b, nbytes) +char *a, *b; /* input array */ +int nbytes; /* number of bytes to swap */ +{ + register char *ip=a, *op=b, *otop; + register unsigned temp; + + /* Swap successive pairs of bytes. + */ + for (otop = op + (nbytes & ~1); op < otop; ) { + temp = *ip++; + *op++ = *ip++; + *op++ = temp; + } + + /* If there is an odd byte left, move it to the output array. + */ + if (nbytes & 1) + *op = *ip; +} + + +/* Cursor and marker pixrects. + */ +static short p_imcursor[] = { +#include "imtool.cursor" +}; +static short p_imcross[] = { +#include "imtool.cross" +}; +static short p_imsquare[] = { +#include "imtool.square" +}; +mpr_static (old_cursor, 16, 16, 1, NULL); +mpr_static (pr_cursor, 16, 16, 1, p_imcursor); +mpr_static (pr_cross, 16, 16, 1, p_imcross); +mpr_static (pr_square, 16, 16, 1, p_imsquare); +static struct pixrect *marker[] = { NULL, &pr_cursor, &pr_cross, &pr_square }; + +/* GIO_READCURSOR -- Initiate an image cursor read. Save the current + * mouse coordinates if outside the imtool window, restore the mouse to the + * imtool window, and change the cursor shape to indicate that a cursor read + * is in progress. May be called while a cursor read is already in progress + * to reset the cursor-read cursor pixrect. + */ +static +gio_readcursor (wcs) +int wcs; +{ + Cursor cursor = window_get (gio_canvas, WIN_CURSOR); + + if (!reading_imcursor) { + /* Save cursor pixrect for later restore. */ + old_cursor = *((Pixrect *) cursor_get (cursor, CURSOR_IMAGE)); + + /* Save the absolute mouse position so that we can restore it when + * the cursor read is completed. Restore the mouse to the most + * recent position in the IMTOOL window. + */ + get_absmousepos (gio_frame_fd, &save_sx, &save_sy); + gio_setcursorpos (last_sx, last_sy); + + reading_imcursor++; + imcursor_wcs = wcs; + } + + /* Change the cursor shape while the cursor read is in progress. */ + cursor_set (cursor, + CURSOR_IMAGE, &pr_cursor, + CURSOR_SHOW_CURSOR, TRUE, + CURSOR_SHOW_CROSSHAIRS, FALSE, + CURSOR_OP, PIX_NOT(PIX_SRC) & PIX_DST | PIX_COLOR(CMS_CURSOR), + CURSOR_XHOT, 8, + CURSOR_YHOT, 8, + 0); + window_set (gio_canvas, WIN_CURSOR, cursor, 0); +} + + +/* GIO_RESTORECURSOR -- Restore the original cursor. + */ +static +gio_restorecursor() +{ + if (reading_imcursor) { + Cursor cursor; + + /* Restore the mouse position to whatever it was before IMTOOL + * grabbed the mouse for the cursor read. + */ + set_absmousepos (gio_frame_fd, save_sx, save_sy); + + /* Restore the default IMTOOL cursor shape. */ + cursor = window_get (gio_canvas, WIN_CURSOR); + cursor_set (cursor, + CURSOR_IMAGE, &old_cursor, + CURSOR_SHOW_CURSOR, FALSE, + CURSOR_SHOW_CROSSHAIRS, (cursor_show == CURSOR_ON), + 0); + window_set (gio_canvas, WIN_CURSOR, cursor, 0); + + reading_imcursor = 0; + } +} + + +/* GIO_RETCURSORVAL -- Return the cursor value on the output datastream to + * the client which requested the cursor read. + */ +static +gio_retcursorval (wx, wy, wcs, key, strval) +float wx, wy; /* cursor coordinates */ +int wcs; /* encoded WCS value */ +int key; /* keystroke used as trigger */ +char *strval; /* optional string value */ +{ + char curval[SZ_IMCURVAL]; + char keystr[20]; + + /* Encode the cursor value. */ + if (key == EOF) + sprintf (curval, "EOF\n"); + else { + if (isprint (key) && !isspace(key)) { + keystr[0] = key; + keystr[1] = '\0'; + } else + sprintf (keystr, "\\%03o", key); + + sprintf (curval, "%10.3f %10.3f %d %s %s\n", + wx, wy, wcs, keystr, strval); + } + + /* Send it to the client program. */ + write (dataout, curval, sizeof(curval)); +} + + +/* EV_GIOFRAME -- GIO frame event handler. + */ +static Notify_value +ev_gioframe (frame, event, arg, type) +Frame frame; +Event *event; +Notify_arg arg; +Notify_event_type type; +{ + Notify_value value; + + value = notify_next_event_func (frame, event, arg, type); + window_open = (((int) window_get (gio_frame, FRAME_CLOSED)) == 0); + + return (value); +} + + +/* EV_GIOINPUT -- GIO input event handler. + */ +static Notify_value +ev_gioinput (frame, event, arg, type) +Frame frame; +Event *event; +Notify_arg arg; +Notify_event_type type; +{ + register int key; + Notify_value value; + static float xsize, ysize; + BRect rect; + char ch; + + key = event_id (event); + + /* The following is to attempt to restore the image greyscale in the + * global color map, after the color map has been clobbered by the + * window manager when the mouse is moved to some other window. + */ + if (key == KBD_DONE || key == LOC_WINEXIT) { + edit_colormap(); + return (NOTIFY_DONE); + } + + /* Let frame operate upon the event. */ + if ((int)type != PANNER_EVENT) + value = notify_next_event_func (frame, event, arg, type); + + switch (key) { + case WIN_RESIZE: + Bpw_get_region_rect (gio_pw, &pw_rect); + pw_rect.r_left = df_p->fb_xoff = + max(0, min(fb_rect.r_width - pw_rect.r_width, df_p->fb_xoff)); + pw_rect.r_top = df_p->fb_yoff = + max(0, min(fb_rect.r_height - pw_rect.r_height, df_p->fb_yoff)); + + gio_xsize = pw_rect.r_width; + gio_ysize = pw_rect.r_height; + init_colorbar (pw_rect.r_width); + + wc_xoff = wc_yoff = 0; + if (display_coords && state == TRACK_CURSOR) + update_coords (event); + break; + + case KEY_SNAP: + /* Imcopy. */ + imagecopy_proc(); + break; + + case KEY_PCOORDS: + /* Enable/disable continuous display of the cursor coordinates. */ + toggle_displaycoords (event); + break; + + case KEY_SETUP: + /* Toggle display of the setup panel. */ + setup_proc(); + break; + + case KEY_REMARK: + /* Remark a list of objects. */ + if (event_is_down(event)) { + char fname[SZ_FNAME]; + + wcs_update (df_p); + o_revtext = !o_revtext; + sprintf (fname, o_fname, df_p->fb_frameno, df_p->fb_imageno); + strcpy (fname, getfname(fname, 0)); + remark_objects (fname); + } + break; + + case MS_RIGHT: + if (event_is_down(event)) { + last_sx = last_bx = event_x(event); + last_sy = last_by = event_y(event); + } + + /* If the cursor is moved while the right mouse button is + * depressed the image is windowed. If the control key is also + * depressed the cursor is used to roam about in the frame buffer. + */ + if (state == TRACK_CURSOR && event_is_down(event)) { + if (event_ctrl_is_down (event)) + state = ROAM; + else + state = WINDOW; + xsize = pw_rect.r_width; + ysize = pw_rect.r_height; + if (state == WINDOW) { + switch (df_p->fb_maptype) { + case MONO: + case HEAT: + case RAMP1: + case RAMP2: + case HALLEY: + case LINEARPS: + case ULUT1: + case ULUT2: + compute_transfer_function (event); + break; + case RANDOMPS: + case CRANDOMPS: + set_colortable(); + break; + } + set_transfer_function (gio_pw, + df_p->fb_center, df_p->fb_slope); + } + } else if (state != TRACK_CURSOR && event_is_up(event)) + state = TRACK_CURSOR; + break; + + case LOC_DRAG: + last_sx = event_x (event); + last_sy = event_y (event); + + if (panning) + p_cursor_setback--; + if (state == WINDOW) { + compute_transfer_function (event); + set_transfer_function (gio_pw, df_p->fb_center, df_p->fb_slope); + } + break; + + case LOC_MOVE: + last_sx = event_x (event); + last_sy = event_y (event); + + if (panning) + p_cursor_setback--; + if (display_coords && state == TRACK_CURSOR) + update_coords (event); + break; + + case MS_LEFT: + last_sx = event_x (event); + last_sy = event_y (event); + + if (event_is_down (event)) { + if (reading_imcursor) { + /* The left mouse button may be used to alias keyboard + * events. Typing ctrl/button causes the last key to be + * aliased with the indicated button. Thereafter, pressing + * that mouse button during a cursor read causes the cursor + * read to terminate, returning the aliased key just as if + * the key had been typed on the keyboard. + */ + if (event_ctrl_is_down (event)) { + if (key == MS_LEFT) + key_left = last_key; + } else if (reading_imcursor) { + if (key == MS_LEFT) + key = key_left; + if (key) + goto readcur; + } + + } else if (display_coords && state==TRACK_CURSOR) { + /* Add an object to a cursor list. */ + mark_object (event); + } + } + break; + + case MS_MIDDLE: + /* Pan - move the object under the cursor to the center of the + * display window (or as close as possible without wraparound). + */ + if (event_is_up (event)) { + int fb_ex, fb_ey, fb_mx, fb_my, fb_xc, fb_yc, fb_nx, fb_ny; + int pw_xc, pw_yc, dx, dy, n_x, n_y; + int newzoom, close=1; + + /* Pressing the middle button without moving the mouse causes + * the zoom factor to be advanced. In other words, placing + * the mouse on a feature and pressing the "zoom/pan" button + * causes that feature to be moved to the center of the + * display; pressing the button again causes the display to be + * zoomed about the centered feature. + */ + newzoom = zoom; + n_x = event_x(event); + n_y = event_y(event); + + if (abs(n_x-last_bx) <= close && abs(n_y-last_by) <= close) { + if (++zoom_index >= nzooms) + zoom_index = 0; + newzoom = zooms[zoom_index]; + } + + last_sx = last_bx = n_x; + last_sy = last_by = n_y; + + pw_xc = pw_rect.r_width / 2; /* window center in pw */ + pw_yc = pw_rect.r_height / 2; + fb_mx = pw_rect.r_left + n_x; /* final mouse position */ + fb_my = pw_rect.r_top + n_y; + fb_xc = pw_rect.r_left + pw_xc; /* window center in fb */ + fb_yc = pw_rect.r_top + pw_yc; + fb_nx = fb_ex = fb_mx; /* next center */ + fb_ny = fb_ey = fb_my; + + dx = n_x - pw_xc; /* step size */ + dy = n_y - pw_yc; + + /* Pan a long ways in the indicated direction, normally to the + * edge of the image. + */ + if (event_shift_is_down (event)) { + fb_ex = fb_nx = fb_mx = + max(pw_xc, min(fb_rect.r_width - pw_xc, fb_xc + dx*5)); + fb_ey = fb_ny = fb_my = + max(pw_xc, min(fb_rect.r_height - pw_yc, fb_yc + dy*5)); + if (!event_ctrl_is_down (event)) + dx = dy = 0; + } + + /* Smooth pan to ex,ey. May be combined with shift-pan. */ + if (event_ctrl_is_down (event)) { + dx = dx ? dx / abs(dx) : 0; + dy = dy ? dy / abs(dy) : 0; + + /* Increase step size if window is large. */ + if (pw_rect.r_width * pw_rect.r_height > 200000) { + dx *= 2; + dy *= 2; + } + + fb_nx = max(0, min(fb_rect.r_width, fb_xc + dx)); + fb_ny = max(0, min(fb_rect.r_height, fb_yc + dy)); + } + + /* Go to x,y starting at nx,ny stepping dx,dy per frame. */ + if (fb_nx != fb_xc || fb_ny != fb_yc || zoom != newzoom) + start_pan (fb_mx,fb_my, fb_nx,fb_ny, fb_ex,fb_ey, dx,dy, + newzoom); + } + break; + + case INTERRUPT: + /* Abort any lengthy operation currently in progress. */ + if (reading_imcursor) + goto readcur; + else + stop_pan(); + break; + + case NEXT_SCREEN: + /* Display the next screen in numerical sequence. */ + set_frame (0); + if (display_coords && state == TRACK_CURSOR) + update_coords (event); + break; + + case PREV_SCREEN: + /* Display the previous screen in numerical sequence. */ + set_frame (-1); + if (display_coords && state == TRACK_CURSOR) + update_coords (event); + break; + + case CYCLE_BLINK: + /* Display the next screen from the blink frames list. + * The frames in the blink frame list do not have to exist; + * if not, then advance through the list until either a valid + * frame is found, or the list has been traversed once. + */ + if (n_blink_frames > 0 && window_open) { + int frame, n; + for (n=n_blink_frames; --n >= 0; ) { + if (++blink_frame >= n_blink_frames) + blink_frame = 0; + frame = blink_frames[blink_frame]; + if (frame >= 1 && frame <= fb_nframes) { + set_frame (frame); + if (display_coords && state == TRACK_CURSOR) + update_coords (NULL); + break; + } + } + } + break; + + default: + /* Terminate a cursor read, returning the encoded cursor value + * sequence to client program on the output datastream. + */ + if (event_is_down(event) && + (event_is_ascii(event) || event_is_key_right(event))) { +readcur: + last_sx = event_x (event); + last_sy = event_y (event); + + /* Terminate cursor read? */ + if (reading_imcursor) { + register struct ctran *ct; + int wcs = imcursor_wcs; + int sx, sy; + float wx, wy; + + /* Map keypad function keys to digits. */ + if (event_is_key_right(event)) { + switch (key = event_id(event) - KEY_RIGHT(1) + 1) { + case 7: case 8: case 9: + break; + case 10: case 11: case 12: + key -= 6; + break; + case 13: case 14: case 15: + key -= 12; + break; + default: + return (value); + } + key += '0'; + } + + last_x = event_x (event); + last_y = event_y (event); + last_key = key; + + wx = sx = last_x + pw_rect.r_left; + wy = sy = last_y + pw_rect.r_top; + + if (wcs) { + ct = wcs_update (df_p); + if (ct->valid) { + if (abs(ct->a) > .001) + wx = sx * ct->a + ct->tx; + if (abs(ct->d) > .001) + wy = sy * ct->d + ct->ty; + } + } + + /* Map ctrl/d and ctrl/z into EOF. */ + if (key == '\004' || key == '\032') + key = EOF; + else if (marktype) { + /* Mark the cursor position? */ + edit_framebuffer (df_p, sx/zoom - 8, sy/zoom - 8, + marker[marktype], + PIX_NOT(PIX_SRC) & PIX_DST); + } + + /* Return the cursor value on the output datastream encoded + * in a fixed size ascii buffer. + */ + gio_retcursorval (wx, wy, display_frame*100+wcs, key, ""); + + /* Terminate the cursor read. */ + gio_restorecursor(); + } + } + } + + return (value); +} + + +static int p_dx, p_dy; +static int p_sx, p_sy; +static int p_left, p_top; +static int p_svdc; + +/* START_PAN -- Pan the image smoothly to the indicated position. This can + * take a while, so we want to do it on a timer and provide for interrupt. + * A new pan can be started to change the destination while an old pan is + * still in progress. + */ +static +start_pan (fb_mx,fb_my, fb_nx,fb_ny, fb_ex,fb_ey, dx,dy, newzoom) +int fb_mx, fb_my; /* mouse position in frame buffer */ +int fb_nx, fb_ny; /* center of window at next display */ +int fb_ex, fb_ey; /* center of window at final display */ +int dx, dy; /* step size for pan */ +register int newzoom; /* new zoom factor */ +{ + register int w, h; + int n_left, n_top; + int n_sx, n_sy, e_sx, e_sy; + + if (!panning) { + p_svdc = display_coords; + display_coords = 0; + panning++; + } + + p_cursor_setback = 9; + gio_setcursor (CURSOR_OFF, 0); + + Bpw_get_region_rect (gio_pw, &pw_rect); + w = pw_rect.r_width; + h = pw_rect.r_height; + + /* Scale zoomed frame buffer units to new zoom factor. + */ + p_sx = fb_mx * newzoom / zoom; + p_sy = fb_my * newzoom / zoom; + n_sx = fb_nx * newzoom / zoom; + n_sy = fb_ny * newzoom / zoom; + e_sx = fb_ex * newzoom / zoom; + e_sy = fb_ey * newzoom / zoom; + p_dx = dx * newzoom; + p_dy = dy * newzoom; + + /* The following are the final left,top values. */ + p_left = max(0, min(Fb_width*newzoom - w, + (e_sx - w/2) / newzoom * newzoom)); + p_top = max(0, min(Fb_height*newzoom - h, + (e_sy - h/2) / newzoom * newzoom)); + + /* The following are the left,top values for the next display. */ + n_left = max(0, min(Fb_width*newzoom - w, + (n_sx - w/2) / newzoom * newzoom)); + n_top = max(0, min(Fb_height*newzoom - h, + (n_sy - h/2) / newzoom * newzoom)); + + /* Set the new zoom factor for the display. */ + set_zoom (df_p, n_left, n_top, newzoom); + + notify_post_event (ev_panner, NULL, NOTIFY_SAFE); +} + + +/* STOP_PAN -- Called to abort a pan. */ +static +stop_pan() +{ + p_dx = p_dy = 0; +} + + +/* PANNER -- Called on a fast timer to do the panning. */ +static Notify_value +ev_panner() +{ + register int left, top; + + /* No clipping is done, so the imtool window must be exposed. */ + window_set (gio_frame, WIN_SHOW, TRUE, 0); + + /* repaint (P_IMAGE|P_DONTCLIP); */ + repaint (P_IMAGE); + + if (p_dx < 0 && pw_rect.r_left <= p_left || + p_dx > 0 && pw_rect.r_left >= p_left) + p_dx = 0; + else if (p_dx) { + left = pw_rect.r_left + p_dx; + if (p_dx < 0) + left = max (p_left, left); + else + left = min (p_left, left); + df_p->fb_xoff = pw_rect.r_left = left; + } + + if (p_dy < 0 && pw_rect.r_top <= p_top || + p_dy > 0 && pw_rect.r_top >= p_top) + p_dy = 0; + else if (p_dy) { + top = pw_rect.r_top + p_dy; + if (p_dy < 0) + top = max (p_top, top); + else + top = min (p_top, top); + df_p->fb_yoff = pw_rect.r_top = top; + } + + if (p_dx == 0 && p_dy == 0) { + if (panning) { + panning = 0; + display_coords = p_svdc; + if (p_cursor_setback > 0) { + int sx = p_sx - pw_rect.r_left; + int sy = p_sy - pw_rect.r_top; + if (sx >= 0 && sx < pw_rect.r_width && + sy >= 0 && sy < pw_rect.r_height) + gio_setcursorpos (sx, sy); + gio_setcursor (CURSOR_ON, 0); + gio_events(); + } + repaint (P_GRAPHICS|P_COLORBAR); + } + } else { + /* Allow the window to process any pending events. */ + gio_events(); + + /* Post another call to the panner. */ + notify_post_event (ev_panner, NULL, NOTIFY_SAFE); + } + + return (NOTIFY_DONE); +} + + +/* EDIT_FRAMEBUFFER -- Edit a frame buffer by operating upon it with the + * given pixrect and rasterop at the given location, clipping as necessary + * at the boundaries of the frame. Update the display window as well, if + * the frame being edited is the display frame. + */ +static +edit_framebuffer (fb, x, y, pr, rop) +struct framebuf *fb; /* frame to be edited */ +int x, y; /* left,top coords of rect to be edited */ +struct pixrect *pr; /* pixrect to be used */ +int rop; /* rasterop defining operation */ +{ + int width = pr->pr_width, height = pr->pr_height; + int s_left = 0, s_top = 0; + int d_left = x, d_top = y; + + /* Clip to the frame boundary. */ + while (d_left < 0) { + s_left++; + width--; + d_left++; + } + + while (d_left + width-1 > Fb_width) + width--; + + while (d_top < 0) { + s_top++; + height--; + d_top++; + } + + while (d_top + height-1 > Fb_height) + height--; + + /* All done if there is nothing left after clipping. */ + if (width*height <= 0) + return; + + /* Edit the frame buffer (clobbers the display pixels). */ + pr_rop (fb->fb_pr, d_left, d_top, width, height, + PIX_NOT(PIX_SRC) & PIX_DST, pr, s_left, s_top); + + /* Refresh the display, if the current display frame is the + * same as the reference frame. + */ + if (fb == df_p) { + BRect fb_r, pw_r; + + fb_r.r_left = d_left * zoom; + fb_r.r_top = d_top * zoom; + fb_r.r_width = width * zoom; + fb_r.r_height = height * zoom; + + Bpw_get_region_rect (gio_pw, &pw_rect); + Bpw_lock (gio_pw, &pw_rect); + + pw_rect.r_left = df_p->fb_xoff; + pw_rect.r_top = df_p->fb_yoff; + + if (maprect (&fb_rect, &fb_r, &pw_rect, &pw_r)) + if (maprect (&pw_rect, &pw_r, &fb_rect, &fb_r)) { + ds_write (gio_pw, + pw_r.r_left, pw_r.r_top, + pw_r.r_width, pw_r.r_height, + PIX_SRC | PIX_COLOR(NGREY-1), + df_p->fb_pr, fb_r.r_left, fb_r.r_top); + + if (pw_r.r_top + pw_r.r_height >= pw_rect.r_height + - cb_height) + put_colorbar(); + } + + Bpw_unlock (gio_pw); + } +} + + +/* GIO_EVENTS -- Have the image window process any queued input events. + */ +static +gio_events() +{ + Event event; + int fd, flags; + + /* Allow the window to process any pending events. */ + fd = (int) window_get (gio_canvas, WIN_FD); + flags = fcntl (fd, F_GETFL, 0); + fcntl (fd, F_SETFL, O_NDELAY); + while (window_read_event (gio_canvas, &event) != -1) + ev_gioinput (gio_canvas, + canvas_event(gio_canvas, &event), NULL, PANNER_EVENT); + fcntl (fd, F_SETFL, flags); +} + + +/* ICLEAR_PROC -- Clear the main (image) window. + */ +static +iclear_proc() +{ + erase (df_p); +} + + +/* GCLEAR_PROC -- Clear the graphics overlay. + */ +static +gclear_proc() +{ + df_p->fb_objno = 1; + repaint (P_IMAGE|P_COLORBAR); +} + + +/* SETFRAME_PROC -- Select the next frame for viewing. + */ +static +setframe_proc() +{ + set_frame (0); +} + + +/* SET_FRAME -- Set the display frame. Call with frameno=0 to advance to + * the next frame, -N will yield the previous frame in sequence, and + * anything else is actual frame number. + */ +static +set_frame (frameno) +int frameno; +{ + if (frameno < 0) { + frameno = display_frame - 1; + if (frameno < 1) + frameno = fb_nframes; + } else if (frameno == 0) { + frameno = display_frame + 1; + if (frameno > fb_nframes) + frameno = 1; + } else { + if (frameno < 1) + frameno = 1; + else if (frameno > fb_nframes) + frameno = fb_nframes; + } + + display_frame = frameno; + df_p = frames + (frameno - 1); + set_zoom (df_p, df_p->fb_xoff, df_p->fb_yoff, df_p->fb_xzoom); + + set_colortable(); + set_transfer_function (gio_pw, df_p->fb_center, df_p->fb_slope); + window_set (gio_frame, FRAME_LABEL, framelabel(), 0); + panel_set_value (pan_set_maptype, df_p->fb_maptype); + + repaint (P_IMAGE|P_COLORBAR|P_GRAPHICS); +} + + +/* SET_ZOOM -- Change the zoom factor for the referenced frame to the given + * value. If the referenced frame is the display frame, update the global + * display zoom factors as well. + */ +static +set_zoom (fr, left, top, newzoom) +register struct framebuf *fr; /* frame to be zoomed */ +int left, top; /* new left and top for frame */ +int newzoom; /* new zoom factor */ +{ + register struct ctran *ct; + int fb_zoom, i; + + /* Verify valid zoom factor. */ + newzoom = max(zooms[0], min(zooms[nzooms-1], newzoom)); + for (i=0; i < nzooms; i++) + if (zooms[i] == newzoom) { + zoom_index = i; + break; + } + + /* Set the new frame buffer zoom factor. */ + if ((fb_zoom = fr->fb_xzoom) != newzoom) { + ct = &fr->fb_ctran; + ct->a = ct->a * fb_zoom / newzoom; + ct->d = ct->d * fb_zoom / newzoom; + + /* For Apply a 0.5 pixel correction when zooming, to make the + * center of the pixel have integral coordinates (coord X,Y where + * X and Y are integral will always be the center of a pixel). + * This should be turned off for zoom=1, since there is no + * subpixel resolution, or if the image has already been zoomed + * at the host level. + */ + if (abs(ct->a * newzoom) < 1.01) { + if (fb_zoom == 1) + ct->tx += (ct->a > 0) ? -0.5 : 0.5; + else if (newzoom == 1) + ct->tx += (ct->a > 0) ? 0.5 : -0.5; + } + if (abs(ct->d * newzoom) < 1.01) { + if (fb_zoom == 1) + ct->ty += (ct->d > 0) ? -0.5 : 0.5; + else if (newzoom == 1) + ct->ty += (ct->d > 0) ? 0.5 : -0.5; + } + + fr->fb_xzoom = fr->fb_yzoom = newzoom; + } + + /* Offsets must be aligned to an unzoomed frame buffer pixel + * boundary since this constraint is applied in ds_write. + */ + fr->fb_xoff = max(0, min(Fb_width*newzoom - pw_rect.r_width, + left / newzoom * newzoom)); + fr->fb_yoff = max(0, min(Fb_height*newzoom - pw_rect.r_height, + top / newzoom * newzoom)); + + /* If the referenced frame is the display frame, make the new zoom + * factor global. + */ + if (fr == df_p) { + fb_width = Fb_width * newzoom; + fb_height = Fb_height * newzoom; + + fb_rect.r_top = 0; + fb_rect.r_left = 0; + fb_rect.r_width = fb_width; + fb_rect.r_height = fb_height; + + pw_rect.r_left = df_p->fb_xoff; + pw_rect.r_top = df_p->fb_yoff; + + zoom = newzoom; + } +} + + +/* ERASE -- Clear a frame. + */ +static +erase (fr) +struct framebuf *fr; +{ + register int *op, v, n; + unsigned char *cp; + int val; + + for (val=0, n=sizeof(int), cp = (unsigned char *)&val; --n >= 0; ) + *cp++ = background; + + if (val) { + op = (int *) mpr_d(fr->fb_pr)->md_image; + n = Fb_width * Fb_height / sizeof(int); + for (v=val; --n >= 0; ) + *op++ = v; + } else + bzero ((char *)mpr_d(fr->fb_pr)->md_image, Fb_width * Fb_height); + + if (fr == df_p) + repaint (P_IMAGE|P_COLORBAR); +} + + +/* REPAINT -- Repaint the display window. + */ +static +repaint (what) +int what; +{ + if (what & P_IMAGE) { + BRect fb_r, pw_r; + int rop; + + pw_r = pw_rect; + pw_r.r_left = pw_r.r_top = 0; + if (what & P_COLORBAR) + pw_r.r_height -= cb_height; + + rop = PIX_SRC | PIX_COLOR(NGREY-1); + if (what & P_DONTCLIP) + rop |= PIX_DONTCLIP; + + if (maprect (&pw_rect, &pw_r, &fb_rect, &fb_r)) + if (maprect (&fb_rect, &fb_r, &pw_rect, &pw_r)) + ds_write (gio_pw, + pw_r.r_left, pw_r.r_top, pw_r.r_width, pw_r.r_height, + rop, df_p->fb_pr, fb_r.r_left, fb_r.r_top); + + if (display_coords && state == TRACK_CURSOR) { + set_wcsboxpos(); + pw_text (gio_pw, wc_xoff, wc_yoff + wc_font->pf_defaultsize.y, + PIX_NOT(PIX_SRC), wc_font, wc_text); + } + } + + if (what & P_COLORBAR) + put_colorbar(); + + if ((what & P_GRAPHICS) && df_p->fb_objno > 1) { + char fname[SZ_FNAME]; + + wcs_update (df_p); + sprintf (fname, o_fname, df_p->fb_frameno, df_p->fb_imageno); + strcpy (fname, getfname(fname, 0)); + remark_objects (fname); + } +} + + +/* REFRESH_DISPLAY -- Called by the windowing system when the display needs + * to be refreshed from the frame buffer. + */ +static +refresh_display (canvas, pw, rl) +Canvas canvas; +Pixwin *pw; +Rectlist *rl; +{ + register struct rectnode *rn; + BRect fb_r, pw_r; + Rect rect, r; + + /* See if any damage has occurred and fix it. */ + rl_rectoffset (rl, &rl->rl_bound, &rect); + pw_lock (pw, &rect); + + /* Now fix all the damage. Regions of the display window which are + * not mapped onto the frame buffer are not fixed up at present. + * Scale changes (zoom/dezoom) are not currently immplemented. + */ + for (rn = rl->rl_head; rn; rn = rn->rn_next) { + rl_rectoffset (rl, &rn->rn_rect, &r); + pw_r.r_left = r.r_left; + pw_r.r_top = r.r_top; + pw_r.r_width = r.r_width; + pw_r.r_height = r.r_height; + + if (maprect (&pw_rect, &pw_r, &fb_rect, &fb_r)) + if (maprect (&fb_rect, &fb_r, &pw_rect, &pw_r)) + ds_write (pw, + pw_r.r_left, pw_r.r_top, pw_r.r_width, pw_r.r_height, + PIX_SRC | PIX_COLOR(NGREY-1), + df_p->fb_pr, fb_r.r_left, fb_r.r_top); + } + + put_colorbar(); + pw_unlock (pw); +} + + +/* DS_WRITE -- Write to the display. This is analogous to pw_write, except + * that pixel replication or subsampling is performed as indicated by the + * zoom factors for the current display frame. At present, the zoom factor + * may not be specified independently for x and y. + */ +static +ds_write (pw, left, top, width, height, rop, fb_pr, fb_left, fb_top) +Pixwin *pw; +int left, top; +int width, height; +int rop; +Pixrect *fb_pr; +int fb_left, fb_top; /* zoomed frame buffer coords */ +{ + register unsigned char pix, *ip, *op; + register int n, p; + unsigned char *otop, *fb, *lp; + int pr_left, pr_top, i, j; + Pixrect *mpr_line, *pr; + struct rect pw_r; + + if (width <= 0 || height <= 0) + return; + + /* If no zoom, just copy the frame buffer rect to the screen. */ + if (zoom <= 1) { + pw_write (pw, left,top, width,height, rop, fb_pr, fb_left,fb_top); + return; + } + + /* Zoom - magnify the image by pixel replication. (This assumes an + * 8 bit frame buffer and screen pixrect). + */ + mpr_line = mem_create (width, 1, pw->pw_pixrect->pr_depth); + fb = (unsigned char *)mpr_d(df_p->fb_pr)->md_image; + lp = (unsigned char *)mpr_d(mpr_line)->md_image; + otop = lp + width; + + /* Lock the frame buffer to avoid scribbling on other windows + * during write to raw screen.. + */ + pw_get_region_rect (pw, &pw_r); + pw_lock (pw, &pw_r); + + pr = pw->pw_pixrect; + pr_left = left + (int)window_get(gio_frame, WIN_X) + TOOL_BORDERWIDTH; + pr_top = top + (int)window_get(gio_frame, WIN_Y) + + HEIGHTADJUST - TOOL_BORDERWIDTH; + + for (j=0, i=(fb_top/zoom); j < height; j += zoom) { + ip = fb + (i++ * Fb_width) + (fb_left/zoom); + op = lp; + + /* Replicate a block of pixels. */ + switch (zoom) { + case 2: + for (n = (width/2); --n >= 0; ) { + pix = *ip++; + *op++ = pix; *op++ = pix; + } + break; + case 3: + for (n = (width/3); --n >= 0; ) { + pix = *ip++; + *op++ = pix; *op++ = pix; *op++ = pix; + } + break; + case 4: + for (n = (width/4); --n >= 0; ) { + pix = *ip++; + *op++ = pix; *op++ = pix; + *op++ = pix; *op++ = pix; + } + break; + case 5: + for (n = (width/5); --n >= 0; ) { + pix = *ip++; + *op++ = pix; *op++ = pix; *op++ = pix; + *op++ = pix; *op++ = pix; + } + break; + case 6: + for (n = (width/6); --n >= 0; ) { + pix = *ip++; + *op++ = pix; *op++ = pix; *op++ = pix; + *op++ = pix; *op++ = pix; *op++ = pix; + } + break; + case 7: + for (n = (width/7); --n >= 0; ) { + pix = *ip++; + *op++ = pix; *op++ = pix; *op++ = pix; + *op++ = pix; *op++ = pix; + *op++ = pix; *op++ = pix; + } + break; + case 8: + for (n = (width/8); --n >= 0; ) { + pix = *ip++; + *op++ = pix; *op++ = pix; + *op++ = pix; *op++ = pix; + *op++ = pix; *op++ = pix; + *op++ = pix; *op++ = pix; + } + break; + default: + for (n = (width/zoom); --n >= 0; ) { + pix = *ip++; + for (p=zoom; --p >= 0; ) + *op++ = pix; + } + break; + } + + /* Fill the last partial pixel. */ + pix = *ip++; + while (op < otop) + *op++ = pix; + + pr_replrop (pr, pr_left,pr_top+j, + width, min (height-j, zoom), rop, mpr_line, 0,0); + } + + pw_unlock (pw); + pr_close (mpr_line); +} + + +/* PUT_COLORBAR -- Refresh the colorbar on the screen. + */ +static +put_colorbar() +{ + if (cb_height) + pw_write (gio_pw, + 0, pw_rect.r_height - cb_height, + min (pw_rect.r_width, Fb_width), cb_height, + PIX_SRC, cb_pr, 0, 0); +} + + +/* TOGGLE_DISPLAYCOORDS -- Enable/disable continuous display of the cursor + * coordinates. + */ +static +toggle_displaycoords (event) +Event *event; +{ + BRect fb_r, pw_r; + + if (display_coords) { + /* Enable mouse moved input events. */ + window_set (gio_canvas, WIN_IGNORE_PICK_EVENTS, LOC_MOVE, 0, + 0); + display_coords = 0; + + /* Refresh the region of the screen used to output coordinates + * from the frame buffer, erasing the coordinate output box. + */ + pw_r.r_left = wc_xoff; + pw_r.r_top = wc_yoff; + pw_r.r_width = wc_width; + pw_r.r_height = wc_height; + + if (maprect (&pw_rect, &pw_r, &fb_rect, &fb_r)) + ds_write (gio_pw, + wc_xoff, wc_yoff, wc_width, wc_height, + PIX_SRC | PIX_COLOR(NGREY-1), + df_p->fb_pr, fb_r.r_left, fb_r.r_top); + + } else { + /* Disable mouse moved input events. */ + window_set (gio_canvas, WIN_CONSUME_PICK_EVENTS, LOC_MOVE, 0, + 0); + display_coords = 1; + update_coords (event); + } +} + + +/* UPDATE_COORDS -- Compute and output the world coordinates of the given + * event, using the WCS specified for the current display window. If called + * with event=NULL the most recent locator position is used. + */ +static +update_coords (event) +Event *event; +{ + register struct ctran *ct; + static struct timeval o_tv; + unsigned char *fb, *ip; + struct timeval n_tv; + int sx, sy, sz, fb_x, fb_y, delta_msec; + char buf[1024], ch; + float wx, wy, wz; + + /* Get frame buffer x,y; ignore events that occur faster than we + * can update the coordinate readout. + */ + if (event) { + /* Ignore event if it comes too soon. */ + n_tv = event_time(event); + if (o_tv.tv_sec) { + delta_msec = ((n_tv.tv_sec - o_tv.tv_sec) * 1000 + + (n_tv.tv_usec - o_tv.tv_usec) / 1000); + if (delta_msec < 50) + return; + } + + /* Get the screen (window relative) coordinates of the event. */ + sx = event_x(event) + pw_rect.r_left; + sy = event_y(event) + pw_rect.r_top; + + } else { + sx = last_sx + pw_rect.r_left; + sy = last_sy + pw_rect.r_top; + } + + /* Get frame buffer pixel value. */ + fb = (unsigned char *) mpr_d (df_p->fb_pr)->md_image; + fb_x = max(0, min(Fb_width, sx/zoom)); + fb_y = max(0, min(Fb_height, sy/zoom)); + sz = fb[fb_y*Fb_width+fb_x]; + if (sz < CMS_DATASTART || sz > CMS_DATAEND) + sz = 0; + + /* Compute the world coordinates of the event. */ + ct = wcs_update (df_p); + + if (ct->valid) { + wx = ct->a * sx + ct->c * sy + ct->tx; + wy = ct->b * sx + ct->d * sy + ct->ty; + + if (sz == 0) + wz = 0.0; + else { + switch (ct->zt) { + case W_LINEAR: + wz = ((sz - CMS_DATASTART) * (ct->z2 - ct->z1) / + (CMS_DATARANGE-1)) + ct->z1; + break; + default: + wz = sz; + break; + } + } + + } else { + wx = sx; + wy = sy; + wz = sz; + } + + /* Get the font to be used. */ + if (wc_font == NULL) { + static char fontname[] = TEXT_FONT; + if ((wc_font = pf_open (fontname)) == NULL) + fprintf (stderr, "cannot open %s\n", fontname); + wc_xoff = wc_yoff = 0; + } + + ch = ' '; + if (sz && ct->valid) { + if (ct->z1 < ct->z2) { + if (wz < (ct->z1 + 0.01)) + ch = '-'; + else if (wz > (ct->z2 - 0.01)) + ch = '+'; + } else if (ct->z1 > ct->z2) { + if (wz < (ct->z2 + 0.01)) + ch = '-'; + else if (wz > (ct->z1 - 0.01)) + ch = '+'; + } + } + + set_wcsboxpos(); + sprintf (buf, ct->format, wx, wy, wz, ch); + strncpy (wc_text, buf, SZ_WCTEXT); + pw_text (gio_pw, wc_xoff, wc_yoff + wc_font->pf_defaultsize.y, + PIX_NOT(PIX_SRC), wc_font, wc_text); + + if (event) + o_tv = n_tv; +} + + +/* MARK_OBJECT -- Called when the user has clicked on the position of an + * object to be marked and/or added to the output coordinate list. + */ +static +mark_object (event) +Event *event; +{ + register struct ctran *ct; + char tx_buf[SZ_FNAME]; + char fname[SZ_FNAME]; + int sx, sy, newset; + float wx, wy; + FILE *fp; + + ct = wcs_update (df_p); + + /* Get name of coordinate output file for the current frame. */ + sprintf (tx_buf, o_fname, df_p->fb_frameno, df_p->fb_imageno); + strcpy (fname, getfname(tx_buf, 0)); + + /* Append to the existing coordinate list, if any. If appending + * to an existing coordinate list, the existing list is displayed + * and the objno counter is left set to the next object to be added. + */ + if (newset = (df_p->fb_objno <= 1)) + remark_objects (fname); + if ((fp = fopen (fname, "a")) == NULL) { + fprintf (stderr, "cannot open %s for appending\n", fname); + return; + } + + /* Timestamp the first entry in the output file. */ + if (newset) + timestamp (fp); + + /* Get the screen (window relative) coordinates of the event. */ + sx = event_x(event) + pw_rect.r_left; + sy = event_y(event) + pw_rect.r_top; + + /* Compute the world coordinates of the event. */ + if (ct->valid) { + wx = ct->a * sx + ct->c * sy + ct->tx; + wy = ct->b * sx + ct->d * sy + ct->ty; + } else { + wx = sx; + wy = sy; + } + + /* Mark the object position on the screen. */ + sprintf (tx_buf, "%d", df_p->fb_objno++); + draw_text (sx - pw_rect.r_left, sy - pw_rect.r_top, tx_buf); + + fprintf (fp, "%g %g\n", wx, wy); + fclose (fp); +} + + +/* REMARK_OBJECTS -- Read a object list file and mark the numbered objects + * therein. + */ +static +remark_objects (fname) +char *fname; +{ + register struct ctran *ct; + register char *ip; + char lbuf[SZ_LINE], tx_buf[SZ_FNAME]; + int sx, sy, objno=1; + float wx, wy; + char *fgets(); + FILE *fp; + + gclear_proc(); + window_set (gio_frame, FRAME_LABEL, framelabel(), 0); + if ((fp = fopen (fname, "r")) == NULL) + return; + + while (fgets (lbuf, SZ_LINE, fp) != NULL) { + /* Skip comment lines and blank lines. */ + for (ip=lbuf; *ip == ' ' || *ip == '\t'; ip++) + ; + if (*ip == '\n' || *ip == '#') + continue; + if (!isdigit (*ip) && *ip != '-') + continue; + if (sscanf (ip, "%f%f", &wx, &wy) < 2) + continue; + + sx = wx; + sy = wy; + + /* Compute the world coordinates of the event if we have a valid + * WCS transform (rotations not permitted)/ + */ + ct = wcs_update (df_p); + if (ct->valid) { + if (abs(ct->a) > .001) + sx = (wx - ct->tx) / ct->a; + if (abs(ct->d) > .001) + sy = (wy - ct->ty) / ct->d; + } + + /* Mark the object position on the screen. */ + sprintf (tx_buf, "%d", objno++); + draw_text (sx - pw_rect.r_left, sy - pw_rect.r_top, tx_buf); + } + + fclose (fp); + + /* If we are updating an existing coordinate list from a newly + * displayed frame, timestamp the new section of the list. + */ + if (df_p->fb_objno <= 1) + if ((fp = fopen (fname, "a")) != NULL) { + timestamp (fp); + fclose (fp); + } + + df_p->fb_objno = objno; +} + + +/* TIMESTAMP -- Timestamp the output stream. + */ +static +timestamp (fp) +FILE *fp; +{ + register char *op; + char obuf[SZ_LINE]; + long clock; + + clock = time(0); + fprintf (fp, "# %s", asctime(localtime(&clock))); + + sprintf (obuf, "# %s", df_p->fb_label); + for (op=obuf; *op && *op != '\n'; op++) + ; + *op++ = '\n'; + *op = '\0'; + fputs (obuf, fp); +} + + +/* DRAW_TEXT -- Draw some text on the frame at the indicated position. + */ +static +draw_text (x, y, text) +int x, y; /* position where text is to be drawn */ +char *text; /* the text */ +{ + static struct pixfont *font = NULL; + + /* Get the screen font to be used. */ + if (font == NULL) { + static char fontname[] = MARK_FONT; + if ((font = pf_open (fontname)) == NULL) + fprintf (stderr, "cannot open %s\n", fontname); + } + + /* Draw the text. */ + if (o_revtext) + pw_text (gio_pw, x, y, PIX_NOT(PIX_SRC) & PIX_DST, font, text); + else + pw_text (gio_pw, x, y, PIX_SRC | PIX_DST, font, text); +} + + +/* WCS_UPDATE -- Load the screen WCS, if not yet validated, from the user + * wcs file, if any. + * + * File format (two lines): + * + * image title (imtool header label string)\n + * a b c d tx ty z1 z2 zt + * + * NOTE: the WCS text is now passed in via the data stream as a write to the + * subunit WCS and left in the buffer "wcsbuf", rather than being passed via + * a text file. + */ +static struct ctran * +wcs_update (fr) +struct framebuf *fr; +{ + register struct ctran *ct = &fr->fb_ctran; + char buf[1024], *format; + + /* Get the new WCS. */ + if (!ct->valid) { + fr->fb_label[0] = '\0'; + ct->zt = W_UNITARY; + + /* Attempt to read the WCS file and set up a unitary transformation + * if the file cannot be read. + */ + if (sscanf (wcsbuf[fr->fb_frameno-1], "%[^\n]\n%f%f%f%f%f%f%f%f%d", + buf, &ct->a, &ct->b, &ct->c, &ct->d, &ct->tx, &ct->ty, + &ct->z1, &ct->z2, &ct->zt) < 7) { + + if (wcsbuf[fr->fb_frameno-1][0]) + fprintf (stderr, "imtool: error reading WCS file\n"); + + strncpy (ct->imtitle, "[NO WCS]\n", SZ_IMTITLE); + ct->a = ct->d = 1; + ct->b = ct->c = 0; + ct->tx = ct->ty = 0; + ct->zt = W_UNITARY; + + } else + strncpy (ct->imtitle, buf, SZ_IMTITLE); + + /* Correct for the current zoom factor, if any. */ + if (fr->fb_xzoom > 1) { + if (abs(ct->a) < 1.01) + ct->tx += (ct->a > 0) ? -0.5 : 0.5; + if (abs(ct->d) < 1.01) + ct->ty += (ct->d > 0) ? -0.5 : 0.5; + ct->a = ct->a / fr->fb_xzoom; + ct->d = ct->d / fr->fb_xzoom; + } + + window_set (gio_frame, FRAME_LABEL, framelabel(), 0); + ct->valid++; + } + + /* Determine best format for wcs output. */ + if (ct->valid && ct->zt == W_LINEAR) { + float z1, z2, zrange; + z1 = ct->z1; + z2 = ct->z2; + zrange = (z1 > z2) ? z1 - z2 : z2 - z1; + if (zrange < 100.0 && (abs(z1) + abs(z2)) / 2.0 < 200.0) + format = " %7.2f %7.2f %7.3f%c"; + else if (zrange > 99999.0 || (abs(z1) + abs(z2)) / 2.0 > 99999.0) + format = " %7.2f %7.2f %7.3g%c"; + else + format = W_DEFFORMAT; + } else + format = " %7.2f %7.2f %7.0f%c"; + + strcpy (ct->format, format); + return (ct); +} + + +/* SET_WCSBOXPOS -- Set the position of the WCS output box. + */ +static +set_wcsboxpos() +{ + /* Compute offset to coordinate output box. */ + if ((wc_xoff + wc_yoff) == 0) { + wc_width = wc_font->pf_defaultsize.x * 25; + wc_height = wc_font->pf_defaultsize.y + 5; + wc_xoff = max (0, min (Fb_width, pw_rect.r_width) - wc_width + - TOOL_BORDERWIDTH); + wc_yoff = max (0, pw_rect.r_height - cb_height - wc_height + - TOOL_BORDERWIDTH); + } +} + + +/* FRAMELABEL -- Return a pointer to the frame label string for the current + * frame. + */ +static char * +framelabel() +{ + char fname[SZ_FNAME]; + char label[SZ_LABEL*2]; + + sprintf (fname, o_fname, df_p->fb_frameno, df_p->fb_imageno); + sprintf (label, "[%d] %s: %s", df_p->fb_frameno, fname, + df_p->fb_ctran.imtitle); + strncpy (df_p->fb_label, label, SZ_LABEL); + + return (df_p->fb_label); +} + + +/* GETFNAME -- Construct the pathname of a user datafile. One optional + * integer argument is permitted. + */ +static char * +getfname (rootname, arg) +char *rootname; /* root filename (printf style format) */ +int arg; +{ + static char pathname[SZ_FNAME]; + char fmt[SZ_LINE], *udir; + + /* Were we passed an absolute pathname as input? */ + if (*rootname == '/') { + strcpy (pathname, rootname); + return (pathname); + } + + if ((udir = getenv ("WCSDIR")) == NULL) + if ((udir = getenv ("wcsdir")) == NULL) + if ((udir = getenv ("HOME")) == NULL) + udir = "/tmp"; + + sprintf (fmt, "%s/%s", udir, rootname); + sprintf (pathname, fmt, arg); + + return (pathname); +} + + +/* GIO_SETCURSOR -- Set graphics frame cursor options. + */ +static +gio_setcursor (op1, op2) +int op1, op2; +{ + Cursor cursor; + int option[2], i; + int blink=cursor_blink, show=cursor_show; + + /* Normalize the argument list. */ + for (option[0]=op1, option[1]=op2, i=0; i < 2; i++) + switch (option[i]) { + case BLINK_OFF: + case BLINK_ON: + blink = option[i]; + break; + case CURSOR_OFF: + case CURSOR_ON: + show = option[i]; + break; + } + + /* Do we need to change anything? */ + if (blink == cursor_blink && show == cursor_show) + return; + + /* Modify the cursor attributes. */ + if (show == CURSOR_ON && reading_imcursor) + gio_readcursor (imcursor_wcs); + else { + cursor = window_get (gio_canvas, WIN_CURSOR); + cursor_set (cursor, + CURSOR_SHOW_CURSOR, FALSE, + CURSOR_SHOW_CROSSHAIRS, (show == CURSOR_ON), + CURSOR_CROSSHAIR_THICKNESS, 1, + CURSOR_CROSSHAIR_LENGTH, 20, + CURSOR_CROSSHAIR_GAP, 6, + +#ifdef sparc + /* This is a kludge to work around a bug with the + * sparcstation 1 under 4.0.3. */ + CURSOR_CROSSHAIR_OP, PIX_SRC ^ PIX_DST, +#else + CURSOR_CROSSHAIR_OP, PIX_SRC, +#endif + + CURSOR_CROSSHAIR_COLOR, CMS_CURSOR, + 0); + window_set (gio_canvas, WIN_CURSOR, cursor, 0); + } + + cursor_blink = blink; + cursor_show = show; +} + + +/* GIO_SETCURSORPOS -- Set the position of the graphics cursor within the + * graphics frame. + */ +static +gio_setcursorpos (x, y) +int x, y; /* pixwin pixel coords */ +{ + if (window_open) + window_set (gio_canvas, WIN_MOUSE_XY, last_bx=x, last_by=y, 0); +} + + +/* RESET_PROC -- Called from the setup panel to reset the state of the + * display. + */ +static +reset_proc() +{ + register struct pixrect *pr = get_screen_rect(); + register struct framebuf *fb; + register int i; + + stop_pan(); + blink = 0; + display_coords = 0; + setup_xoff = 4; + setup_yoff = 18; + wc_xoff = wc_yoff = 0; + state = TRACK_CURSOR; + + for (i=0; i < fb_nframes; i++) { + fb = &frames[i]; + fb->fb_xoff = 0; + fb->fb_yoff = 0; + fb->fb_xzoom = fb->fb_yzoom = 1; + fb->fb_center = fb_ngrey / 2.0; + fb->fb_slope = (float)white / (float)(fb_ngrey - 1); + fb->fb_maptype = MONO; + fb->fb_objno = 1; + fb->fb_imageno = 0; + fb->fb_frameno = i + 1; + } + + gio_xsize = initial_gio_xsize; + gio_ysize = initial_gio_ysize; + + gio_xsize = min (pr->pr_width - TOOL_BORDERWIDTH * 2, gio_xsize); + gio_ysize = min (pr->pr_height + - tool_headerheight ((int)window_get(gio_frame,FRAME_SHOW_LABEL)) + - TOOL_BORDERWIDTH, gio_ysize); + + window_set (gio_canvas, + WIN_WIDTH, gio_xsize, + WIN_HEIGHT, gio_ysize, + 0); + + window_fit (gio_canvas); + window_fit (gio_frame); + + set_frame (1); +} + + +/* MAPRECT -- Compute the intersection of the given subrect of the first rect + * with the second rect, in the coordinate system of the second. The rects + * are defined in screen coordinates, the subrects relative to their parent + * rects. + */ +maprect (r1, s1, r2, s2) +BRect *r1, *s1; /* source rect and subrect */ +BRect *r2, *s2; /* destination rect and subrect */ +{ + int xoff, yoff; + int x0, y0, x1, y1; + + /* Compute offset of second rect from the first. */ + xoff = r2->r_left - r1->r_left; + yoff = r2->r_top - r1->r_top; + + /* Translate the first subrect into the coordinate system of the + * second rect. + */ + x0 = s1->r_left - xoff; + y0 = s1->r_top - yoff; + x1 = x0 + s1->r_width - 1; + y1 = y0 + s1->r_height - 1; + + /* Does the new subrect totally miss the second rect? + */ + if (x1 < 0 || x0 >= r2->r_width || y1 < 0 || y0 >= r2->r_height) { + *s2 = *r2; + s2->r_width = s2->r_height = 0; + } else { + /* Clip the new subrect to the boundary of the second rect. + */ + if (x0 < 0) + x0 = 0; + else if (x0 >= r2->r_width) + x0 = r2->r_width - 1; + + if (x1 < 0) + x1 = 0; + else if (x1 >= r2->r_width) + x1 = r2->r_width - 1; + + if (y0 < 0) + y0 = 0; + else if (y0 >= r2->r_height) + y0 = r2->r_height - 1; + + if (y1 < 0) + y1 = 0; + else if (y1 >= r2->r_height) + y1 = r2->r_height - 1; + + /* Compute the new subrect. + */ + s2->r_left = x0; + s2->r_top = y0; + s2->r_width = x1 - x0 + 1; + s2->r_height = y1 - y0 + 1; + } + + return (s2->r_width > 0 && s2->r_height > 0); +} + + +/* BPW_GET_REGION_RECT -- Get pw_rect, transforming a Rect to a BRect. + */ +static +Bpw_get_region_rect (pw, br) +Pixwin *pw; +BRect *br; +{ + Rect r; + + pw_get_region_rect (pw, &r); + br->r_left = r.r_left; + br->r_top = r.r_top; + br->r_width = r.r_width; + br->r_height = r.r_height; +} + + +/* BPW_LOCK -- Lock a big pixwin. + */ +static +Bpw_lock (pw, br) +Pixwin *pw; +BRect *br; +{ + Rect r; + + r.r_left = br->r_left; + r.r_top = br->r_top; + r.r_width = br->r_width; + r.r_height = br->r_height; + + pw_lock (pw, &r); +} + + +/* BPW_UNLOCK -- Unlock a big pixwin. + */ +static +Bpw_unlock (pw) +Pixwin *pw; +{ + pw_unlock (pw); +} + + +/* IMAGECOPY_PROC -- Make a hardcopy of the image window on the laserwriter. + * We don't do this immediately, but rather after a delay of a few milliseconds + * to allow the window system to restore the imtool window lookup table after + * the mouse button is released. + */ +static +imagecopy_proc() +{ + static Notify_value ev_screendump(); + + window_set (gio_frame, WIN_SHOW, TRUE, 0); + imt_pause (100, ev_screendump); +} + + +/* EV_SCREENDUMP -- Called after the specified interval has passed to carry out + * the actual screendump operation. + */ +static Notify_value +ev_screendump() +{ + int depth = 8; + + edit_colormap(); + + if (snap_frame_too) { + screendump ( + (int) window_get (gio_canvas, WIN_FD), + win_get_pixwin (gio_canvas), + (int) window_get (gio_frame, WIN_WIDTH), + (int) window_get (gio_frame, WIN_HEIGHT), + (int) window_get (gio_frame, WIN_X), + (int) window_get (gio_frame, WIN_Y), + depth); + } else { + screendump ( + (int) window_get (gio_canvas, WIN_FD), + win_get_pixwin (gio_canvas), + (int) window_get (gio_frame, WIN_WIDTH) - TOOL_BORDERWIDTH * 2, + (int) window_get (gio_frame, WIN_HEIGHT) - + HEIGHTADJUST - cb_height, + (int) window_get (gio_frame, WIN_X) + TOOL_BORDERWIDTH, + (int) window_get (gio_frame, WIN_Y) + HEIGHTADJUST - + TOOL_BORDERWIDTH, + depth); + } + + return (NOTIFY_DONE); +} + + +/* IMT_PAUSE -- Suspend output for the indicated number of milliseconds, to + * allow other event processing to catch up. + */ +imt_pause (msec, ufcn) +int msec; +Notify_value (*ufcn)(); +{ + static struct itimerval itimer_delay; + + itimer_delay.it_interval.tv_usec = 0; + itimer_delay.it_interval.tv_sec = 0; + itimer_delay.it_value.tv_usec = (msec % 1000) * 1000; + itimer_delay.it_value.tv_sec = (msec / 1000); + + notify_set_itimer_func ((int)ufcn, ufcn, ITIMER_REAL, + &itimer_delay, NULL); +} + + +/* PRINT_USAGE -- Print instructions on how to use this window tool. + */ +static +print_usage (toolname) +char *toolname; +{ + printf ("no on-line help text yet for IMTOOL\n"); +} diff --git a/unix/sun/imtool.cross b/unix/sun/imtool.cross new file mode 100644 index 00000000..2e1b3532 --- /dev/null +++ b/unix/sun/imtool.cross @@ -0,0 +1,4 @@ +/* Format_version=1, Width=16, Height=16, Depth=1, Valid_bits_per_item=16 + */ + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0240,0x0180, + 0x0180,0x0240,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 diff --git a/unix/sun/imtool.cursor b/unix/sun/imtool.cursor new file mode 100644 index 00000000..b1041fe9 --- /dev/null +++ b/unix/sun/imtool.cursor @@ -0,0 +1,4 @@ +/* Format_version=1, Width=16, Height=16, Depth=1, Valid_bits_per_item=16 + */ + 0x0000,0x03E0,0x0FF8,0x1C1C,0x380E,0x3006,0x6003,0x6003, + 0x6003,0x6003,0x6003,0x3006,0x380E,0x1C1C,0x0FF8,0x03E0 diff --git a/unix/sun/imtool.h b/unix/sun/imtool.h new file mode 100644 index 00000000..e0048a28 --- /dev/null +++ b/unix/sun/imtool.h @@ -0,0 +1,13 @@ +/* IMTOOL.H -- Global definitions for IMTOOL. + */ +#define CURSOR_OFF 3 /* turn cursor off entirely */ +#define CURSOR_ON 4 /* turn it back on */ + +struct fonttab { /* Imtool font descriptor. */ + short pointsize; + char ch_xsize, ch_ysize; + short win_xsize, win_ysize; + struct pixfont *pixfont; + char *path; + char *label; +}; diff --git a/unix/sun/imtool.icon b/unix/sun/imtool.icon new file mode 100644 index 00000000..5857c1d0 --- /dev/null +++ b/unix/sun/imtool.icon @@ -0,0 +1,66 @@ +/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16 + */ + 0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000, + 0x0FFF,0xFFFF,0xFFFF,0xFFF0, + 0x0AAA,0xAAAA,0xAAAA,0xAAB0, + 0x0D55,0x5555,0x5555,0x5550, + 0x0AAA,0xAAAA,0xAAAA,0xAAB0, + 0x0D55,0x5555,0x5555,0x5550, + 0x0AAA,0xAAAA,0xAAAA,0xAAB0, + 0x0D55,0xFFFF,0xFFD5,0x5550, + 0x0AAE,0x0000,0x003A,0xBEB0, + 0x0D58,0x0000,0x0015,0x6350, + 0x0AB0,0x0000,0x000A,0xC1B0, + 0x0D50,0x0000,0x000D,0x4150, + 0x0AA7,0xE7C1,0x07E6,0xC1B0, + 0x0D61,0x8663,0x8605,0x6350, + 0x0AA1,0x8663,0x8606,0xBEB0, + 0x0D61,0x8666,0xC605,0x5550, + 0x0AA1,0x87C6,0xC7C6,0xAAB0, + 0x0D61,0x86CC,0x6605,0x5550, + 0x0AA1,0x866F,0xE606,0xBEB0, + 0x0D61,0x866C,0x6605,0x6350, + 0x0AA7,0xE66C,0x6606,0xC1B0, + 0x0D60,0x0000,0x0005,0x4150, + 0x0AA0,0x0000,0x0006,0xC1B0, + 0x0D60,0x0000,0x0005,0x6350, + 0x0AA0,0x07E6,0x6006,0xBEB0, + 0x0D60,0x0186,0x6005,0x5550, + 0x0AA0,0x0186,0x6106,0xAAB0, + 0x0D60,0x0182,0x4105,0x5550, + 0x0AA0,0x0183,0xC7C6,0xAAB0, + 0x0D60,0x0183,0xC105,0x5550, + 0x0AA0,0x0181,0x8106,0xAAB0, + 0x0D60,0x0181,0x8005,0xF7D0, + 0x0AB0,0x0181,0x8007,0x1C70, + 0x0D50,0x0000,0x000D,0x1450, + 0x0AA8,0x0000,0x001B,0x1C70, + 0x0D56,0x0000,0x0035,0xF7D0, + 0x0AAB,0xFFFF,0xFFEA,0xAAB0, + 0x0D55,0x5555,0x5555,0x5550, + 0x0AAA,0xAAAA,0xAAAA,0xAAB0, + 0x0D55,0x5555,0x5555,0x5550, + 0x0AAA,0xAAAA,0xAAAA,0xAAB0, + 0x0D55,0x5555,0x5555,0x5550, + 0x0FFF,0xFFFF,0xFFFF,0xFFF0, + 0x0001,0x8000,0x0000,0x6000, + 0x0001,0x8000,0x0000,0x6000, + 0x0001,0x8000,0x0000,0x6000, + 0x0003,0x0000,0x0000,0x3000, + 0x0003,0x0000,0x0000,0x3000, + 0x0006,0x0000,0x0000,0x1800, + 0x0006,0x0000,0x0000,0x1800, + 0x000C,0x0000,0x0000,0x0C00, + 0x000C,0x0000,0x0000,0x0C00, + 0x0018,0x0000,0x0000,0x0600, + 0x0018,0x0000,0x0000,0x0600, + 0x0038,0x0000,0x0000,0x0700, + 0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000 diff --git a/unix/sun/imtool.icon.NEW b/unix/sun/imtool.icon.NEW new file mode 100644 index 00000000..2eff06f0 --- /dev/null +++ b/unix/sun/imtool.icon.NEW @@ -0,0 +1,34 @@ +/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16 + */ + 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x88D5,0x5555,0x5555,0x5509, + 0xA2BF,0xFFFF,0xFFFF,0xFEA3,0xA260,0x0000,0x0000,0x0523, + 0x88A7,0xFE00,0xFFFF,0xF689,0x8864,0x0200,0xFFFE,0xF509, + 0xA2A7,0xFE00,0xF80F,0xB6A3,0xA260,0x0000,0xEBFF,0xF523, + 0x88A0,0x1FFF,0xF7E1,0xF689,0x8860,0x1000,0xF61E,0xF509, + 0xA2A0,0x17FE,0xF6FD,0x36A3,0xA260,0x1000,0xE6FF,0xB523, + 0x88A0,0x17FF,0xEE47,0xB689,0x886F,0xF000,0xE711,0xB509, + 0xA2A8,0x17FC,0xB3FD,0x96A3,0xA268,0x1000,0xFBFD,0xD523, + 0x88A8,0x37E0,0xFDB9,0x9689,0x8868,0x7000,0xEEFB,0xB509, + 0xA2A8,0x57FE,0xE607,0xB6A3,0xA268,0x5000,0xFBFF,0x7523, + 0x88A8,0x5400,0xFC6C,0x7689,0x8868,0x5400,0xDFC9,0xF509, + 0xA2A8,0x5000,0xFFFF,0xF6A3,0xA268,0x5000,0x0800,0x0523, + 0x88A8,0x5FFF,0xF800,0x0689,0x8868,0x441D,0x0000,0x7589, + 0xA2A8,0x8275,0x0000,0x56A3,0xA268,0x81C1,0x0000,0x7563, + 0x88A8,0x8081,0x0000,0x06B9,0x886B,0x8001,0x0007,0x750F, + 0xA2A8,0x0001,0x0005,0x56A3,0xA26F,0xFFFF,0x0007,0x7523, + 0x88A0,0x0000,0x0000,0x068B,0x887F,0xFFFF,0xFFFF,0xFD0F, + 0xA2AA,0xAAAA,0xAAAA,0xAAAF,0xA255,0x5555,0x5555,0x5533, + 0x88AA,0xAAAA,0xAAAA,0xAAA9,0x8848,0x8895,0x5548,0x88E9, + 0xA222,0x222A,0xAAA2,0x2263,0xA222,0x2215,0x5562,0x22A3, + 0x8888,0xAAAA,0xAAAA,0x8FFD,0x8888,0x5555,0x5555,0x0DB7, + 0xA222,0xAAAA,0xAAAA,0xADB7,0xA222,0x2222,0x2222,0x2B6F, + 0x8888,0x8888,0x8888,0x9B6D,0x8888,0x8888,0x8888,0x9FF9, + 0xA222,0x2222,0x2222,0x3FFB,0xA222,0x2222,0x2222,0x3FFB, + 0x8888,0x8888,0x8888,0xBFF9,0x8000,0x0000,0x0000,0xBFF9, + 0xA100,0x0000,0x00C2,0x3FF3,0xA000,0x0800,0x0042,0x2223, + 0x830D,0x9E1C,0x3840,0x8889,0x810A,0x8822,0x4440,0x8889, + 0xA10A,0x8822,0x4442,0x2223,0xA10A,0x8822,0x4442,0x2223, + 0x810A,0x8922,0x4440,0x8889,0x810A,0x861C,0x3840,0x8889, + 0xA000,0x0000,0x0002,0x2223,0xA000,0x0000,0x0002,0x2223, + 0x8888,0x8888,0x8888,0x8889,0x8888,0x8888,0x8888,0x8889, + 0xA222,0x2222,0x2222,0x2223,0xFFFF,0xFFFF,0xFFFF,0xFFFF diff --git a/unix/sun/imtool.man b/unix/sun/imtool.man new file mode 100644 index 00000000..f4af4d1c --- /dev/null +++ b/unix/sun/imtool.man @@ -0,0 +1,713 @@ +.\" @(#)imtool.1 1.1 14-Aug-87 DCT +.TH IMTOOL 1 "29 June 1989" +.SH NAME +imtool \- image display server for the SunView environment +.SH SYNOPSIS +.B imtool +[ +.B \-fbconfig \fIN\fP +] +[ +.B \-raster \fIfilename\fP +] +.ti +0.5i +[ +.B \-maptype +\fB\fR(\fPmono \fR|\fP linear \fR|\fP random \fR|\fP crandom\fR) +] +.ti +0.5i +[ +.B \-\fR[\fPno\fR]\fPcolorbar\fR +] +[ +.B \-white \fR|\fP \-black\fR +] +[ +\fIframeargs\fR +] +.SH OPTIONS +.TP +\fB\-fbconfig \fIN\fP +Specifies the initial frame buffer configuration (specifying the number and +size of the internal frame buffers) for the server. +The set of acceptable frame buffer configurations is defined in a private +or public \fIimtoolrc\fR file (discussed below). +.TP +\fB\-raster \fIfilename\fP +Specifies that the server is to start up with the image in the standard +Sun raster format file \fIfilename\fR already loaded into frame buffer 1. +The size of the specified raster need not match the size of the frame +buffer configuration specified with the \fI\-fbconfig\fR argument. +.TP +\fB\-maptype \fR(\fPmono \fR|\fP linear \fR|\fP random \fR|\fP crandom\fR)\fP +Specifies the type of greyscale mapping to be used. +\fBmono\fR means render the image in black and white (shades of gray). +\fBlinear\fR means render the image in linear pseudocolor, with the range of +displayed pixel values corresponding to a range of colors from black to blue +to green to red to white. +\fBrandom\fR means render the image in random pseudocolor, with a random +color being assigned to each greyscale value. +\fBcrandom\fR means render the image in random pseudocolor, updating the +colortable every second or so while the mouse is in the display window. +.TP +\fB\-\fR[\fPno\fR]\fPcolorbar\fR +Specifies whether or not a colorbar is to be displayed at the bottom of the +display window. The colorbar graphically illustrates the relationship between +pixel intensity and displayed color or greylevel, and is particularly useful +with pseudocolor, or when windowing the display. The minimum pixel intensity +(1) is at the left and the maximum (200) is at the right. +.TP +[\fB\-white\fR |\fP \-black\fR] +Specifies whether the image is to be displayed on a white (default) or black +background. +.TP +[\fIframeargs\fR] +\fIimtool\fR also takes generic tool arguments, used to set the position, +size, etc. of the display window; see \fIsuntools\fR(1) for a list of these +arguments. +.if t .sp 0.08i +.SH DESCRIPTION +.SS Image Display Server +.LP +\fIimtool\fR implements a simple image display server for the SunView window +environment. The server runs as an independent process, managing the display +window and listening for connections on a pseudodevice entry in \fB/dev\fR. +All communications with the server are via a simple data stream protocol +described below. +.if t .sp 0.05i +.SS Prototype Status +.LP +The current implementation of the imtool image display server is a limited +prototype, and can be expected to change substantially in the future as the +prototype continues to evolve. The main capabilities lacking in the current +version are flexibility in lookup table control, overlaid graphics and text, +miscellaneous functions such as split screen, and a fully interactive interface +to applications programs. +.if t .sp 0.05i +.SS Basic Concepts +.LP +The display server consists of a set of N \fBframe buffers\fR and a single +\fBdisplay window\fR. A frame buffer is a two dimensional array in memory +into which the image to be displayed is loaded, and which is used to refresh +the display window when portions of the window are uncovered. +In the current prototype display server only 8 bit deep frame buffers are +supported, but the number and size of the frame buffers is user configurable. +.PP +The display window is literally a window into the image stored in the frame +buffer. While the size of the frame buffer is fixed (subject to periodic +reconfiguration), the display window may be any size, and the size may be +changed at any time without affecting the contents of the frame buffer. +Likewise, the position of a small display window upon a larger frame buffer +is arbitrary and may be changed at any time by \fBpanning\fR the window +across the image. While there may be multiple frame buffers, there is only +a single display window, and only a single image may be displayed at any one +time, although a single keystroke suffices to change the frame being viewed. +.PP +With few exceptions, all display server functions are both \fIindependent\fR +and \fIasynchronous\fR. Hence, one can display one frame while another is +being loaded, or even resize or pan the display window and adjust the greyscale +mapping of a frame while the frame is being loaded. +.PP +The primary function of the display server is to provide image display and +interactive image oriented user interface capabilities to a concurrently +executing client program via a bidirectional datastream interface. +Hence, to make use of the display server for image display one also needs an +applications program capable of talking to the server, and sending it image +data to be displayed (a rudimentary builtin capability for displaying Sun +raster files is however provided). The \fBdisplay\fR program in the IRAF +\fBimages.tv\fR package is an example of such a client program. +.if t .sp 0.05i +.SS The Frame Menu +The imtool frame menu provides the following selections: +.if t .sp .05i +.if n .sp +.RS +.IP \fBFrame\fR 15 +Displays the standard SunView frame menu. +.IP \fBSetup\fR +Displays (or hides) the imtool interactive setup panel. +.IP \fBRegister\fR +Adjusts the pan offset of all frame buffers to match that of the image +currently being displayed. Normally, the individual frame buffers are +independently panned. +.IP "\fBBlink \fR[\fPon\fR|\fPoff\fR]" +Turns frame blink (alternate display of a series of frames) on or off. +Alternatively the \fBctrl/B\fR key may be used to manually cycle through +the blink frames. +.IP \fBFitFrame\fR +Adjusts the size of the display window to display the entire frame buffer. +.IP \fBNextFrame\fR +Displays the next frame buffer in sequence. +Used to cycle through and alternately display all frames +(the \fBalternate\fR or \fBctrl/F\fR and \fBctrl/R\fR keys may also be used +to cycle forward or reverse through the frames). +.IP \fBGclear\fR +Clear the graphics overlay of the frame currently being displayed. +.IP \fBIclear\fR +Clear the image, i.e., frame buffer, currently being displayed. +.IP \fBImcopy\fR +Make a hardcopy of the image window. +.RE +.if t .sp .05i +.if n .sp +.LP +The image hardcopy output function is an entry point to the general screen +capture facility, discussed in the next section. This is the same facility +used by the \fIgterm\fR program. +.if t .sp 0.05i +.SS Hardcopy Output +.LP +The image hardcopy function produces a "what you see is what you get" bitmap +of the rectangular region of the screen occupied by the display window. +If the region of interest is partially covered by another window, then the +hardcopy will be a picture of a partially covered window. Any interactive +adjustment of the grayscale mapping will be reflected in the hardcopy output. +.LP +The screen capture software reads out the full memory of the workstation in +the region of interest, and in the case of a color workstation, processes the +screen pixels through the colortable to produce an image corresponding to what +appears on the screen. No full color output options are currently provided, +hence the average of the red, green, and blue color values is next computed. +If rasterfile output is being generated, the raw pixel values and RGB color +table entries are saved directly in the rasterfile, rather than applying the +tables in software to produce a monochrome or bitmap image. +.LP +Two output options are currently provided, i.e., \fBPostscript\fR output +suitable for output directly to a laser writer to produce the final graphics +hardcopy, or \fBSun rasterfile\fR output. The default action is to output a +Postscript program to the device "lw", e.g., the Apple Laserwriter +(any 300 dpi Postscript device should do), using the dithering capability of +Postscript to produce a pseudogreyscale representation of the 8 bit output +image. These defaults may be changed by defining the following environment +variables: +.IP R_RASTERFILE +If this variable is defined a Sun rasterfile will be generated, otherwise a +Postscript plotfile is generated. The string value of the variable is a +\fIprintf\fR style format string to be used to generate the filename of +the rasterfile. If multiple rasterfiles are to be generated, the format +string may contain a decimal integer field (e.g., "\fLframe.%d\fR") to be +replaced by the \fIfile number\fR of the current rasterfile. The first file +generated will be number zero, with the file number being incremented once +for every rasterfile produced. If Postscript plotfile output is desired, +the plotfile will be a uniquely named temporary file in \fB/tmp\fR. +(Postscript output is text and you can read this file if you are curious what +it looks like). +.IP R_DISPOSE +The string value of this variable is a \fIprintf\fR style format string with +one string valued subfield to be replaced by the plotfile or rasterfile name, +to be used to generate the command used to dispose of the output file. +If this variable is not defined and the output file is a Postscript plotfile, +the default format string \fL"lpr -Plw -r -s %s"\fR will be used. +If the variable is not defined and the output file is a rasterfile, +no action is taken. It is the responsibility of the dispose command to +delete the output file. +.LP +It should only take several seconds to capture the screen and produce the +output rasterfile or queue the Postscript job to the printer. The screen +is flashed to indicated when the operation has completed (provided the user +has not turned off the \fIvisible bell\fR feature in their SunView defaults +startup file). +.PP +The Postscript processing time is usually several minutes (of laserwriter time). +Since most Postscript printers are interfaced via a serial interface at 9600 +baud, data compression is used to reduce the amount of data to be transmitted, +and the current bottleneck is the processing speed of the Postscript engine +itself, which does all the dithering and coordinate transformations. +(This is true for bitmaps, but the data compression algorithm used is not +very effective for 8 bit image data, and the serial interface can still be +a bottleneck in this case). +.if t .sp 0.05i +.SS The Setup Panel +.LP +The setup panel is used to interactively modify imtool options. +Two types of selections are provided, \fImultiple choice\fR selections, +and \fIpush button\fR selections. Clicking on a multiple choice selection +cycles through the choices (left mouse button) or displays the choices as +a menu (right mouse button). +String valued options are modified by clicking on the old value, rubbing out +all or part of the old value if necessary, and then typing in a new value +followed by return. If there several string valued fields in a panel, +return may be used to cycle through the fields. +Clicking on a push button (use the left mouse button) "pushes" the button, +causing the action indicated on the button to be executed. +.LP +The multiple choice options in the setup panel are the following: +.IP "\fBNumber of frame buffers\fR" +Specifies the number of frame buffers for which space is currently allocated. +The number of frame buffers may be changed at any time. If a client program +references a frame which does not yet exist, the number of frame buffers will +automatically be increased, hence it is not necessary to preallocate space +for the frame buffers. +.IP "\fBGreyscale mapping\fR" +Specifies the method to be used to map pixel intensity values to RGB color +intensity values. +\fBmono\fR specifies that the image is to be rendered in shades of grey. +\fBlinear pseudocolor\fR specifies that the image is to be rendered in +pseudocolor, with pixel intensities mapped into the range of colors from +black to blue to green to red to white. +\fBrandom pseudocolor\fR assigns a random color to each possible pixel +greylevel. +\fBcontinuous random pseudocolor\fR is like random pseudocolor, +but the colors are changed every few seconds, where the interval +between color changes is specified by the \fBrate\fR option below. +.IP "\fBRate (sec) for Crandom Option\fR +Specifies the frequency (1 to 32 seconds) with which new colors are to be +assigned for the continuous random pseudocolor option. +.IP "\fBBackground color\fR +Specifies the frame background color, i.e., the color to which the frame +will be set when cleared (black or white), or when displaying an image which +fills only part of the frame, the color of the portion of the frame buffer +which has not been written into. +.IP "\fBInclude Frame Border in Imcopy\fR +Specifies whether the frame border, including the frame label, is to be +included in image hardcopies. By default the frame border is included since +the frame label is often used to identify the displayed image. +If the frame border is excluded then so is the colormap, if any. +.IP "\fBShow colorbar\fR +Specifies whether or not a colorbar is to be shown at the bottom of the +display window. +.IP "\fBBlink rate (sec)\fR +When blink is enabled, specifies the amount of time a single frame is to +be displayed. The value may range from 1/2 second to 32 seconds. +The maximum blink rate may be achieved by holding down the \fBalternate\fR +key long enough to cause autorepeat. +.IP "\fBFrames to be blinked\fR +The string value of this parameter specifies the list of frames to be blinked. +The special value "all" may be specified to blink all frames in sequence. +If the frames are explicitly listed, the same frame may appear in the list +multiple times. +.IP "\fBZoom factors\fR +Specifies the positive integer zoom factors to be used for the zoom and pan +function. Up to eight zoom factors may be specified (more would +be undesirable due to the time required to cycle through the zooms to get +back to an unzoomed image). The default zoom factors are "1 2 4 8"; +depending upon the application, one might want to add, e.g., a zoom factor +of 3, or a large zoom factor of 32 or 64 to make it easy to identify +individual pixels. +.IP "\fBCoordinate list output file\fR +Specifies the name of the file to be used for cursor lists (text files +containing lists of object coordinates - see below). +.IP "\fBRaster filename (load/save)\fR +Specifies the filename of the Sun rasterfile to be loaded into the current +frame buffer (\fBload\fR push button, below), or the filename into which +to current frame is to be written (\fBsave\fR push button). +.LP +The following "push buttons" are also provided in the setup panel. +Many of these are equivalent to the comparable selections in the frame menu. +.RS +.IP "\fBRegister Frames\fR" 15 +Adjust the pan offset of all frames to match that of the current frame. +.IP "\fBFit Window\fR" +Adjust the size of the display window to match that of the frame buffer. +.IP \fBReset\fR +Reset the display. The mapping type, transfer function, and pan offsets are +restored to their initial values, but the contents of the frames are not +affected. +.IP \fBIclear\fR +Clear the frame buffer currently being displayed. +.IP \fBGclear\fR +Clear the graphics overlay (may also be cleared whenever the display window +is refreshed). +.IP \fBLoad\fR +Load the Sun rasterfile named by the \fIRaster filename\fR panel string +parameter into the frame buffer currently being displayed. +If the rasterfile is smaller than +the frame buffer the raster will be loaded into the upper left corner of +the frame buffer. If the rasterfile is larger than the frame buffer part of +the raster will be discarded. Any colortable information present in the +rasterfile is ignored. +.IP \fBSave\fR +Save the contents of the frame buffer currently being displayed in the +Sun rasterfile named by the \fIRaster filename\fR panel string parameter. +The new raster will be the same size as the frame buffer. No colortable, +WCS, or any information other than the pixel values is saved in the rasterfile. +.IP \fBBlink\fR +Turn frame blink on or off. +.IP \fBFrame\fR +Display the next frame in sequence. Equivalent to the \fBNextFrame\fR frame +menu selection, and to the \fBalternate\fR and \fBctrl/F\fR keys. +.IP \fBQuit\fR +Close the setup panel. +.RE + +.if t .sp 0.05i +.SS Function Keys +.LP +The following function keys have special significance to \fIimtool\fR: +.RS +.IP F4 15 +Calls up the setup panel, or closes it if already displayed. +.IP F5 15 +Causes the current cursor list file to be rewound and reread, marking all +objects on the cursor list by drawing a number beside each object in the +display window. Each object is marked by its ordinal number in the cursor +list, ignoring comment lines and blank lines. The precise object position +is at the lower left corner of the first digit. +Each time the cursor list is redrawn the color of the digits toggles between +black and white, making it possible for the user to manually "blink" the +object numbers, or select the representation which provides the best visibility +for their data. Note that objects are marked only in the display window, +i.e., the frame buffer is not modified, hence the numerals will be lost +whenever the display is refreshed. +.IP F6 +Enables and disables \fBcursor readout mode\fR. While cursor readout mode is +in effect a box is displayed in the lower right corner of the display window, +in which the coordinates and corresponding pixel intensity at the position of +the the mouse cursor are continuously updated as the mouse is moved. +The cursor coordinates are given in \fIworld coordinates\fR if a WCS (world +coordinate system) has been defined for the frame, otherwise display window +relative pixel coordinates and display pixel intensity values are given. +If the pixel intensity is saturated (set to the extreme high or low value), +a + or - is appended to the printed value to flag the value as saturated. +.IP F7 +Hitting this key while the mouse is in the display window causes an image +hardcopy to be generated. This is equivalent to selecting the \fBimagecopy\fR +item in the frame menu, except that it can be done without moving the mouse. +This may be important to avoid changing the greyscale mapping, which also +depends upon the mouse position. +.RE +.LP +Note that the mouse must be in the display window for these function keys to +have any effect. +.if t .sp 0.05i +.SS Mouse Buttons +.LP +The mouse buttons are used with \fIimtool\fR as follows: +.RS +.IP "Left Button" 15 +In cursor readout mode, used to mark objects, adding each object to the cursor +list for the current frame. Ignored when not in cursor readout mode. + +.IP "Middle Button" +The middle button on the mouse is the \fBpan/zoom\fR button. +If the pan button is held down and released at a position in the display +window, the object under the cursor will be moved to the center of the +display. \fBcontrol-pan\fR is the same except that the image will pan +smoothly to the new position, rather than all at once. \fBshift-pan\fR +causes the image to be panned in the indicated direction in large steps. +Shift and control may be combined to smoothly pan in large steps. +.IP +The \fBzoom\fR function is also controlled by the middle mouse button. +Placing the mouse on an object and pressing pan/zoom once causes the object +to be moved to the center of the display; pressing the button again causes +the image to be zoomed about the mouse position. Repeated presses without +moving the mouse cycle through the predefined set of zoom factors until the +cycle wraps around and the unzoomed image is restored. Zoom is almost as +fast as a normal unzoomed window refresh, so there is no problem with, +for example, panning on a zoomed image. +.IP +If the middle button is held down while in cursor readout mode the mouse may +be moved without updating the displayed cursor coordinates. This is useful +when moving the mouse to a different window, e.g., to type the displayed +object coordinates into an application running in some other window. +An attempt to pan while already at the edge of the frame is ignored. +.IP "Right Button" +Used to interactively adjust the greyscale mapping (colortable) for the window. +.RE +.LP +To window the display, i.e., adjust the \fBtransfer function\fR for the +window, hold the right mouse button down and move the cursor about within the +window. Zero contrast (one greylevel) is at the center of the window, +with positive contrast above, negative contrast below, +and contrast increasing the further the mouse is moved from the centerline. +Moving the mouse to the left or right adjusts the greyscale range to lower +or higher intensities. The colorbar provides a graphic display of the effect +of the transfer function. If the right mouse button is pressed and then +released without moving the mouse the transfer function will be adjusted +according to the position of the mouse. By alternately displaying several +frames and tapping the right mouse button for each frame without moving the +mouse, the transfer functions of several frames may be matched. +.if t .sp 0.05i +.SS Frame Buffer Configuration Files +.LP +While the prototype display server does support dynamic reconfiguration of +the frame buffers, allowing multiple frame buffers of virtually any size, +it is currently necessary to define the possible frame buffer configurations +at startup time. This is done via a table file called the \fBimtoolrc\fR +file. An example illustrating the contents of such a file is shown below. +Note that this may differ from the default configuration file used at your +site. +.sp +.nf + 1 2 512 512 # imt1|imt512 + 2 2 800 800 # imt2|imt800 + 3 2 1024 1024 # imt3|imt1024 + 4 1 1600 1600 # imt4|imt1600 + 5 1 2048 2048 # imt5|imt2048 + 6 1 4096 4096 # imt6|imt4096 + 7 1 4096 1024 # imt7|imt4x1 + 8 1 1024 4096 # imt8|imt1x4 + 9 2 1144 880 # imt9|imtfs full screen (1152x900 minus frame) + 10 2 1144 764 # imt10|imtfs35 full screen at 35mm film aspect ratio + 11 2 128 128 # imt11|imt128 + 12 2 256 256 # imt12|imt256 + + 20 2 388 576 # imt20|imtgec GEC CCD detector format + 21 1 3040 976 # imt21|imtkpca KPCA detector format (also 2D-Frutti) + 22 1 128 1520 # imt22|imt2df1 2D-Frutti + 23 1 256 1520 # imt23|imt2df2 2D-Frutti + 24 1 512 1520 # imt24|imt2df5 2D-Frutti + 25 1 960 1520 # imt25|imt2df9 2D-Frutti + 26 1 512 800 # imt26|imtcryo Cryogenic Camera + 27 1 348 800 # imt27|imtgcam Gold Camera + 28 1 976 3040 # imt28|imt2df9x3 2D-Frutti +.fi +.LP +Each entry in the file contains four numbers, the configuration number +(e.g., as used in \fI\-fbconfig N\fR), the number of frames to be created +initially (frames may be added or deleted once the configuration is +specified), and the width and height of the frame in screen pixels. +Blank lines and comments are ignored. +Note that \fIthe frame width must evenly divisible by 4\fR, +due to alignment restrictions on memory pixrects in SunView. +.LP +Selection of the frame buffer configuration to be used is done at run time +by the client application program when a frame is loaded. Since the frame +buffer size to be used is controlled by the client application program rather +than by the server, there is no entry in the setup panel for changing the +configuration. Rather, it is expected that a command will be provided +at the applications level for specifying the frame buffer size to be used. +In the case of IRAF, this is done with a command such as +\fBreset stdimage = imt800\fR, where the logical device name used on the right +is given in the comments in the configuration table above, and must +correspond to an equivalent entry in the IRAF \fBgraphcap\fR file. +The imtoolrc file may be customized by the user for special applications, +if desired, but a custom version of the graphcap file will be required too. +.LP +The frame buffer configuration file may be located in a default public +directory, e.g., \fB/usr/local/lib/imtoolrc\fR, or the user may have a +private version of the file, e.g., \fB.imtoolrc\fR. During startup, imtool +looks first for an environment variable IMTOOLRC defining the pathname of +the imtoolrc file, then it checks for a .imtoolrc file in the user's login +directory, and finally it checks for the file /usr/local/lib/imtoolrc. +If none of these are found, a default configuration of a single 512 square +frame buffer is used. +.if t .sp 0.05i +.SS World Coordinate Systems +.LP +\fIimtool\fR provides a simple mechanism for associating a linear \fBworld +coordinate system\fR (WCS) with the displayed image. A WCS consists of an +image title string to be displayed in the frame label, a rotation matrix +expressing the translation from window pixel coordinates (zero-indexed, origin +in the upper left corner of the display window) to \fIworld coordinates\fR, +e.g., the image pixel coordinates of the displayed image, and a pair of +image intensity values defining the transformation between display server +pixel intensity units (range 1-200 currently) and image pixel intensity units. +.LP +The WCS for a frame is passed to imtool as a set-WCS command in the datastream +input from the client process (applications display program). +A sample WCS descriptor is shown below. +.if t .sp 0.03i +.if n .sp +.RS +.nf +dev$pix - m51 B 600s +.br +1. 0. 0. -1. 1. 512. 0. 1481.635 1 +.fi +.RE +.if t .sp 0.03i +.if n .sp +.LP +The first line is simply a line of text to be displayed in the frame label +when the WCS is read. This should normally contain the name of the image +and a few words describing the image being displayed. +.LP +The first six numbers in the second line define a rotation matrix specifying +the translation from window pixel coordinates to world coordinates, according +to the following relations: +.if t .sp 0.03i +.if n .sp +.RS +.nf +x' = ax + cy + tx +.br +y' = bx + dy + ty +.fi +.RE +.if t .sp 0.03i +.if n .sp +The coefficients of the transformation matrix are given in the order +\fBa b c d tx ty\fR. The example defines the image pixel coordinates for a +512 square image, displayed with the origin at [1,1] in the lower left corner +of the display window. Note that the world coordinates are flipped in Y +and shifted to an origin at [1,1]. +.LP +The final three numbers on the second line define the transformation from +display pixel intensity units to image pixel intensity units. The first two +values specify the image pixel intensities corresponding to display pixel +intensities 1 and 200. The third number is an integer defining the type +of transformation used; currently the value must be 1, indicating a linear +transformation. +.LP +The WCS is initially undefined when a new frame is created. +The first cursor or function key event thereafter +which attempts to use WCS information will cause the WCS information to be +interpreted if it has been passed in via the set-WCS datastream command. +You will know if the server succeeds in reading the WCS because the +\fBframe label\fR will change when the WCS is read. +The first field of the frame label is the frame name, which will be the +filename of any cursor list files created for the frame. +.if t .sp 0.05i +.SS Coordinate List Files +.LP +Cursor readout mode provides a convenient means of displaying the cursor +coordinates, but the coordinates are lost as soon as the cursor is moved. +To permanently record the positions of objects of interest one may generate +a \fIcoordinate list file\fR by marking objects with the mouse. +The contents of existing list files may also be displayed, and one may append +to an existing list. List files generated by foreign programs may easily +be displayed. +.LP +A coordinate list file is a simple text file with the X-Y coordinate pairs of +objects recorded on successive lines in the file. +The object number is not recorded explicitly, but is determined by the +relative position of a coordinate pair within the file, ignoring comment +lines (#...) and blank lines. List files may be edited and redisplayed if +desired, and although the object numbers may change they will always agree +with whatever is shown on the screen. A hardcopy of the screen may be made +to provide a pictorial record of the contents of a list file, e.g., so that +objects may be referred to by number if the list is used as input to another +program. +.LP +The filename of the list file associated with the displayed frame is shown in +the frame label, e.g., "frame.1". By default the list file will be created +in the WCSDIR, i.e., in the directory defined by the user environment variable +WCSDIR. +.PP +These defaults may be overridden by entering via the setup panel the +\fIprintf\fR style format string to be used to construct the filename of the +list file. If the name given begins with a / an absolute pathname is assumed +and the filename is not modified in any way. Otherwise, a directory prefix +is prepended, e.g., "$wcsdir/frame.\fIN\fP". +The directory prefix is specified by the value of the WCSDIR environment +variable if defined, otherwise the user's UNIX login directory is assumed. +The frame number will appear in the generated filename only if a numeric +format is included in the format string, e.g., \fBframe.%d\fR to specify +a frame number file extension. +.if t .sp 0.05i +.SS Colortable Usage +.LP +To permit simultaneous viewing of both the display window and any other +windows under SunView, \fIimtool\fR uses only a portion of the 256 element +hardware colortable. Image pixels range in value from 1 to 200 (colortable +entry 0 is reserved for the background or foreground color by SunView). +Additional colortable entries are used for the cursor color and a set of +graphics overlay colors, reserving 50 or so colortable entries for use by +other windows. The graphics colortable entries are in the range 202-217. +These are assigned predefined colors, which are unaffected by windowing the +display. The graphics colortable assignments are summarized below. +.if t .sp 0.03i +.RS +.nf +202 black 206 blue 210 coral 214 orchid +203 white 207 yellow 211 maroon 215 turquoise +204 red 208 cyan 212 orange 216 violet +205 green 209 magenta 213 khaki 217 wheat +.fi +.RE +.if t .sp 0.03i +.PP +When imtool is started it reads the hardware color table, which is assumed to +contain the entries for the other windows on the screen, replaces entries +1 through 200+, and uses the resultant table to update the hardware colortable +thereafter at a rate of twice a second. It is necessary to continuously +update the hardware colortable to permit image display while the mouse is not +in the display window, however, this scheme will cause colortable conflicts +f one attempts to run a second window tool which also uses a large number of +colortable entries. +.if t .sp 0.05i +.SS Hints for Blinking Frames +.LP +Blink is most effective when used to compare two or more frames which are very +similar, e.g., a frame and an edited version of the same frame. For blink to +be most effective the images should be displayed as similarly as possible. +Start by loading the two frames using the same spatial and greyscale +transformation for both frames (IRAF users should use the \fBrepeat\fR +option to the \fIdisplay\fR task). Select one of the frames and adjust the +window size, pan offset, and greyscale mapping as desired. After adjusting +the greyscale with the mouse, repeatedly hit the \fBalternate\fR key followed +by the right mouse button to match the greyscale mapping of the first frame to +the remaining frames. Then select \fBregister\fR in the frame menu or setup +panel to register all the frames, followed by \fBblink\fR to blink the frames. +Blink works best if the display window is not too large, e.g., a 400 or 500 +pixel square window is fine. +.if t .sp 0.05i +.SS Data Stream Protocol +.LP +The display server is started like any other SunView tool by executing the +\fIimtool\fR command either directly or indirectly via the \fB.suntools\fR +file or via the mouse from the \fBrootmenu\fR. When first started a checkered +test pattern is displayed, and the display server opens the pseudodevice +files \fB/dev/imt1o\fR (used by the client to send commands and data to the +display server) and \fB/dev/imt1i\fR (for data read back from the display +server) and begins listening for commands from client programs. +All commands and data are passed to the display server as a data stream by +applications writing directly to /dev/imt1o. +.LP +The data stream protocol used +in the prototype server (this will change) mimics that of the IIS Model 70 +image display, with an extension added for specifying the frame buffer +configuration to be used. The server will automatically sense if the +datastream is byte swapped, allowing use of the server with, for example, +IRAF running on a large VAX compute server. Only byte packed data is +supported. +.LP +Note that any process may write to the server, but if more +than one process writes to the server at the same time, the output may be +garbled. Also, multiple display servers may be spawned, but since only a +single pseudodevice entry is currently supported, all such servers would be +trying to read from the same input stream. +.SH SEE ALSO +suntools(1), gterm(1), images.tv.display(IRAF) +.br +\fIWindows and Window-Based Tools: Beginner's Guide\fR +.SH ENVIRONMENT +.IP IMTOOLRC 15 +The full pathname of the \fIimtoolrc\fR (frame buffer configuration) file +to be used (optional). +.IP WCSDIR +The full pathname of the user directory +into which imtool will write any files it creates that are +not specified by a full pathname (alias \fBwcsdir\fR also permitted). +.IP R_RASTERFILE +If defined, a Sun rasterfile rather than Postscript file is generated by +the \fIimcopy\fR function. The string value is a format used to generate +the filename of the rasterfile. +.IP R_DISPOSE +The command to be executed to dispose of the Sun rasterfile or Postscript +output file created by \fIimcopy\fR. If not defined and Postscript output is +indicated (R_RASTERFILE also not defined), then the Postscript output file +is disposed of via \fIlpr\fR to device \fIlw\fR. +.SH FILES +.LP +.nf +/dev/imt1[io] +$WCSDIR/frame.* +/usr/bin/suntools +/usr/lib/rootmenu +$iraf/local/sun/imtool.c +.fi +.SH BUGS +.IP (1) +The display server is continuously updating the hardware colortable even while +the mouse is not in the display window. This is necessary to be able to see +the image while the mouse is not in the window, but may interfere with other +windows which also use many colortable entries. Under normal circumstances +(only one greyscale window) this should not be a problem. If it is a problem, +close the display window when not in use; updating of the hardware colortable +is disabled while the display window is closed. +.IP (2) +Only a single display server should be used at any one time. +Only a single client process should write to the server at any one time. +.IP (3) +The environment variables affecting IMTOOL operation must be defined before +starting suntools if they are to have any effect. +.IP (4) +An error message is printed if imtool encounters a bad data header checksum, +e.g., if synchronization is lost on the input datastream or if illegal data +is input. Recovery from such an error can be difficult, possibly requiring +killing the imtool and starting a new one. This error should not occur if the +software (i.e., the client applications program) is functioning properly. +.SH AUTHOR +Doug Tody, National Optical Astronomy Observatories (NOAO), IRAF project. diff --git a/unix/sun/imtool.square b/unix/sun/imtool.square new file mode 100644 index 00000000..cb54f6eb --- /dev/null +++ b/unix/sun/imtool.square @@ -0,0 +1,4 @@ +/* Format_version=1, Width=16, Height=16, Depth=1, Valid_bits_per_item=16 + */ + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x03C0,0x03C0, + 0x03C0,0x03C0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 diff --git a/unix/sun/imtoolrc b/unix/sun/imtoolrc new file mode 100644 index 00000000..b20a9544 --- /dev/null +++ b/unix/sun/imtoolrc @@ -0,0 +1,48 @@ +# IMTOOL -- Defined frame buffer configurations. Note that the given nframes +# is only a starting point, and may be modified during execution, hence smaller +# values are preferred. The configuration numbers may be given in any order, +# but must be unique and in the range 1-128. NOTE - corresponding entries must +# be present in the dev$graphcap file, for use with IRAF. +# +# Format: configno nframes width height + + 1 2 512 512 # imt1|imt512 + 2 2 800 800 # imt2|imt800 + 3 2 1024 1024 # imt3|imt1024 + 4 1 1600 1600 # imt4|imt1600 + 5 1 2048 2048 # imt5|imt2048 + 6 1 4096 4096 # imt6|imt4096 + 7 1 4096 1024 # imt7|imt4x1 + 8 1 1024 4096 # imt8|imt1x4 + 9 2 1144 880 # imt9|imtfs full screen (1152x900 minus frame) +10 2 1144 764 # imt10|imtfs35 full screen at 35mm film aspect ratio +11 2 128 128 # imt11|imt128 +12 2 256 256 # imt12|imt256 +13 2 128 1056 # imt13|imttall128 tall & narrow for spectro. +14 2 256 1056 # imt14|imttall256 tall & wider for spectro. +15 2 1056 128 # imt15|imtwide128 wide & thin for spectro. +16 2 1056 256 # imt16|imtwide256 wide & fatter for spectro. + +# Some site specific formats for NOAO. +20 2 388 576 # imt20|imtgec GEC CCD detector format +21 1 3040 976 # imt21|imtkpca KPCA detector format (also 2D-Frutti) +22 1 128 1520 # imt22|imt2df1 2D-Frutti +23 1 256 1520 # imt23|imt2df2 2D-Frutti +24 1 512 1520 # imt24|imt2df5 2D-Frutti +25 1 960 1520 # imt25|imt2df9 2D-Frutti +26 1 512 800 # imt26|imtcryo Cryogenic Camera +27 1 348 800 # imt27|imtgcam Gold Camera +28 1 976 3040 # imt28|imt2df9x3 2D-Frutti +29 1 800 256 # imt29|imtgong Gong Cache Monitor +30 1 256 800 # imt30|imtgong Gong Cache Monitor +31 1 1240 400 # imt31|imtret Reticon CCD detector format +32 2 832 800 # imt32|imtti|imtti2|imtti3 +33 2 544 512 # imt33|imtt5ha|imttek2 +34 1 1056 1024 # imt34|imtt1ka|imtte1k|imtst1k +35 1 2080 2048 # imt35|imts2ka|imtt2kb|imtst2k|imtt2k2 +36 1 2048 2080 # imt36|imtt2ka|imtte2k +37 1 3104 1024 # imt37|imtf3ka|imtfo3k + +# User added formats. (start with #64) +# (add here) + diff --git a/unix/sun/mksuntool.csh b/unix/sun/mksuntool.csh new file mode 100755 index 00000000..0c7a4175 --- /dev/null +++ b/unix/sun/mksuntool.csh @@ -0,0 +1,39 @@ +#! /bin/csh +# MKSUNTOOL -- Configure the suntool subdirectory, used to link the suntools +# executable. (Only used for SunOS versions prior to 4.0). + +# set echo + +unset noclobber +unalias cd cmp echo ln mv rm sed set + +set OBJS = "imtool.o gterm.o gtermio.o screendump.o arrow.o notify_read.o" +set sundir = /usr/src/sun/suntool + +if (! -e ./suntool) then + mkdir suntool +endif +cd suntool + +cmp -s Makefile $sundir/Makefile +if ($status == 0 && `grep gterm basetools.h` != "") then + echo "suntool build directory is up to date" + exit 0 +else if (! -e $sundir/Makefile) then + echo "$sundir not found" + exit 1 +else + echo "rebuilding suntool subdirectory" +endif + +set files = "`ls`" +if ("$files" != "") then + rm -rf * +endif +(cd $sundir; tar -cf - . ) | tar -xpf - +echo '"gterm",gterm_main,' >> basetools.h +echo '"imtool",imtool_main', >> basetools.h +echo '/cmdtool_main/i\' > Temp +echo 'extern imtool_main();\' >> Temp +echo 'extern gterm_main();' >> Temp +sed -f Temp toolmerge.c > Temp2; mv -f Temp2 toolmerge.c; rm Temp diff --git a/unix/sun/mouse.c b/unix/sun/mouse.c new file mode 100644 index 00000000..a7d4b538 --- /dev/null +++ b/unix/sun/mouse.c @@ -0,0 +1,47 @@ +/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + */ + +#include <suntool/sunview.h> + +/* MOUSE.C -- Routines for saving and restoring the mouse position. These + * are used by a window which needs to grab the mouse and set it to a specific + * position, e.g., because the user has entered a command in to another window + * requesting a cursor read by the process running in the current window. + * (It was NOT easy to figure out how to do this in SunView, but at least I + * was able to do it...). + */ + +/* GET_ABSMOUSEPOS -- Get the current position of the mouse in absolute screen + * coordinates. + */ +get_absmousepos (mywinfd, x, y) +int mywinfd; /* any window on current screen will do */ +int *x, *y; /* mouse position (output) */ +{ + struct screen rootscreen; + int rootfd; + + win_screenget (mywinfd, &rootscreen); + rootfd = open (rootscreen.scr_rootname, 0); + + *x = win_get_vuid_value (rootfd, LOC_X_ABSOLUTE); + *y = win_get_vuid_value (rootfd, LOC_Y_ABSOLUTE); + + close (rootfd); +} + + +/* SET_ABSMOUSEPOS -- Set the mouse position in absolute screen coordinates. + */ +set_absmousepos (mywinfd, x, y) +int mywinfd; /* any window on current screen will do */ +int x, y; /* desired mouse position */ +{ + struct screen rootscreen; + int rootfd; + + win_screenget (mywinfd, &rootscreen); + rootfd = open (rootscreen.scr_rootname, 0); + win_setmouseposition (rootfd, x, y); + close (rootfd); +} diff --git a/unix/sun/notify_read.c b/unix/sun/notify_read.c new file mode 100644 index 00000000..b02913c9 --- /dev/null +++ b/unix/sun/notify_read.c @@ -0,0 +1,85 @@ +/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + */ + +#include <syscall.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <stdio.h> + +static int (*u_fcn)(); /* user functions to process read */ +static int u_fd; /* fd to be monitored */ + +/* NOTIFY_READ -- This is a customized version of the SunView 3.2 notify_read + * primitive, the notifier's version of the UNIX read() system call (when + * the notifier is used, read() is a high level function, not a system call). + * The function of this special version of notify_read is to intercept kernel + * read calls made by the notifier for the purposes of monitoring, and + * possibly filtering, low level input from a file descriptor. + */ +notify_read (fd, buf, maxch) +int fd; +char *buf; +int maxch; +{ + register int n; + + /* This is a bit of a kludge, but lacking the shelltool source it + * was difficult to do better. The 18 is the size of the tty packet + * echoed by the driver when a character is typed; this is not part + * of the normal output stream so we exclude these events. The buf+1 + * business is to hide the packet mode nature of the stream from the + * gtermio code; the first byte of each packet indicates the packet + * type. These details could change in a future Sun release in which + * case this code would have to be modified. + */ + if (u_fcn && fd == u_fd && maxch != 18) { + n = syscall (SYS_read, fd, buf, maxch); + if (n > 0 && *buf == TIOCPKT_DATA) + return ((*u_fcn)(buf+1, n-1, maxch-1) + 1); + else + return (n); + } else + return (syscall (SYS_read, fd, buf, maxch)); +} + + +/* READV -- This is a customized version of the readv system call, used in + * the Release 3.4 version of ttysw to read from the pty. Usage is (appears + * to be) identical to the old notify_read, except that the TIOCPKT byte is + * returned separately from the data. + */ +readv (fd, iov, iovcnt) +register int fd; +register struct iovec *iov; +int iovcnt; +{ + register int n; + + if (u_fcn && fd == u_fd && iovcnt == 2 && iov[0].iov_len == 1) { + n = syscall (SYS_readv, fd, iov, iovcnt); + if (n > 0 && *(iov[0].iov_base) == TIOCPKT_DATA) + return ((*u_fcn)(iov[1].iov_base, n-1, iov[1].iov_len) + 1); + else + return (n); + } else + return (syscall (SYS_readv, fd, iov, iovcnt)); +} + + +/* NOTIFY_READ_POST_MONITOR_FCN -- Post a user data monitor/filter function + * to process the input on the specified file descriptor. Only one file + * descriptor can be monitored at present. + */ +notify_read_post_monitor_fcn (fd, fcn) +int fd; +int (*fcn)(); +{ + if (u_fcn && !fcn) + return (-1); + else { + u_fcn = fcn; + u_fd = fd; + return (0); + } +} diff --git a/unix/sun/screendump.c b/unix/sun/screendump.c new file mode 100644 index 00000000..a3582e57 --- /dev/null +++ b/unix/sun/screendump.c @@ -0,0 +1,549 @@ +/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + */ + +#include <suntool/sunview.h> +#include <suntool/fullscreen.h> +#include <pixrect/pr_planegroups.h> +#include <stdio.h> +#include <pwd.h> + +#define SEGSIZE 16 /* output segment size (bytes) */ +#define SEGBITS (SEGSIZE*8) +#define BITFLIP 0 /* bit-flip each byte for P.S.? */ +#define NGREY 256 /* max color table size */ +#define PAGE_WIDTH 2550 /* 8.5x11, 300 dpi */ +#define PAGE_HEIGHT 3300 /* 8.5x11, 300 dpi */ +#define PAGE_XOFFSET 0 /* offset to drawing area */ +#define PAGE_YOFFSET 0 /* offset to drawing area */ +#define MARGIN 150 /* 1/2 inch margin */ +#define MAXGROUPS (PIXPG_OVERLAY+1) + +#define RT_DATA 'a' /* record type codes */ +#define RT_ZERO 'b' +#define RT_FULL 'c' +#define RT_BKG1 'd' +#define RT_BKG2 'e' +#define BKGPAT_1 "22" /* atom for stipple pattern */ +#define BKGPAT_2 "88" /* atom for stipple pattern */ + +/* The following are provided by the calling program and specify what type + * of output is desired. + */ +extern int r_type; /* 0=postscript, 1=rasterfile */ +extern char r_dispose[]; /* dispose command */ +extern char r_filename[]; /* output file template */ + +int gt_bitflip_postscript = BITFLIP; +static unsigned char red[NGREY], green[NGREY], blue[NGREY]; +static void bitmap_to_postscript(); +static char *make_label(); + + +/* SCREENDUMP -- Make a hardcopy of the indicated region of the screen on a + * hardcopy device. Currently only two output formats are supported, Sun + * rasterfile output, or Postscript. A dispose command may be given to + * postprocess the output file, e.g., send it to the printer. + */ +screendump (win_fd, pw, width, height, left, top, nbits_out) +int win_fd; /* window fd, for bell */ +struct pixwin *pw; /* arbitrary pixwin, used to lock display */ +int width, height; /* region to be printed: size, */ +int left, top; /* origin */ +int nbits_out; /* output 1 bit or 8 bit postscript image? */ +{ + register int v, i, j; + register unsigned char *ip, *op; + unsigned char *pr_data, *obuf, *zero; + + struct rect pw_r; + struct timeval tv_bell; + struct pixrect *screen, *s_pr, *o_pr, *m_pr; + static int filenum = 0; + + float scale, xs, ys; + int overlay, ngroups; + char groups[MAXGROUPS]; + char tempfile[80], dispose[80]; + int depth, cache_v, cache_greyval, rasterout; + int status=0, bit, byte, pr_linebytes, ob_linebytes, fd; + char *str, *getenv(); + FILE *fp; + + /* Open the hardware frame buffer, create a memory pixrect to hold user + * specified rect, lock the display and read in the data and colormap. + * The Sun 3-110, 3/60, etc., have separate monochrome and color + * planes plus an overlay-enable plane, whereas the older frame buffers + * have only a single monochrome or color plane. + */ + screen = pr_open ("/dev/fb"); + + depth = screen->pr_depth; + ngroups = pr_available_plane_groups (screen, MAXGROUPS, groups); + overlay = (ngroups >= PIXPG_OVERLAY); + + /* Get memory pixrects to hold frame buffer data. */ + zero = (unsigned char *) malloc (height); + s_pr = mem_create (width, height, depth); + if (overlay) { + o_pr = mem_create (width, height, 1); + m_pr = mem_create (width, height, 1); + } + + /* Lock the frame buffer to avoid edits during readout. */ + pw_get_region_rect (pw, &pw_r); + pw_lock (pw, &pw_r); + + /* Get the color map and the main frame buffer pixrect. */ + pr_getcolormap (screen, 0, NGREY, red, green, blue); + pr_set_plane_group (s_pr, PIXPG_8BIT_COLOR); + pr_rop (s_pr, 0, 0, width, height, PIX_SRC, screen, left, top); + + /* If the device has an overlay plane, readout it out as well as the + * enable plane. + */ + if (overlay) { + int o_pg; + o_pg = pr_get_plane_group (screen); + pr_set_plane_group (screen, PIXPG_OVERLAY); + pr_rop (o_pr,0,0, width, height, + PIX_SRC, screen, left, top); + pr_set_plane_group (screen, PIXPG_OVERLAY_ENABLE); + pr_rop (m_pr,0,0, width, height, + PIX_SRC, screen, left, top); + pr_set_plane_group (screen, o_pg); + } + + pw_unlock (pw); + pr_close (screen); + + /* Combine the color plane and overlay plane to produce a single + * color plane. Use only those overlay plane pixels which have their + * bit set in the enable plane. + */ + if (overlay) { + pr_stencil (s_pr,0,0, width, height, + PIX_COLOR(255) | PIX_SRC | PIX_DONTCLIP, m_pr,0,0, o_pr,0,0); + pr_close (m_pr); + pr_close (o_pr); + } + + /* Output can be either Postscript or a Sun rasterfile. Rasterfile + * output is handled here. + */ + if (rasterout = (r_type && r_filename[0])) { + colormap_t cmap; + + /* Setup colormap descriptor. */ + cmap.type = RMT_EQUAL_RGB; + cmap.length = NGREY; + cmap.map[0] = red; + cmap.map[1] = green; + cmap.map[2] = blue; + + /* Open raster file. */ + sprintf (tempfile, r_filename, filenum++); + if ((fp = fopen (tempfile, "w")) == NULL) { + fprintf (stderr, "cannot create %s\n", tempfile); + return (-1); + } + + pr_dump (s_pr, fp, &cmap, RT_STANDARD, 0); + + fclose (fp); + pr_close (s_pr); + goto dispose_; + } + + /* If the frame buffer is only 1 bit deep we can set obuf to point + * to the pixrect data and we are done. Otherwise we must process + * the image pixels through the color table and convert the output + * into a monochrome pixrect. NOTE: the bits may need to be flipped + * in the monochrome pixrect to satisfy Postscript; I wasn't sure. + */ + if (depth == 1) { + /* This option is currently untested. */ + obuf = (unsigned char *) mpr_d(s_pr)->md_image; + ob_linebytes = mpr_d(s_pr)->md_linebytes; + + if (gt_bitflip_postscript) { + unsigned char flip[256]; + + /* Set up lookup table. */ + for (j=0; j < 256; j++) { + for (v=0, i=0; i < 8; i++) + v |= (((j >> i) & 1) << (7-i)); + flip[j] = v; + } + + /* Bitflip and set the zero-line vector. */ + for (j=0; j < height; j++) { + v = 1; + for (op=obuf+j*ob_linebytes, i=ob_linebytes; --i >= 0; ) { + if (v && *op) + v = 0; + *op++ = flip[*op]; + } + zero[j] = v; + } + } else { + /* Set the zero-line vector for the pixrect. */ + for (j=0; j < height; j++) { + v = 1; + for (op=obuf+j*ob_linebytes, i=ob_linebytes; --i >= 0; ) { + if (v && *op) { + v = 0; + break; + } + } + zero[j] = v; + } + } + + } else if (nbits_out == 1) { + ob_linebytes = (width + 7) / 8; + obuf = (unsigned char *) calloc (ob_linebytes * height, 1); + if (obuf == NULL) { + fprintf (stderr, "out of memory\n"); + return (-1); + } + pr_data = (unsigned char *) mpr_d(s_pr)->md_image; + pr_linebytes = mpr_d(s_pr)->md_linebytes; + + for (j=0, cache_v=(-1); j < height; j++) { + ip = pr_data + j * pr_linebytes; + op = obuf + j * ob_linebytes; + + for (byte=(-1), i=0; i < width; i++) { + if ((v = ip[i]) == cache_v) + v = cache_greyval; + else { + cache_v = v; + v = cache_greyval = (red[v] + green[v] + blue[v]) / 3; + } + if (v <= NGREY/2) { + byte = i / 8; + bit = 8 - (i % 8) - 1; + op[byte] |= (1 << bit); + } + } + + /* Set flag if entire line is zero. */ + zero[j] = (byte < 0); + } + + pr_close (s_pr); + + } else if (nbits_out == 8 && depth == 8) { + /* Eight bits out; transform the image in place in the input + * pixrect to save memory. + */ + obuf = pr_data = (unsigned char *) mpr_d(s_pr)->md_image; + ob_linebytes = pr_linebytes = mpr_d(s_pr)->md_linebytes; + + for (j=0, cache_v=(-1); j < height; j++) { + ip = pr_data + j * pr_linebytes; + op = obuf + j * ob_linebytes; + + for (i=0; i < width; i++) { + if ((v = ip[i]) == cache_v) + v = cache_greyval; + else { + cache_v = v; + v = cache_greyval = (red[v] + green[v] + blue[v]) / 3; + } + op[i] = v; + } + + /* Set flag if entire line is zero. */ + zero[j] = 0; + } + + } else { + fprintf (stderr, "can only create 1 bit or 8 bit output image\n"); + return (-1); + } + + /* Create the output file to hold postscript program. If no filename + * has been specified create a unique file in /tmp. + */ + if (!r_filename[0]) { + strcpy (tempfile, "/tmp/psXXXXXX"); + if ((fd = mkstemp (tempfile)) == -1) { + fprintf (stderr, "cannot create temporary file %s\n", tempfile); + return (-1); + } else + fp = fdopen (fd, "a"); + } else { + sprintf (tempfile, r_filename, filenum++); + if ((fp = fopen (tempfile, "w")) == NULL) { + fprintf (stderr, "cannot create %s\n", tempfile); + return (-1); + } + } + + /* Scale to fit output page. */ + xs = (PAGE_WIDTH - MARGIN*2) / (float)width; + ys = (PAGE_HEIGHT - MARGIN*2) / (float)height; + scale = (xs < ys) ? xs : ys; + + /* Translate the bitmap into a postscript program. */ + bitmap_to_postscript (fp, + obuf, width, height, nbits_out, ob_linebytes, zero, scale); + + free ((char *)zero); + if (depth == 1 || (depth == 8 && nbits_out == 8)) + pr_close (s_pr); + else + free ((char *)obuf); + + fclose (fp); + close (fd); + + /* Dispose of tempfile to the printer. We leave it up to the dispose + * command to delete the temporary file when finished. + */ +dispose_: + if (r_dispose[0]) { + sprintf (dispose, r_dispose, tempfile); + if ((status = system (dispose)) != 0) + fprintf (stderr, "screendump: exit status %d\n", status); + } + + /* Flash the screen to signal the user that we are done. */ + tv_bell.tv_usec = 0*1000; tv_bell.tv_sec = 0; + win_bell (win_fd, tv_bell, pw); + + return (status); +} + + +/* BITMAP_TO_POSTSCRIPT -- Translate a memory bitmap into a postscript program + * using image compression where regions of the image are all zeroes. This is + * done as follows: [1] lines of the bitmap are divided into segments of N + * bytes, [2] if all N bytes are zero a single zero byte is transmitted, + * otherwise a byte with the value one is transmitted, followed by N bytes of + * literal data. Lines which are entirely zero are not transmitted at all. + * The goal is to significantly reduce the amount of data to be pushed through + * the laserwriter serial interface while keeping things simple enough that + * postscript will hopefully be able to process the bitmap efficiently. + * + * NOTE: Postscript is supposed to be able to copy bitmaps directly without + * any transformations if all the right conditions are met, e.g., unitary + * matrices, pixrect resolution matches device resolution, etc. We do not + * make use of this here due to the great volume of data which would have to + * pushed through the laserwriter serial interface at 9600 baud to transmit + * a fully resolved bitmap. If a parallel interface were available, e.g., + * if the laserwriter is on the ethernet, then this would be the way to go. + */ +static void +bitmap_to_postscript (fp, bitmap, width, height, depth, linebytes, zero, scale) +register FILE *fp; +unsigned char *bitmap; +int width, height, depth; +int linebytes; +unsigned char *zero; +float scale; +{ + register unsigned char *ip; + register char *op, *hp; + register int n; + unsigned char *segp; + char hbuf[NGREY*2]; + char obuf[SEGSIZE*2]; + char rt_full[SEGSIZE*2+1]; + char bkg_1[SEGSIZE*2+1]; + char bkg_2[SEGSIZE*2+1]; + int partseg, seg, nsegs, allzeroes, i, j, last_j; + + /* Initialize the hbuf array, which contains the hex encoded + * representations of the NGREY possible binary byte values. + */ + for (n=0, op=hbuf; n < NGREY; n++) { + i = ((n >> 4) & 017); + *op++ = (i < 10) ? i + '0' : (i-10) + 'A'; + i = (n & 017); + *op++ = (i < 10) ? i + '0' : (i-10) + 'A'; + } + + /* Set up the background (stipple) pattern arrays, used to represent + * the Sunview background pattern outside of windows. + */ + for (op=bkg_1, hp=BKGPAT_1, n=SEGSIZE; --n >= 0; ) { + *op++ = hp[0]; + *op++ = hp[1]; + } *op++ = '\0'; + for (op=bkg_2, hp=BKGPAT_2, n=SEGSIZE; --n >= 0; ) { + *op++ = hp[0]; + *op++ = hp[1]; + } *op++ = '\0'; + + /* RT_FULL is a solid line, another common pattern. */ + for (op=rt_full, n=SEGSIZE*2; --n >= 0; ) + *op++ = 'F'; + *op++ = '\0'; + + /* Initialize obuf, in case a partseg call causes the full buffer to + * be written out before the garbage elements at the end have been + * initialized to legal values. + */ + bcopy (rt_full, obuf, SEGSIZE*2); + + /* Define the postscript necessary to receive and output the lines + * of the pixrect with image compression. + */ + fprintf (fp, "%%! GTERM screendump\n"); + fprintf (fp, "erasepage initgraphics\n"); + + /* fprintf (fp, "[%6.3f 0 0 %6.3f 2350 3180] setmatrix\n", + -scale, -scale); */ + fprintf (fp, "initmatrix\n"); + fprintf (fp, "%6.3f 72 mul 300 div\n", -scale); + fprintf (fp, "%6.3f 72 mul 300 div scale\n", scale); + fprintf (fp, "%f %f translate\n", 2409/(-scale), (-88)/(-scale)); + + fprintf (fp, "%d %d translate\n", PAGE_XOFFSET, PAGE_YOFFSET); + fprintf (fp, "/r_data %d string def\n", SEGSIZE); + fprintf (fp, "/r_zero %d string def\n", SEGSIZE); + fprintf (fp, "/r_full %d string def\n", SEGSIZE); + fprintf (fp, "/r_bkg1 %d string def\n", SEGSIZE); + fprintf (fp, "/r_bkg2 %d string def\n", SEGSIZE); + fprintf (fp, "currentfile r_full readhexstring %s\n", rt_full); + fprintf (fp, "currentfile r_bkg1 readhexstring %s\n", bkg_1); + fprintf (fp, "currentfile r_bkg2 readhexstring %s\n", bkg_2); + fprintf (fp, "clear\n"); + + if (depth == 8) { + fprintf (fp, + "/dline {0 exch translate %d %d 8 matrix\n", width, 1); + } else { + fprintf (fp, + "/dline {0 exch translate %d %d true matrix\n", width, 1); + } + + fprintf (fp, " { currentfile read pop dup %d eq\n", RT_DATA); + fprintf (fp, " { pop currentfile r_data readhexstring pop }\n"); + fprintf (fp, " { dup %d eq\n", RT_ZERO); + fprintf (fp, " { pop r_zero }\n"); + fprintf (fp, " { dup %d eq\n", RT_FULL); + fprintf (fp, " { pop r_full }\n"); + fprintf (fp, " { %d eq\n", RT_BKG1); + fprintf (fp, " { r_bkg1 }\n"); + fprintf (fp, " { r_bkg2 }\n"); + fprintf (fp, " ifelse }\n"); + fprintf (fp, " ifelse }\n"); + fprintf (fp, " ifelse }\n"); + fprintf (fp, " ifelse\n"); + + if (depth == 8) + fprintf (fp, " } image} def\n"); + else + fprintf (fp, " } imagemask} def\n"); + + nsegs = width / (SEGBITS / depth); + partseg = linebytes - (nsegs * SEGSIZE); + + /* Output successive lines of the pixrect. All zero lines are omitted + * and data compression is used for large regions of zeroes embedded + * within a line. + */ + for (j=0, last_j=0; j < height; j++) { + if (zero[j]) + continue; + + fprintf (fp, "\n%d dline\n", j - last_j); + last_j = j; + + /* Output an integral number of line segments in hexstring format, + * i.e., two hex digits output per binary input byte. + */ + segp = bitmap + j*linebytes; + for (seg=0; seg < nsegs; seg++, segp += SEGSIZE) { + /* Quick scan of the data to see if it is all zeroes. */ + allzeroes = 1; + for (ip=segp, n=SEGSIZE; --n >= 0; ) + if (*ip++) { + allzeroes = 0; + break; + } + + if (allzeroes) { + putc (RT_ZERO, fp); + } else { + /* Encode the data segment in hex format. */ + for (ip=segp, op=obuf, n=SEGSIZE; --n >= 0; ) { + hp = hbuf + (*ip++ * 2); + *op++ = *hp++; + *op++ = *hp++; + } + + if (obuf[0] == rt_full[0] && + strncmp (obuf, rt_full, SEGSIZE*2) == 0) { + putc (RT_FULL, fp); + } else if (obuf[0] == bkg_1[0] && + strncmp (obuf, bkg_1, SEGSIZE*2) == 0) { + putc (RT_BKG1, fp); + } else if (obuf[0] == bkg_2[0] && + strncmp (obuf, bkg_2, SEGSIZE*2) == 0) { + putc (RT_BKG2, fp); + } else { + putc (RT_DATA, fp); + fwrite (obuf, SEGSIZE*2, 1, fp); + } + } + } + + /* Write out any partial segment at the end of the line. We must + * always write a full segment, even if the data at the end is + * garbage, else synchronization will be lost. + */ + if (partseg) { + for (op=obuf, n=partseg; --n >= 0; ) { + hp = hbuf + (*ip++ * 2); + *op++ = *hp++; + *op++ = *hp++; + } + putc (RT_DATA, fp); + fwrite (obuf, SEGSIZE*2, 1, fp); + } + } + + /* Add the NOAO logo and timestamp at the bottom of the page and + * output the page. + */ + fprintf (fp, "\n"); + fprintf (fp, "/Times-Roman findfont 24 scalefont setfont\n"); + + /* fprintf (fp, "[-1 0 0 -1 2350 3180] setmatrix\n"); */ + fprintf (fp, "initmatrix\n"); + fprintf (fp, "-1 72 mul 300 div 1 72 mul 300 div scale\n"); + fprintf (fp, "-2409 88 translate\n"); + + fprintf (fp, "%d %d moveto\n", 1600, 3150); + fprintf (fp, "[1 0 0 -1 0 0] concat\n"); + fprintf (fp, "(%s) show\n", make_label()); + fprintf (fp, "showpage\n"); +} + + +/* MAKE_LABEL -- Generate the label for the output printer page. + */ +static char * +make_label() +{ + static char buf[128]; + char hostname[32]; + char username[32]; + struct passwd *pw; + long clock; + + clock = time(0); + gethostname (hostname, 32); + pw = getpwuid (getuid()); + strcpy (username, pw->pw_name); + endpwent(); + + sprintf (buf, "NOAO/IRAF %s@%s %s", + username, hostname, asctime(localtime(&clock))); + + return (buf); +} diff --git a/unix/sun/ss1.patch b/unix/sun/ss1.patch new file mode 100644 index 00000000..dcd0ce15 --- /dev/null +++ b/unix/sun/ss1.patch @@ -0,0 +1,31 @@ +This is to fix the "chicken scratches" bug that occurs with IMTOOL on a +sparcstation. The problem occurs due to a bug in the SunOS kernel for the +sparcstation. The patch given here is a workaround to avoid the problem +until Sun fixes the bug. + +To patch the imtool executable, login as iraf, then make a backup copy of +the imtool.e executable and patch the online one, as follows (be sure to +get the case of the ?X and ?W right): + + % cd $iraf/unix/bin.sparc + % cp imtool.e imtool.e.OLD + % + % adb -w imtool.e + 0xc2a0?X +* 0xc2a0: ac102018 + 0xc2a0?W0xac10200c +* 0xc2a0: 0xac102018 = 0xac10200c + $q + % + +In the sequence shown above, the lines marked * are adb output. If the old +value of location 0xc2a0 is not ac102018 (hex) as shown, then you have an +old or otherwise unusual version of IMTOOL and the patch should not be +applied. Once the executable has been patched, either copy the new executable +to /usr/bin/imtool (or wherever imtool lives on your system) or rerun the +INSTALL script in $hlib. + +The fix changes the rasterop used to draw the IMTOOL crosshair cursor from +a copy-source-to-destination to an xor-source-and-destination. This results +in a less visible cursor, but avoids the bug that leaves the scratches all +over the IMTOOL window. |