General Designs Contents Index Output Recording




15 Extended Stream Output

CLIM provides a stream-oriented output layer that is implemented on top of the sheet output architecture. The basic CLIM output stream protocol is based on the character output stream protocol proposal submitted to the ANSI Common Lisp committee by David Gray. This proposal was not approved by the committee, but has been implemented by most Lisp vendors.

15.1 Basic Output Streams

CLIM provides an implementation of the basic output stream facilities (described in more detail in Appendix Common Lisp Streams ), either by directly using the underlying Lisp implementation, or by implementing the facilities itself.

standard-output-stream[Class]
This class provides an implementation of the CLIM basic output stream protocol, based on the CLIM output kernel. Members of this class are mutable.
stream-write-charstream character[Generic function]
Writes the character character to the output stream stream , and returns character as its value.

stream-write-stringstream string &optional (start 0 ) end[Generic function]
Writes the string string to the output stream stream . If start and end are supplied, they are integers that specify what part of string to output. string is returned as the value.

stream-terpristream[Generic function]
Writes an end of line character on the output stream stream , and returns false .

stream-fresh-linestream[Generic function]
Writes an end of line character on the output stream stream only if the stream is not at the beginning of the line.

stream-finish-outputstream[Generic function]
Ensures that all the output sent to the output stream stream has reached its destination, and only then return false .

stream-force-outputstream[Generic function]
Like stream-finish-output , except that it may immediately return false without waiting for the output to complete.

stream-clear-outputstream[Generic function]
Aborts any outstanding output operation in progress on the output stream stream , and returns false .

stream-line-columnstream[Generic function]
This function returns the column number where the next character will be written on the output stream stream . The first column on a line is numbered 0.

stream-start-line-pstream[Generic function]
Returns true if the output stream stream is positioned at the beginning of a line (that is, column 0), otherwise returns false .

stream-advance-to-columnstream column[Generic function]
Writes enough blank space on the output stream stream so that the next character will be written at the position specified by column , which is an integer.

15.2 Extended Output Streams

In addition to the basic output stream protocol, CLIM defines an extended output stream protocol. This protocol extends the stream model to maintain the state of a text cursor, margins, text styles, inter-line spacing, and so forth.

extended-output-stream[Protocol Class]
The protocol class for CLIM extended output streams. This is a subclass of output-stream . If you want to create a new class that behaves like an extended output stream, it should be a subclass of extended-output-stream. Subclasses of extended-output-stream must obey the extended output stream protocol.
extended-output-stream-pobject[Predicate]
Returns true if object is a CLIM extended output stream , otherwise returns false .

:foreground[Init arg]
:background[Init arg]
:text-style[Init arg]
:vertical-spacing[Init arg]
:text-margin[Init arg]
:end-of-line-action[Init arg]
:end-of-page-action[Init arg]
:default-view[Init arg]
All subclasses of extended-output-stream must handle these initargs, which are used to specify, respectively, the medium foreground and background, default text style, vertical spacing, default text margin, end of line and end of page actions, and the default view for the stream.

:foreground , :background , and :text-style are handled via the usual pane initialize options (see Section Pane Initialization Options ).

standard-extended-output-stream[Class]
This class provides an implementation of the CLIM extended output stream protocol, based on the CLIM output kernel.

Members of this class are mutable.

15.3 The Text Cursor

In the days when display devices displayed only two dimensional arrays of fixed width characters, the text cursor was a simple thing. A discrete position was selected in integer character units, and a character could go there and noplace else. Even for variable width fonts, simply addressing a character by the pixel position of one of its corners is sufficient. However, variable height fonts with variable baselines on pixel-addressable displays upset this simple model. The ``logical'' vertical reference point is the baseline, as it is in typesetting. In typesetting, however, an entire line of text is created with baselines aligned and padded to the maximum ascent and descent, then the entire line is put below the previous line.

It is clearly desirable to have the characters on a line aligned with their baselines, but when the line on the display is formed piece by piece, it is impossible to pick in advance the proper baseline. The solution CLIM adopts is to choose a baseline, but not commit to it.

The CLIM model says that text has at least 6 properties. With a reference point of (0,0) at the upper left of the text, it has a bounding box consisting of ascent, descent, left kerning, right extension, and a displacement to the next reference point in both x and y. CLIM determines the position of the reference point and draws the text relative to that, and then the cursor position is adjusted by the displacement. In this way, text has width and height, but the x and y displacements need not equal the width and height.

