.........1.........2.........3.........4.........5.........6.........7.........8

STREAMS AND CHANNELS
by Toni Baker
part 3 of 5, ZX Computing February 1987

The concluding part of Toni Baker's Windows program.

[Note that the code in STREAMS.TAP "PART3"]
[includes the code from "PART2".      JimG]


Last month we began experimenting with windows. The listing continues
...

As a demonstration, the extra program WIND_DEMO which I've tagged on
at the end at address B544 will open a window twenty-four squares wide
by eight squares high, positioned AT 2,1 (relative to the whole
screen) with yellow paper and blue ink. Furthermore, the window will
be a SLOW window, so words won't ever be cut in half, and although the
standard character set is used, they are defined to be seven bits
wide, not eight, so you get more characters than you would normally.
Running the program once will open the window and attach it to stream
four. Thereafter PRINT #4 will print onto the window.


Follow through

For those of you who wish to follow the program through and understand
how it all works, I'll tell you that the program starts running from
location WINDOW (address B4F1) with the A register containing the
character to be printed, whenever RST 10 is used with this channel.

Oh - incidentally - while we're talking about the WINDOW routine, take
a look at the four instructions following the label WIND_CTRL. The
CALL instruction carries out the control code function, the POP
instruction restores the control character to the A register, and the
RET instruction terminates everything - the routine has finished -
control will then pass back to the RST 10 sub-routine itself, and then
back to the PRINT statement which caused the RST 10 to be used. But
... what's this AND A instruction doing just before the RET? The
comment beside the instruction reads "Reset the carry flag". Why? -
Surely everything's finished now. We shouldn't need to worry about
flags should we?

Unfortunately we do. You see when a control code such as PAPER 4 or
INVERSE 1 is used in a PRINT statement then the appropriate control
codes are sent to RST 10 to be carried out. The PRINT routine expects
the carry flag to be reset on return from such a routine, and will
produce the error message "C Nonsense in BASIC" if this is not the
case.

Next month I'll give you no less than two new channels: a modified
network channel for owners of the ZX Interface 1 which will
successfully communicate with a QL, and a channel which will allow
users of the Spectrum 128 to use the standard ZX Printer whilst in
128K mode, saving a lot of money in the process. See you then.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following subroutine prints a newline; ie. it moves the print position to
the left-hand edge of the next line down.