CLIM adopts the following approach to the actual rendering of a glyph. Textual output using the stream functions (not the graphics functions) maintains text on a ``line''. Note that a line is not an output record, but is rather a collection of ``text so far'', a top (which is positioned at the bottom of the previous line plus the stream's vertical spacing), a baseline, a bottom, and a ``cursor position''. The cursor position is defined to be at the top of the line, not at the baseline. The reason for this is that the baseline can move, but the top is relative to the previous line, which has been completed and therefore doesn't move. If text is drawn on the current line whose ascent is greater than the current ascent of the line, then the line is moved down to make room. This can be done easily using the output records for the existing text on the line. When there is enough room, the reference point for the text is the x position of the cursor at the baseline, and the cursor position is adjusted by the displacement.

The following figures show this in action before and after each of three characters are drawn. In all three figure, the small circle is the ``cursor position''. At first, there is nothing on the line. The first character establishes the initial baseline, and is then drawn. The upper left corner of the character is where the cursor was (as in the traditional model), but this will not remain the case. Drawing the second character, which is larger than the first, requires moving the first character down in order to get the baselines to align; during this time, the top of the line remains the same. Again, the upper left of the second character is where the cursor was, but that is no longer the case for the first character (which has moved down). The third character is smaller than the second, so no moving of characters needs to be done. However, the character is drawn to align the baselines, which in this case means the upper left is not where the cursor was. Nor is the cursor at the upper right of the character as it was for the previous two characters. It is, however, at the upper right of the collective line.

                                        (w1+w2,y)\         
                                                  \        
               (w1,y)\             (w1,y)\         \       
                      \                   \         \      
(0,y)\    (0,y)\       \      (0,y)\       \         \     
      \         \       \           \       \         \    
       ----      ------------        ----------------------
                 |       |                   |         |   
                 |       |           --------|         |   
                 |       |           |       |         |   
                 |       |           |       |         |   
                 |       |           |       |         |   
                 | small |           |       |         |   
                 |       |           |       |         |   
                 |       |           | small |   BIG   |   
                 |       |           |       |         |   
                 ----------          |       |         |   
                 |       |           |       |         |   
                 ---------           --------------------  
                /                    |       |         |   
                                     --------|         |   
                                    /        |         |   
       bl-small/                             -----------   
                                                           
                             bl-BIG/                       
                                                           
                                                           
                                                           
                       (w1+w2+w3,y)\                       
                                    \                      
                    (w1+w2,y)\       \                     
                              \       \                    
               (w1,y)\         \       \                   
                      \         \       \                  
          (0,y)\       \         \       \                 
                \       \         \       \                
                 ------------------------------            
                         |         |                       
                 --------|         ---------               
                 |       |         |       |               
                 |       |         |       |               
                 |       |         |       |               
                 |       |         |       |               
                 |       |         |       |               
                 | small |   BIG   | small |               
                 |       |         |       |               
                 |       |         |       |               
                 |       |         |       |               
                 ----------------------------              
                 |       |         |       |               
                 --------|         ---------               
                /        |         |                       
                         -----------                       
                                                           
         bl-BIG/                                           


Issue: DCPL
The above may be too simplistic. The displacement probably wants to depend not only on language but language rendering mode. For example, Japanese can apparently go either vertically or horizontally. It may be necessary to have the bounding box and perhaps the reference point dispatch as well. Similarly, ``newline'' could mean ``down one line, all the way to the left'' for English, ``down one line, all the way to the right'' for Arabic, or ``to the left one line, all the way to the top.'' ``Home cursor'' is another ditty to consider. We need to discuss this on a larger scale with people who know multi-lingual rendering issues.

15.3.1 Text Cursor Protocol

Many streams that maintain a text cursor display some visible indication of the text cursor. The object that represents this display is (somewhat confusingly) also called a cursor.

An active cursor is one that is being actively maintained by its owning sheet. A active cursor has a state that is either on or off. An active cursor can also has a state that indicates the the owning sheet has the input focus.

cursor[Protocol Class]
The protocol class that corresponds to cursors. If you want to create a new class that behaves like a cursor, it should be a subclass of cursor. Subclasses of cursor must obey the cursor protocol.Members of this class are mutable.
cursorpobject[Predicate]
Returns true if object is a cursor , otherwise returns false .

:sheet[Init arg]
The :sheet initarg is used to specify the sheet with which the cursor is associated.

standard-text-cursor[Class]
The instantiable class that implements a text cursor. Typically, ports will further specialize this class.

cursor-sheetcursor[Generic function]
Returns the sheet with which the cursor cursor is associated.

cursor-positioncursor[Generic function]
Returns the x and y position of the cursor cursor as two values. x and y are in the coordinate system of the cursor's sheet.

(setf* cursor-position)x y cursor[Generic function]
Sets the x and y position of the cursor cursor to the specified position. x and y are in the coordinate system of the cursor's sheet.

For CLIM implementations that do not support setf* , the ``setter'' function for this is cursor-set-position .

cursor-activecursor[Generic function]
(setf cursor-active)value cursor[Generic function]
Returns (or sets) the ``active'' attribute of the cursor. When true , the cursor is active.

cursor-statecursor[Generic function]
(setf cursor-state)value cursor[Generic function]
Returns (or sets) the ``state'' attribute of the cursor. When true , the cursor is visible. When false , the cursor is not visible.

cursor-focuscursor[Generic function]
Returns the ``focus'' attribute of the cursor. When true , the sheet owning the cursor has the input focus.

cursor-visibilitycursor[Generic function]
(setf cursor-visibility)visibility cursor[Generic function]
These are convenience functions that combine the functionality of cursor-active and cursor-state . The visibility can be either :on (meaning that the cursor is active and visible at its current position), :off (meaning that the cursor is active, but not visible at its current position), or nil (meaning that the cursor is not activate).

15.3.2 Stream Text Cursor Protocol

The following generic functions comprise the stream text cursor protocol. Any extended output stream class must implement methods for these generic functions.

stream-text-cursorstream[Generic function]
(setf stream-text-cursor)cursor stream[Generic function]
Returns (or sets) the text cursor object for the stream stream .

stream-cursor-positionstream[Generic function]
Returns the current text cursor position for the extended output stream stream as two integer values, the x and y positions.

(setf* stream-cursor-position)x y stream[Generic function]
Sets the text cursor position of the extended output stream stream to x and y . x and y are in device units, and must be integers.

For CLIM implementations that do not support setf* , the ``setter'' function for this is stream-set-cursor-position .

stream-increment-cursor-positionstream dx dy[Generic function]
Moves the text cursor position of the extended output stream stream relatively, adding dx to the x coordinate and dy to the y coordinate. Either of dx or dy may be nil , meaning the the x or y cursor position will be unaffected. Otherwise, dx and dy must be integers.

15.4 Text Protocol

The following generic functions comprise the text protocol. Any extended output stream class must implement methods for these generic functions.

stream-character-widthstream character &key text-style[Generic function]
Returns a rational number corresponding to the amount of horizontal motion of the cursor position that would occur if the character character were output to the extended output stream stream in the text style text-style (which defaults to the current text style for the stream). This ignores the stream's text margin.

stream-string-widthstream character &key start end text-style[Generic function]
Computes how the cursor position would move horizontally if the string string were output to the extended output stream stream in the text style text-style (which defaults to the current text style for the stream) starting at the left margin. This ignores the stream's text margin.

The first returned value is the x coordinate that the cursor position would move to. The second returned value is the maximum x coordinate the cursor would visit during the output. (This is the same as the first value unless the string contains a #\Newline character.)

start and end are integers, and default to 0 and the length of the string, respectively.

stream-text-marginstream[Generic function]
(setf stream-text-margin)margin stream[Generic function]
The x coordinate at which text wraps around on the extended output stream stream (see stream-end-of-line-action ). The default setting is the width of the viewport, which is the right-hand edge of the viewport when it is horizontally scrolled to the ``initial position''.

You can use setf with stream-text-margin to establish a new text margin. If margin is nil , then the width of the viewport will be used. If the width of the viewport is later changed, the text margin will change, too.

stream-line-heightstream &key text-style[Generic function]
Returns what the line height of a line on the extended output stream stream containing text in the text style text-style would be, as a rational number. The height of the line is measured from the baseline of the text style to its ascent. text-style defaults to the current text style for the stream.

stream-vertical-spacingstream[Generic function]
Returns the current inter-line spacing (as a rational number) for the extended output stream stream .

stream-baselinestream[Generic function]
Returns the current text baseline (as a rational number) for the extended output stream stream .

15.4.1 Mixing Text and Graphics

The following macro provides a convenient way to mix text and graphics on the same output stream.

with-room-for-graphics(&optional stream &key (first-quadrant t ) height (move-cursor t ) record-type) &body body[Macro]
Binds the dynamic environment to establish a local coordinate system for doing graphics output onto the extended output stream designated by stream . If first-quadrant is true (the default), a local Cartesian coordinate system is established with the origin (0,0) of the local coordinate system placed at the current cursor position; (0,0) is in the lower left corner of the area created. If the boolean move-cursor is true (the default), then after the graphic output is completed, the cursor is positioned past (immediately below) this origin. The bottom of the vertical block allocated is at this location (that is, just below point (0,0), not necessarily at the bottom of the output done).

The stream argument is not evaluated, and must be a symbol that is bound to a stream. If stream is t (the default), *standard-output* is used. body may have zero or more declarations as its first forms.

If height is supplied, it must be a rational number that specifies the amount of vertical space to allocate for the output, in device units. If it is not supplied, the height is computed from the output.

record-type specifies the class of output record to create to hold the graphical output. The default is standard-sequence-output-record .

15.4.2 Wrapping of Text Lines

stream-end-of-line-actionstream[Generic function]
(setf stream-end-of-line-action)action stream[Generic function]
The end-of-line action controls what happens if the text cursor position moves horizontally out of the viewport, or if text output reaches the text margin. (By default the text margin is the width of the viewport, so these are usually the same thing.)

stream-end-of-line-action returns the end-of-line action for the extended output stream stream . It can be changed by using setf on stream-end-of-line-action .

The end-of-line action is one of:

with-end-of-line-action(stream action) &body body[Macro]
Temporarily changes stream 's end-of-line action for the duration of execution of body. action must be one of the actions described in stream-end-of-line-action .

The stream argument is not evaluated, and must be a symbol that is bound to a stream. If stream is t , *standard-output* is used. body may have zero or more declarations as its first forms.

stream-end-of-page-actionstream[Generic function]
(setf stream-end-of-page-action)action stream[Generic function]
The end-of-page action controls what happens if the text cursor position moves vertically out of the viewport.

stream-end-of-page-action returns the end-of-page action for the extended output stream stream . It can be changed by using setf on stream-end-of-page-action .

The end-of-page action is one of:

with-end-of-page-action(stream action) &body body[Macro]
Temporarily changes stream 's end-of-page action for the duration of execution of body. action must be one of the actions described in stream-end-of-page-action .

The stream argument is not evaluated, and must be a symbol that is bound to a stream. If stream is t , *standard-output* is used. body may have zero or more declarations as its first forms.

15.5 Attracting the User's Attention

beep&optional medium[Generic function]
Attracts the user's attention, usually with an audible sound.

15.6 Buffering of Output

Some mediums that support the output protocol may buffer output. When buffering is enabled on a medium, the time at which output is actually done on the medium is unpredictable. force-output or finish-output can be used to ensure that all pending output gets completed. If the medium is a bidirectional stream, a force-output is performed whenever any sort of input is requested on the stream.

with-buffered-output provides a way to control when buffering is enabled on a medium. By default, CLIM's interactive streams are buffered if the underlying window system supports buffering.

medium-buffering-output-pmedium[Generic function]
Returns true if the medium medium is currently buffering output, otherwise returns false .

(setf medium-buffering-output-p)buffer-p medium[Generic function]
Sets medium-buffering-output-p of the medium medium to buffer-p .

with-output-buffered(medium &optional (buffer-p t )) &body body[Macro]
If buffer-p is true (the default), this causes the medium designated by medium to start buffering output, and evaluates body in that context. If buffer-p is false , force-output will be called before body is evaluated. When body is exited (or aborted from), force-output will be called if output buffering will be disabled after with-output-buffered is exited.

The medium argument is not evaluated, and must be a symbol that is bound to a medium. If medium is t , *standard-output* is used. body may have zero or more declarations as its first forms.



General Designs Contents Index Output Recording