B2BB CDC3B2   ENTER     CALL ENTER_1       ;Print a single newline once
B2BE DDCB0B56           BIT  2,(IX+W_FLAGS)
B2C2 C8                 RET  Z             ;Return if using single height
B2C3 DD7E0E   ENTER_1   LD   A,(IX+W_YCOORD)  ;A= current y coordinate
B2C6 3C                 INC  A             ;A= new y coordinate
B2C7 DDBE0F             CP   (IX+W_HEIGHT)
B2CA C2B1B1             JP   NZ,LINE_A     ;Jump if in range to move print pos
B2CD DDCB0B6E           BIT  5,(IX+W_FLAGS)
B2D1 2812               JR   Z,SCROLL      ;Jump if scroll pause disabled
B2D3 DD3515             DEC  (IX+W_SCROLLS);Decrement scroll count
B2D6 200D               JR   NZ,SCROLL     ;Jump unless scroll pause required
B2D8 DD7E0F             LD   A,(IX+W_HEIGHT)
B2DB DD7715             LD   (IX+W_SCROLLS),A ;Re-initialise scroll count
B2DE 3E7F     SCR_PAUSE LD   A,#7F
B2E0 DBFE               IN   A,(#FE)       ;Scan part of the keyboard
B2E2 1F                 RRA
B2E3 38F9               JR   C,SCR_PAUSE   ;Pause until SPACE pressed
B2E5 CD541F   SCROLL    CALL BREAK_KEY
B2E8 D2000D             JP   NC,REPORT_D   ;Give error report if BREAK pressed
B2EB DD7E0E             LD   A,(IX+W_YCOORD)  ;A= y coordinate of bottom line
B2EE F5                 PUSH AF
B2EF CDB1B1             CALL LINE_A        ;Move print pos to start of bottom
                                           ;line of window
B2F2 C1                 POP  BC            ;B= number of lines to copy
B2F3 CD06B2             CALL GET_WIDTH     ;C= width of window in squares
B2F6 DD6E12             LD   L,(IX+W_HOME)lo
B2F9 DD6613             LD   H,(IX+W_HOME)hi  ;HL= address of top left corner
B2FC CD71B1             CALL PAGE_7        ;Use RAM page 7 in case scr 1 used
B2FF C5       SCR_LOOP1 PUSH BC            ;Stack loop counter
B300 0600               LD   B,#00         ;BC= width of line
B302 C5                 PUSH BC
B303 E5                 PUSH HL
B304 CDA5B1             CALL ATTR_ADDR     ;HL= addr of this attribute line
B307 112000             LD   DE,#0020
B30A EB                 EX   DE,HL         ;DE= addr of this attribute line
B30B 19                 ADD  HL,DE         ;HL= addr of next attribute line
B30C EDB0               LDIR               ;Copy one attribute line
B30E E1                 POP  HL
B30F C1                 POP  BC
B310 E5                 PUSH HL
B311 CD9BB1             CALL DOWN_8        ;HL= address of next line
B314 D1                 POP  DE            ;DE= address of this line
B315 E5                 PUSH HL
B316 3E08               LD   A,#08         ;A= number of rows per line
B318 C5       SCR_LOOP2 PUSH BC
B319 D5                 PUSH DE
B31A E5                 PUSH HL
B31B EDB0               LDIR               ;Copy one row from line
B31D E1                 POP  HL
B31E D1                 POP  DE
B31F C1                 POP  BC
B320 24                 INC  H             ;HL= addr of next row of next line
B321 14                 INC  D             ;DE= addr of next row of this line
B322 3D                 DEC  A
B323 20F3               JR   NZ,SCR_LOOP2  ;Copy whole line
B325 E1                 POP  HL
B326 C1                 POP  BC
B327 10D6               DJNZ SCR_LOOP1     ;Transfer all required lines
B329 0B                 DEC  BC            ;BC= length of line, less one
B32A DD7E14             LD   A,(IX+W_ATTR) ;A= attribute byte
B32D CDDEB1             CALL CLW_LINE      ;Clear bottom line
B330 C36CB1             JP   PAGE_0        ;Restore RAM page zero and return

The following subroutine deals with all control codes except for comma-control
and TAB (these are dealt with by CHR_TYPE2 at address B12F). On entry the A
register will contain the control code itself, while any parameters required
will be stored in B (middle parameter, if one exists) and C (last parameter).

B333 FE0D     CONTROLS  CP   "enter"
B335 2884               JR   Z,ENTER       ;Jump to deal with "enter"
B337 D610               SUB  #10
B339 D8                 RET  C             ;Return with codes 00 to 0F
B33A FE06               CP   #06
B33C 2827               JR   Z,CTRL_AT     ;Jump to deal with AT
B33E D0                 RET  NC            ;Return with codes 17 to 1F
B33F C65F               ADD  A,CTRL_INFO lo
B341 6F                 LD   L,A
B342 26B3               LD   H,CTRL_INFO hi;HL points to control info table
B344 46                 LD   B,(HL)        ;B= bit mask for this control
B345 111400             LD   DE,#0014      ;DE= IX displacement to W_ATTR
B348 FE63               CP   #63
B34A 3802               JR   C,CTRL_CONT   ;Jump unless ctrl is INVERSE/OVER
B34C 1E0B               LD   E,#0B         ;DE= IX displacement to W_FLAGS
B34E DDE5     CTRL_CONT PUSH IX
B350 E1                 POP  HL            ;HL points to channel info block
B351 19                 ADD  HL,DE         ;HL points to variable to alter
B352 79                 LD   A,C           ;A= control parameter
B353 48                 LD   C,B           ;C= bit mask
B354 0F                 RRCA
B355 07       CTRL_LOOP RLCA
B356 CB18               RR   B
B358 30FB               JR   NC,CTRL_LOOP  ;A= ctrl parameter in correct posn
B35A AE                 XOR  (HL)
B35B A1                 AND  C
B35C AE                 XOR  (HL)          ;Mix in reqd bits according to mask
B35D 77                 LD   (HL),A        ;Store variable
B35E C9                 RET

B35F 07       CTRL_INFO DEFB #07           ;Bit mask for INK
B360 38                 DEFB #38           ;Bit mask for PAPER
     80                 DEFB #80           ;Bit mask for FLASH
B362 40                 DEFB #40           ;Bit mask for BRIGHT
B363 08                 DEFB #08           ;Bit mask for INVERSE
B364 04                 DEFB #04           ;Bit mask for OVER

The next subroutine is the WINDOW version of the AT function. It performs the
function AT B,C for the current window.

B365 C5       CTRL_AT   PUSH BC
B366 78                 LD   A,B           ;A= proposed y coordinate
B367 CDB1B1             CALL LINE_A        ;Move print pos to start of this line
B36A C1                 POP  BC
B36B 79                 LD   A,C           ;A= proposed x coordinate
B36C A7                 AND  A
B36D C8                 RET  Z             ;Return if task already done
B36E DDBE0D             CP   (IX+W_WIDTH)
B371 D29F1E             JP   NC,REPORT_B   ;Give error report if out of range
B374 DD770C             LD   (IX+W_XCOORD),A  ;Store new x coordinate
B377 0600               LD   B,#00         ;BC= x coordinate
B379 DDCB0B66           BIT  4,(IX+W_FLAGS)
B37D 281A               JR   Z,AT_EXIT     ;Jump with "Fast" channels
B37F E5                 PUSH HL            ;Stack address of start of line
B380 DD4E17             LD   C,(IX+W_CH_WID)  ;BC= character width in pixels
B383 60                 LD   H,B
B384 68                 LD   L,B           ;HL= 0000
B385 09       AT_LOOP_1 ADD  HL,BC
B386 3D                 DEC  A
B387 20FC               JR   NZ,AT_LOOP_1  ;HL= no of pixels to start of char
B389 0603               LD   B,#03
B38B CB3C     AT_LOOP_2 SRL  H
B38D CB1D               RR   L
B38F 1F                 RRA
B390 10F9               DJNZ AT_LOOP_2     ;HL= no of squares to start of char
B392 07                 RLCA
B393 07                 RLCA
B394 07                 RLCA               ;A= pixel position within char square
B395 DD7716             LD   (IX+W_PIX),A  ;Store in variable
B398 C1                 POP  BC            ;BC= address of start of line
B399 09       AT_EXIT   ADD  HL,BC         ;HL= new print position address
B39A DD7510   STOREADDR LD   (IX+W_PRPOS)lo,L
B39D DD7411             LD   (IX+W_PRPOS)hi,H  ;Store new print position
B3A0 C9                 RET                ;Return

The following subroutine is very short and simple. It merely sets the attribute
byte corresponding to the screen address in HL.

B3A1 E5       SET_ATTR  PUSH HL
B3A2 CDA5B1             CALL ATTR_ADDR     ;HL= address of attribute byte
B3A5 DD7E14             LD   A,(IX+W_ATTR) ;A= current colours
B3A8 77                 LD   (HL),A        ;Store attribute byte
B3A9 E1                 POP  HL
B3AA C9                 RET                ;Return

This subroutine is intended for use with "Slow" windows only. It will plot one
row of a character onto the screen.

B3AB CDA1B3   PLOT_ROW  CALL SET_ATTR      ;Set attribute byte
B3AE 7E                 LD   A,(HL)        ;A= byte from screen
B3AF AA                 XOR  D
B3B0 A0                 AND  B
B3B1 AA                 XOR  D             ;Mix in bits from character
B3B2 77                 LD   (HL),A        ;Store in screen
B3B3 79                 LD   A,C           ;A= low byte of mask
B3B4 3C                 INC  A
B3B5 280A               JR   Z,PLRW_EXIT   ;Exit if all bits stored on screen
B3B7 23                 INC  HL            ;HL points to next screen byte
B3B8 CDA1B3             CALL SET_ATTR      ;Set this attribute byte as well
B3BB 7E                 LD   A,(HL)        ;A= byte from screen
B3BC AB                 XOR  E
B3BD A1                 AND  C
B3BE AB                 XOR  E             ;Mix in bits from character
B3BF 77                 LD   (HL),A        ;Store in screen
B3C0 2B                 DEC  HL            ;HL points to original screen byte
B3C1 C38CB1   PLRW_EXIT JP   DOWN_1        ;Point HL one pixel down, and return

This subroutine will calculate 8*A+DE, and will also collect the current print
position.

B3C4 6F       PREPARE   LD   L,A
B3C5 2600               LD   H,#00         ;HL= character code
B3C7 29                 ADD  HL,HL
B3C8 29                 ADD  HL,HL
B3C9 29                 ADD  HL,HL         ;HL= eight times character code
B3CA 19                 ADD  HL,DE
B3CB EB                 EX   DE,HL         ;DE= address of pixel expansion
B3CC DD6E10             LD   L,(IX+W_PRPOS)lo
B3CF DD6611             LD   H,(IX+W_PRPOS)hi  ;HL= address of print position
B3D2 C9                 RET                ;Return

This subroutine will collect one byte from the pixel expansion pointed to by DE
and will invert it if necessary.

B3D3 1A       GET_ROW   LD   A,(DE)        ;A= next row of pixel expansion
B3D4 13                 INC  DE            ;DE points to next row
B3D5 DDCB0B5E           BIT  3,(IX+W_FLAGS)
B3D9 C8                 RET  Z             ;Return unless INVERSE 1 in operation
B3DA 2F                 CPL                ;Otherwise invert the row
B3DB C9                 RET

This next and very important subroutine will actually print a character,
specified in the A register, onto the current window.

B3DC F5       PRINT_CHR PUSH AF            ;Stack character to print
B3DD F5                 PUSH AF            ;Stack character to print (again)
B3DE DD7E0C             LD   A,(IX+W_XCOORD)  ;A= current X coordinate
B3E1 DDBE0D             CP   (IX+W_WIDTH)
B3E4 CCBBB2             CALL Z,ENTER       ;Print newline if at end of line
B3E7 DDCB0B66           BIT  4,(IX+W_FLAGS)
B3EB 2034               JR   NZ,PCHRSLOW   ;Jump with "Slow" window
B3ED F1                 POP  AF            ;A= character to print
B3EE ED5B365C           LD   DE,(CHARS)    ;DE= addr of normal char set - 100h
B3F2 2012               JR   NZ,PCHR_OK_1  ;Jump with ASCII character
B3F4 300A               JR   NC,PCHR_UDG   ;Jump with user-defined graphics
B3F6 47                 LD   B,A
B3F7 CD380B             CALL PO_GR_1       ;Construct block graphic
B3FA 11925C             LD   DE,MEMBOT     ;DE points to pixel expansion
B3FD AF                 XOR  A
B3FE 1806               JR   PCHR_OK_1     ;Jump forward
B400 D690     PCHR_UDG  SUB  #90
B402 ED5B7B5C           LD   DE,(UDG)      ;DE points to user-defined graphics
B406 CDC4B3   PCHR_OK_1 CALL PREPARE       ;DE= address of pixel expansion
                                           ;HL= address of print position
B409 CDA1B3             CALL SET_ATTR      ;Set attribute for this square
B40C E5                 PUSH HL
B40D 0608               LD   B,#08         ;B= number of rows per line
B40F CDD3B3   PCHRLOOP1 CALL GET_ROW       ;A= next row from expansion
B412 CD71B1             CALL PAGE_7        ;Use RAM page 7 in case scrn 1 in use
B415 77                 LD   (HL),A        ;Store row in screen
B416 24                 INC  H             ;HL points to next row
B417 CD6CB1             CALL PAGE_0        ;Restore RAM page zero
B41A 10F3               DJNZ PCHRLOOP1     ;Print whole character
B41C E1                 POP  HL
B41D 23                 INC  HL            ;HL= new print position
B41E C3B2B4             JP   PCHR_EXIT     ;Jump to exit
B421 DDCB0B56 PCHRSLOW  BIT  2,(IX+W_FLAGS)
B425 281E               JR   Z,PCHRSLOW2   ;Jump unless using double height
B427 DD7E0F             LD   A,(IX+W_HEIGHT)  ;A= height of window
B42A 3D                 DEC  A             ;A= y coordinate of bottom line
B42B DDBE0E             CP   (IX+W_YCOORD)
B42E 2015               JR   NZ,PCHRSLOW2  ;Jump unless at bottom line
B430 DD4E0C             LD   C,(IX+W_XCOORD)  ;C= current x coordinate
B433 47                 LD   B,A           ;B= current y coordinate
B434 05                 DEC  B             ;B= y coordinate after scroll
B435 DD7E0B             LD   A,(IX+W_FLAGS)
B438 F5                 PUSH AF            ;Stack flags
B439 C5                 PUSH BC            ;Stack coordinates
B43A CDC3B2             CALL ENTER_1       ;Scroll the screen once
B43D C1                 POP  BC            ;BC= coordinates
B43E CD65B3             CALL CTRL_AT       ;Move print position back where it
                                           ;belongs
B441 F1                 POP  AF
B442 DD770B             LD   (IX+W_FLAGS),A  ;Restore the flags
B445 F1       PCHRSLOW2 POP  AF            ;A= character to print
B446 DD5E18             LD   E,(IX+W_CHARS)lo
B449 DD5619             LD   D,(IX+W_CHARS)hi;DE= addr of normal chr set - 100h
B44C 2008               JR   NZ,PCHR_OK_2  ;Jump with ASCII characters
B44E D680               SUB  #80
B450 DD5E1A             LD   E,(IX+W_UDG)lo
B453 DD561B             LD   D,(IX+W_UDG)hi;DE points to graphics chr set
B456 CDC4B3   PCHR_OK_2 CALL PREPARE       ;DE= address of pixel expansion
                                           ;HL= address of print position
B459 E5                 PUSH HL            ;Stack address of print position
B45A 01FFFF             LD   BC,#FFFF
B45D DD7E17             LD   A,(IX+W_CH_WID)  ;A= width of chr in pixels
B460 CB38     PCHRMASK1 SRL  B
B462 CB19               RR   C
B464 3D                 DEC  A
B465 20F9               JR   NZ,PCHRMASK1  ;BC= mask, not yet in position
B467 DD7E16             LD   A,(IX+W_PIX)  ;A= pixel posn within chr square
B46A A7                 AND  A
B46B 2808               JR   Z,PCHRMASK3   ;Jump if mask OK
B46D 37       PCHRMASK2 SCF
B46E CB18               RR   B
B470 CB19               RR   C
B472 3D                 DEC  A
B473 20F8               JR   NZ,PCHRMASK2  ;Otherwise rotate mask into place
B475 3E08     PCHRMASK3 LD   A,#08         ;A= number of rows per line
B477 F5       PCHRLOOP2 PUSH AF            ;Stack loop counter
B478 CDD3B3             CALL GET_ROW       ;A= next row from expansion
B47B D5                 PUSH DE            ;Stack pointer into expansion
B47C 57                 LD   D,A
B47D DD7E16             LD   A,(IX+W_PIX)  ;A= pixel posn within chr square
B480 A7                 AND  A
B481 2807               JR   Z,PCHR_ROW    ;Jump if pixels correctly aligned
B483 CB1A     PCHRSHIFT RR   D
B485 CB1B               RR   E
B487 3D                 DEC  A
B488 20F9               JR   NZ,PCHRSHIFT  ;Shift pixels into position
B48A CD71B1   PCHR_ROW  CALL PAGE_7        ;Set RAM page 7 in case scrn 1 in use
B48D CDABB3             CALL PLOT_ROW      ;Plot row onto screen
B490 DDCB0B56           BIT  2,(IX+W_FLAGS)
B494 C4ABB3             CALL NZ,PLOT_ROW   ;And again if using double height
B497 CD6CB1             CALL PAGE_0        ;Restore RAM page zero
B49A D1                 POP  DE            ;DE points to pixel expansion
B49B F1                 POP  AF            ;A= loop counter
B49C 3D                 DEC  A
B49D 20D8               JR   NZ,PCHRLOOP2  ;Print whole character
B49F E1                 POP  HL            ;HL= original print position
B4A0 DD7E16             LD   A,(IX+W_PIX)  ;A= original position within square
B4A3 DD8617             ADD  A,(IX+W__CH_WID)  ;Allow for width of character
B4A6 FE08     PCHR_POS  CP   #08
B4A8 3805               JR   C,PCHR_POS2   ;Jump if print position OK
B4AA D608               SUB  #08
B4AC 23                 INC  HL            ;Otherwise amend it
B4AD 18F7               JR   PCHR_POS      ;Loop back to try again
B4AF DD7716   PCHR_POS2 LD   (IX+W_PIX),A  ;Store new position within square
B4B2 CD9AB3   PCHR_EXIT CALL STOREADDR     ;Store new print position
B4B5 DD340C             INC  (IX+W_XCOORD) ;Increment x coordinate
B4B8 F1                 POP  AF            ;A= character just printed
B4B9 C9                 RET                ;Return

The following subroutine will empty the buffer ("Slow" windows only), printing
the former contents onto the window.

B4BA D4BBB2   EMPTY     CALL NC,ENTER      ;Print a newline if required
B4BD DDE5               PUSH IX
B4BF E1                 POP  HL            ;HL points to channel info block
B4C0 011D00             LD   BC,#001D
B4C3 09                 ADD  HL,BC         ;HL points to variable W_LEN
B4C4 7E                 LD   A,(HL)        ;A= number of characters in buffer
B4C5 A7                 AND  A
B4C6 C8       EMPTYLOOP RET  Z             ;Return if finished
B4C7 23                 INC  HL            ;HL points to next char in buffer
B4C8 7E                 LD   A,(HL)
B4C9 E5                 PUSH HL
B4CA CDF4B0             CALL CTYP_NTOK     ;Flags indicate type of character
B4CD CDDCB3             CALL PRINT_CHR     ;Print the character
B4D0 E1                 POP  HL
B4D1 DD351D             DEC  (IX+W_LEN)
B4D4 18F0               JR   EMPTYLOOP

The following subroutine will empty the buffer ("Slow") or do nothin ("Fast").
It will decide whether or not a newline is required, and print one if so.

B4D6 DDCB0B66 EMPTY_2   BIT  4,(IX+W_FLAGS)
B4DA C8                 RET  Z             ;Return with "Fast" windows
B4DB 57                 LD   D,A           ;D= next character to print
B4DC DD7E1D             LD   A,(IX+W_LEN)  ;A= length of word in buffer
B4DF DD860C             ADD  A,(IX+W_XCOORD)  ;A= potential x coordinate after
                                           ;the buffer has been emptied
B4E2 DDBE0D             CP   (IX+W_WIDTH)
B4E5 2002               JR   NZ,EMPTY_OUT  ;Jump unless word exactly fills line
B4E7 53                 LD   D,E           ;D= alternative char to print
B4E8 37                 SCF                ;Signal "Newline not needed"
B4E9 D5       EMPTY_OUT PUSH DE
B4EA C5                 PUSH BC
B4EB CDBAB4             CALL EMPTY         ;Empty buffer with newline if needed
B4EE C1                 POP  BC
B4EF F1                 POP  AF            ;A= next character to print
B4F0 C9                 RET                ;Return

And now at last we have the window output subroutine itself.

B4F1 DD2A515C WINDOW    LD   IX,(CURCHL)   ;IX points to channel info block
B4F5 CDB7B0             CALL CHR_TYPE      ;Deal with keywords, etc.
B4F8 F8                 RET  M             ;Return if tasks completed
B4F9 F5                 PUSH AF            ;Stack character to print
B4FA 2824               JR   Z,WIND_ABLE   ;Jump with graphics characters
B4FC 3013               JR   NC,WINDASCII  ;Jump with ASCII characters
B4FE A7                 AND  A
B4FF CC92B2             CALL Z,CLSWINDOW   ;Clear window for CHR$ 0
B502 F1                 POP  AF
B503 F5                 PUSH AF
B504 5F                 LD   E,A           ;Signal "Char not to be changed"
B505 CDD6B4             CALL EMPTY_2       ;Empty buffer
B508 CD32B1             CALL CHRTYPE2A     ;Deal with TAB and comma control
B50B CD33B3  WIND_CTRL  CALL CONTROLS      ;Deal with remaining ctrl characters
B50E F1                 POP  AF
B50F A7                 AND  A             ;Reset Carry flag
B510 C9                 RET                ;Return
B511 FE20     WINDASCII CP   "space"
B513 200B               JR   NZ,WIND_ABLE  ;Jump with all chars except "space"
B515 1E0D               LD   E,"enter"     ;Use "enter" as alternative char
B517 CDD6B4             CALL EMPTY_2       ;Empty buffer
B51A FE0D               CP   "enter"
B51C 28ED               JR   Z,WIND_CTRL   ;Jump if newline now required
B51E 1806               JR   WINDPRINT     ;Jump to print "space" on window
B520 DDCB0B66 WIND_ABLE BIT  4,(IX+W_FLAGS)
B524 2004               JR   NZ,#B52A      ;Jump with "Slow" windows
B526 F1       WINDPRINT POP  AF
B527 C3DCB3             JP   PRINT_CHR     ;Jump to print the character
B52A 2A515C   WIND_SLOW LD   HL,(CURCHL)   ;HL points to channel info block
B52D 011D00             LD   BC,#001D
B530 09                 ADD  HL,BC         ;HL points to variable W_LEN
B531 7E                 LD   A,(HL)        ;A= number of chars in buffer
B532 DDBE0D             CP   (IX+W_WIDTH)
B535 2005               JR   NZ,WINDSLOW2  ;Jump unless buffer full
B537 E5                 PUSH HL
B538 CDBAB4             CALL EMPTY         ;Empty buffer
B53B E1                 POP  HL
B53C F1       WINDSLOW2 POP  AF
B53D 34                 INC  (HL)          ;Increment length of buffer
B53E 4E                 LD   C,(HL)
B53F 0600               LD   B,#00         ;BC= new length of buffer
B541 09                 ADD  HL,BC
B542 77                 LD   (HL),A        ;Store char in buffer
B543 C9                 RET                ;Return

;[The next subroutine gets overwritten by the code in Part 4.  JimG]

And finally - just a quick demonstration program to open a window and attach it
to stream four. If you RUN this you'll be able to use PRINT #4; to print onto
the window.

B544 3E04     WIND_DEMO LD   A,#04
B546 08                 EX   AF,AF'        ;A'= stream number
B547 2A7B5C             LD   HL,(UDG)      ;HL= address of user-defined graphics
B54A 0180FF             LD   BC,#FF80
B54D 09                 ADD  HL,BC
B54E 44                 LD   B,H
B54F 4D                 LD   C,L           ;BC'= address of UDGs - 80h
B550 ED5B365C           LD   DE,(CHARS)    ;DE'= addr of normal char set - 100h
B554 2607               LD   H,#07         ;H'= width of characters
B556 D9                 EXX
B557 3E31               LD   A,#31         ;A= attribute byte for window
B559 010102             LD   BC,#0201      ;BC= position of window
B55C 111808             LD   DE,#0818      ;DE= size of window
B55F 21FFFF             LD   HL,#FFFF      ;HL signals "Slow window" and
                                           ;"Scroll pause enabled"
B562 CD12B2             CALL OPEN_WIND     ;Open the window channel
B565 215827             LD   HL,#2758
B568 D9                 EXX                ;HL'= value required by BASIC
B569 C9                 RET                ;Return
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
