BSD 4_3 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Mon, 27 Jan 1986 05:23:10 +0000 (21:23 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Mon, 27 Jan 1986 05:23:10 +0000 (21:23 -0800)
Work on file usr/contrib/X/xted/screen.clu

Synthesized-from: CSRG/cd1/4.3

usr/contrib/X/xted/screen.clu [new file with mode: 0644]

diff --git a/usr/contrib/X/xted/screen.clu b/usr/contrib/X/xted/screen.clu
new file mode 100644 (file)
index 0000000..6216c7f
--- /dev/null
@@ -0,0 +1,869 @@
+% Physical screen hacking cluster, for editors, etc.
+
+# extend
+
+screen = cluster is
+
+       % mode changing and initialization functions
+       init,                   % sets up (first time, or new terminal)
+       enter_image_mode,       % set up terminal
+       leave_image_mode,       % restores the terminal
+       destroy,                % finishes up
+
+       % option setting functions
+       set_padding,            % pad output
+       set_scroll,             % do scrolling (if poss)
+       set_keypad_mode,        % enter/exit alternate keypad mode
+       set_highlight,          % underline/invert
+       recolor,                % change colors
+
+       % display functions
+       clear,                  % clear screen and home up
+       display_line,           % display a line of an environment
+       redisplay_line,         % redisplay line as is
+       display_chars,          % display chars at end of line
+       update_line,            % update data to correspond with screen
+       set_cursor_pos,         % set the cursor position
+       get_cursor_pos,         % get the cursor position
+       scroll,                 % scroll a region
+       full_scroll,            % scroll entire screen
+       bell,                   % bell
+       highlight,              % highlight
+       redisplay,              % hack redisplay
+       unmapped,               % hack icon
+
+       % information returning functions
+       position,               % pixel -> char coordinates
+       get_padding,            % padding on ?
+       get_screen_size,        % returns length and width of screen
+       fetch,                  % fetch a line
+       id_lines_poss,          % ins/del lines possible ?
+       scrolling_poss,         % full screen scrolling possible ?
+       should_id_lines,        % makes decision about ins/del lines
+       should_scroll           % makes decision about scrolling
+
+    ldata = record[line: act,          % screen line, as chars
+                  len:  int,          % len of real string
+                  lim:  int,          % pos of last non-space char in line
+                  str:  string]       % the actual string
+
+    % invariant property of ldatas:
+    %  size(line) = hsize - 1
+    %  len = _calc_hpos(str, string$size(str) + 1)
+    %  lim < i < hsize  =>  line[i] = ' '
+    %  the chars in line correspond to the chars in str
+    %  the chars in lines[j] correspond to the chars on the
+    %      screen on line j (the presence of an ! determined by len)
+
+    rep     = null
+    al      = array[ldata]
+
+    qi      = sequence[int]
+    qs      = sequence[string]
+    zapc    = array_zap[char]
+    shiftc  = array_shift[char]
+    shiftl  = array_shift[ldata]
+    repll   = array_replace[ldata]
+
+    events = KeyPressed + ButtonPressed + ButtonReleased +
+            ExposeRegion + ExposeCopy + UnmapWindow
+
+    own done: bool := false
+
+    % screen data base
+
+    own lines: al                          % array of line data
+    own holder: act                        % for display_line (new line)
+    own hlim: int                          % limit for holder
+    own temp: al                           % for scrolling
+    own xline: act                         % display_chars hack
+    own xvpos: int
+    own xhpos: int
+    own xmpos: int
+
+    own image: bool                        % in image mode?
+    own f: x_font
+    own fheight: int
+    own fwidth: int
+    own of: x_font
+    own oheight: int
+    own owidth: int
+    own textpix: int
+    own clearpix: int
+    own planemask: int
+    own nobit: x_bitmap
+    own w: x_window
+    own ow: x_window
+    own mousepix: int
+    own mousefunc: int
+    own chpos: int
+    own cdisp: bool
+    own crcols: colordeflist
+    own hlcols: colordeflist
+    own hlmode: bool
+    own high: bool
+    own hvpos: int
+    own hhpos: int
+
+    % terminal properties
+
+    own vsize: int                          % # of lines (0 to vsize-1)
+    own hsize: int                          % # of cols  (0 to hsize-1)
+    own vsize1: int                         % vsize-1
+    own hsize1: int                         % hsize-1
+
+    % cursor info (-1 means unknown)
+
+    own vpos: int                           % current vertical pos
+    own hpos: int                           % current horizontal pos
+
+    init = proc (options: qs)
+       if ~done
+          then lines := al$create(0)
+               holder := act$create(0)
+               hlim := -1
+               temp := al$create(0)
+               xhpos := 0
+               xmpos := -1
+               image := false
+               display: string := ""
+               myname: string := _get_xjname()
+               font: string := x_default(myname, "BodyFont")
+                  except when not_found: font := "8x13" end
+               revvid: bool := x_default(myname, "ReverseVideo") = "on"
+                  except when not_found: revvid := false end
+               bwidth: int := int$parse(x_default(myname, "BorderWidth"))
+                  except when not_found, overflow, bad_format: bwidth := 2 end
+               spec: string := "=80x24"
+               cfore: string := x_default(myname, "Foreground")
+                  except when not_found: cfore := "" end
+               cback: string := x_default(myname, "Background")
+                  except when not_found: cback := "" end
+               ccurs: string := x_default(myname, "Cursor")
+                  except when not_found: ccurs := "" end
+               chigh: string := x_default(myname, "Highlight")
+                  except when not_found: chigh := "" end
+               cbdr: string := x_default(myname, "Border")
+                  except when not_found: cbdr := "" end
+               mfore: string := x_default(myname, "Mouse")
+                  except when not_found: mfore := "" end
+               mousefunc := int$parse(x_default(myname, "MouseFunction"))
+                  except when not_found, overflow, bad_format: mousefunc := GXcopy end
+               icon: bool := x_default(myname, "BitmapIcon") = "on"
+                  except when not_found: icon := false end
+               for opt: string in qs$elements(options) do
+                   if opt = "-rv"
+                      then revvid := true
+                    elseif opt = "-i"
+                      then icon := true
+                    elseif string$indexs("-fn=", opt) = 1
+                      then font := string$rest(opt, 5)
+                    elseif string$indexs("-fg=", opt) = 1
+                      then cfore := string$rest(opt, 5)
+                    elseif string$indexs("-bg=", opt) = 1
+                      then cback := string$rest(opt, 5)
+                    elseif string$indexs("-cr=", opt) = 1
+                      then ccurs := string$rest(opt, 5)
+                    elseif string$indexs("-hl=", opt) = 1
+                      then chigh := string$rest(opt, 5)
+                    elseif string$indexs("-bd=", opt) = 1
+                      then cbdr := string$rest(opt, 5)
+                    elseif string$indexs("-ms=", opt) = 1
+                      then mfore := string$rest(opt, 5)
+                    elseif opt[1] = '='
+                      then spec := opt
+                    else if opt[1] = '-'
+                            then opt := string$rest(opt, 2) end
+                         if string$indexc(':', opt) ~= 0
+                            then display := opt
+                            else font := opt
+                            end
+                    end
+                   end
+               x_display$init(display)
+                  except when error, failure (why: string):
+                              _chan$puts(_chan$error_output(), why || "\r\n",
+                                         false)
+                              quit_()
+                         end
+               f := x_font$create(font)
+                  except when error (*):
+                              _chan$puts(_chan$error_output(), "bad font\r\n",
+                                         false)
+                              quit_()
+                         end
+               clearmap, bdrmap: x_pixmap
+               if revvid
+                  then textpix := WhitePixel
+                       bdrmap := x_display$white()
+                       clearpix := BlackPixel
+                       clearmap := x_display$black()
+                  else textpix := BlackPixel
+                       bdrmap := x_display$black()
+                       clearpix := WhitePixel
+                       clearmap := x_display$white()
+                  end
+               mousepix := textpix
+               crcols := colordeflist$new()
+               hlcols := colordeflist$new()
+               begin
+               if x_display$cells() > 2  cand
+                  (~string$empty(cfore)  cor  ~string$empty(cback) cor
+                   ~string$empty(ccurs)  cor  ~string$empty(chigh))
+                  then pixs: pixellist
+                       if string$empty(ccurs)  cand  string$empty(chigh)
+                          then pixs, planemask := x_display$alloc_cells(
+                                                      1, 1, false)
+                               clearpix := pixs[1]
+                               textpix := clearpix + planemask
+                          else pixs, planemask := x_display$alloc_cells(
+                                                      2, 1, false)
+                               clearpix := pixs[1]
+                               textpix := pixs[2]
+                          end
+                       mousepix := textpix
+                       r, g, b: int
+                       if string$empty(cback)
+                          then r, g, b := x_display$query_color(clearpix)
+                          else r, g, b := x_parse_color(cback)
+                          end
+                       x_display$store_color(clearpix, r, g, b)
+                       if ~string$empty(ccurs)  cor  ~string$empty(chigh)
+                          then x_display$store_color(textpix + planemask,
+                                                     r, g, b)
+                          end
+                       clearmap := x_pixmap$tile(clearpix)
+                       if string$empty(cfore)
+                          then r, g, b := x_display$query_color(textpix)
+                          else r, g, b := x_parse_color(cfore)
+                          end
+                       x_display$store_color(textpix, r, g, b)
+                       if ~string$empty(chigh)
+                          then hr, hg, hb: int := x_parse_color(chigh)
+                               colordeflist$addh(hlcols,
+                                                 colordef${pixel: clearpix +
+                                                                  planemask,
+                                                           red:   hr,
+                                                           green: hg,
+                                                           blue:  hb})
+                          end
+                       if ~string$empty(ccurs)
+                          then r, g, b := x_parse_color(ccurs) end
+                       colordeflist$addh(crcols,
+                                         colordef${pixel: clearpix +
+                                                          planemask,
+                                                   red:   r,
+                                                   green: g,
+                                                   blue:  b})
+                       if ~string$empty(ccurs)  cor  ~string$empty(chigh)
+                          then x_display$store_color(clearpix + planemask,
+                                                     r, g, b)
+                          end
+                  else planemask := 1
+                  end
+               if x_display$cells() > 2
+                  then if ~string$empty(cbdr)
+                          then r, g, b: int := x_parse_color(cbdr)
+                               bdrmap := x_pixmap$tile(x_display$alloc_color(
+                                                           r, g, b))
+                          end
+                       if ~string$empty(mfore)
+                          then r, g, b: int := x_parse_color(mfore)
+                               mousepix := x_display$alloc_color(r, g, b)
+                          end
+                  end
+               end except when undefined, bad_format:
+                               _chan$puts(_chan$error_output(), "bad color\r\n",
+                                          false)
+                               quit_()
+                          end
+               first, last: char
+               base: int
+               fixed: bool
+               fwidth, fheight, first, last, base, fixed := x_font$query(f)
+               w, hsize, vsize := x_tcons(myname, clearmap, bdrmap,
+                                          spec, "=80x24+1+1",
+                                          f, fwidth, fheight, 2,
+                                          6, 6, bwidth)
+               if icon
+                  then of := x_font$create("nil2")
+                       owidth, oheight, first, last, base, fixed :=
+                           x_font$query(of)
+                       ow := x_window$create(0, 0, hsize * owidth + 2,
+                                             vsize * oheight + 2, clearmap,
+                                             x_display$root(), 2, bdrmap)
+                       ow.input := events
+                       w.icon := ow
+                  else ow := x_window$none()
+                  end except when error (*):
+                                  _chan$puts(_chan$error_output(), "bad font\r\n",
+                                             false)
+                                  quit_()
+                             end
+               w.name := myname
+               x_window$set_resize(w, 2, fwidth, 2, fheight)
+               w.input := events - ExposeRegion
+               x_window$map(w)
+               w.input := events
+               new_cursor()
+               nobit := x_bitmap$none()
+               vsize1 := vsize - 1
+               hsize1 := hsize - 1
+               chpos := 0
+               cdisp := false
+               hlmode := false
+               high := false
+               done := true
+          else leave_image_mode()
+          end
+       enter_image_mode()
+       end init
+
+    enter_image_mode = proc ()
+       if image
+          then return end
+       sx, sy, sw, sh, wb, ms, wk: int, iw: x_window := x_window$query(w)
+       hsize := int$max((sw + fwidth - 3) / fwidth, 6)
+       hsize1 := hsize - 1
+       vsize := int$max((sh + fheight - 3) / fheight, 6)
+       vsize1 := vsize - 1
+       nw: int := hsize * fwidth + 2
+       nh: int := vsize * fheight + 2
+       if nh ~= sh  cor  nw ~= sw
+          then x_window$change(w, nw, nh)
+               if ow ~= x_window$none()
+                  then x_window$change(ow, hsize * owidth + 2,
+                                       vsize * oheight + 2)
+                  end
+          end
+       output$reset()
+       vpos := -1        % force positioning
+       hpos := -1
+       image := true
+       end enter_image_mode
+
+    leave_image_mode = proc ()
+       if image
+          then input$reset()
+               image := false
+          end
+       end leave_image_mode
+
+    destroy = proc ()
+       leave_image_mode()
+       x_window$destroy(w)
+       done := false
+       end destroy
+
+    set_padding = proc (b: bool)
+       end set_padding
+
+    set_scroll = proc (b: bool)
+       end set_scroll
+
+    set_keypad_mode = proc (b: bool) returns (bool)
+       return(false)
+       end set_keypad_mode
+
+    set_highlight = proc (h, b: bool)
+       hlmode := b
+       if h
+          then w.input := events + MouseMoved
+               if ~colordeflist$empty(hlcols)
+                  then x_display$store_colors(hlcols) end
+          else w.input := events
+               if ~colordeflist$empty(hlcols)
+                  then x_display$store_colors(crcols) end
+          end
+       end set_highlight
+
+    recolor = proc (white: bool) returns (bool)
+       if textpix > WhitePixel
+          then return(false) end
+       if white
+          then textpix := BlackPixel
+               clearpix := WhitePixel
+               w.background := x_display$white()
+               w.border := x_display$black()
+          else textpix := WhitePixel
+               clearpix := BlackPixel
+               w.background := x_display$black()
+               w.border := x_display$white()
+          end
+       mousepix := textpix
+       x_window$clear(w)
+       new_cursor()
+       return(true)
+       end recolor
+
+    clear = proc ()
+       ovsize: int := al$size(lines)
+       x_window$clear(w)
+       x_flush()
+       deltav: int := vsize - ovsize
+       deltah: int := hsize1 - act$size(holder)
+       limit: int := ovsize - 1
+       if deltav < 0
+          then limit := vsize1 end
+       % clear out char arrays, and auxiliary info
+       for i: int in int$from_to(0, limit) do
+           line: ldata := lines[i]
+           lim: int := line.lim
+           chars: act := line.line
+           zapc(chars, 0, lim+1, ' ')
+           if deltah < 0
+              then act$trim(chars, 0, hsize1)
+              else for j: int in int$from_to_by(deltah, 1, -1) do
+                       act$addh(chars, ' ')
+                       end
+              end
+           line.lim := -1
+           line.len := 0
+           line.str := ""
+           end
+       if deltav < 0
+          then al$trim(lines, 0, vsize)
+          else for i: int in int$from_to_by(deltav, 1, -1) do
+                   line: ldata :=
+                       ldata${line: act$fill(0, hsize1, ' '),
+                              lim:  -1,
+                              len:  0,
+                              str:  ""}
+                   al$addh(lines, line)
+                   end
+          end
+       if deltah < 0
+          then act$trim(holder, 0, hsize1)
+               if hlim >= hsize1
+                  then hlim := hsize - 2 end
+          else for i: int in int$from_to_by(deltah, 1, -1) do
+                   act$addh(holder, ' ')
+                   end
+          end
+       vpos := -1   % force positioning
+       cdisp := false
+       set_cursor_pos(0, 0, true)
+       end clear
+
+    display_line = proc (s: string, lpos: int) returns (bool) signals (bounds)
+       line: ldata := lines[lpos]
+          resignal bounds
+       if s = line.str
+          then return(false) end
+       if cdisp
+          then forget_cursor() end
+       new: act := holder
+       nlim, newlen: int := _calc_hpos_copy(s, new)
+       if hlim >= newlen
+          then zapc(new, newlen, hlim - newlen + 1, ' ') end
+       old: act := line.line
+       oldlen: int := line.len
+       olim: int := line.lim
+       excl: char := ' '
+       if oldlen >= hsize
+          then excl := '!' end
+       mlim: int := nlim
+       mpos: int := _diff_scan(new, old, 0, mlim)
+       if hpos ~= mpos cor vpos ~= lpos  cor  cdisp
+          then reposition(lpos, mpos) end
+       outa(new, mpos, mlim - mpos + 1)
+       hpos := mlim + 1
+       mpos := hpos
+
+       if mlim < olim
+          then % keol needed
+               vpos := lpos
+               hpos := mpos
+               chpos := mpos
+               if excl = ' '
+                  then mlim := olim + 1
+                  else mlim := hsize
+                       excl := ' '
+                  end
+               clear_region(lpos, mpos, 1, mlim - mpos)
+          end
+       dexcl: char := ' '      % desired excl place char
+       if newlen >= hsize
+          then dexcl := '!' end
+       if dexcl ~= excl
+          then reposition(lpos, hsize1)
+               outc(dexcl)
+               hpos := hsize
+               reposition(lpos, hsize1)
+          end
+       holder := old
+       hlim := olim
+       line.line := new
+       line.lim := nlim
+       line.len := newlen
+       line.str := s
+       return(true)
+       end display_line
+
+    redisplay_line = proc (lpos: int)
+       line: ldata := lines[lpos]
+          except when bounds: return end
+       if cdisp
+          then forget_cursor() end
+       vpos := -1
+       s: string := line.str
+       zapc(line.line, 0, hsize1, '\177')
+       if line.len >= hsize
+          then line.len := hsize1
+          else line.len := hsize
+          end
+       line.lim := hsize1
+       line.str := "\177"
+       display_line(s, lpos)
+       end redisplay_line
+
+    display_chars = proc (nvpos, ohpos, nhpos: int, chars: act, mhpos: int)
+       xline := chars
+       xvpos := nvpos
+       if xhpos > xmpos
+          then xhpos := ohpos end
+       xmpos := nhpos
+       reposition(nvpos, ohpos)
+       outa(chars, ohpos, nhpos - ohpos)
+       hpos := nhpos
+       if nhpos < mhpos
+          then clear_region(nvpos, nhpos, 1, mhpos - nhpos) end
+       display_cursor()
+       end display_chars
+
+    update_line = proc (s: string, lpos: int) signals (bounds)
+       xmpos := -1
+       line: ldata := lines[lpos]
+          resignal bounds
+       nlim, newlen: int := _calc_hpos_copy(s, line.line)
+       if line.lim >= newlen
+          then zapc(line.line, newlen, line.lim - newlen + 1, ' ') end
+       line.lim := nlim
+       line.len := newlen
+       line.str := s
+       end update_line
+
+    reposition = proc (nvpos, nhpos: int)
+       if nhpos >= hsize
+          then nhpos := hsize1 end
+       if cdisp
+          then forget_cursor() end
+       if vpos ~= nvpos cor hpos ~= nhpos
+          then vpos := nvpos
+               hpos := nhpos
+               chpos := hpos
+          end
+       end reposition
+
+    set_cursor_pos = proc (nvpos, nhpos: int, doit: bool)
+       if nhpos >= hsize
+          then nhpos := hsize1 end
+       if nvpos ~= vpos  cor  nhpos ~= hpos
+          then if cdisp
+                  then forget_cursor() end
+               vpos := nvpos
+               hpos := nhpos
+               chpos := hpos
+          end
+       if ~cdisp
+          then display_cursor() end
+       if doit
+          then x_flush() end
+       end set_cursor_pos
+
+    forget_cursor = proc ()
+       x_window$pix_fill(w, 0, nobit, 1 + hpos * fwidth, 1 + vpos * fheight,
+                         fwidth, fheight, GXinvert, planemask)
+       cdisp := false
+       end forget_cursor
+
+    display_cursor = proc ()
+       x_window$pix_fill(w, 0, nobit, 1 + hpos * fwidth, 1 + vpos * fheight,
+                         fwidth, fheight, GXinvert, planemask)
+       cdisp := true
+       end display_cursor
+
+    get_cursor_pos = proc () returns (int, int)
+       return(vpos, hpos)
+       end get_cursor_pos
+
+    position = proc (x, y: int) returns (int, int)
+       return((x - 1) / fwidth, (y - 1) / fheight)
+       end position
+
+    get_padding = proc () returns (bool)
+       return(false)
+       end get_padding
+
+    get_screen_size = proc () returns (int, int)
+       return(vsize, hsize)
+       end get_screen_size
+
+    fetch = proc (lpos: int) returns (string) signals (bounds)
+       return(lines[lpos].str)
+          resignal bounds
+       end fetch
+
+    id_lines_poss = proc () returns (bool)
+       return(true)
+       end id_lines_poss
+
+    scrolling_poss = proc () returns (bool)
+       return(false)
+       end scrolling_poss
+
+    should_id_lines = proc (top, bot, delta, num_saved: int) returns (bool)
+       return(num_saved > 0)
+       end should_id_lines
+
+    scroll = proc (top, bot, delta: int)
+       d: int := int$abs(delta)
+       topd: int := top + d
+       pos: int := bot - d + 1
+       numshift: int := pos - top
+       input$copy_wait()
+       if cdisp
+          then forget_cursor() end
+       max: int := 0
+       for i: int in int$from_to(top, bot) do
+           line: ldata := lines[i]
+           if lines[i].len >= hsize
+              then max := hsize
+                   break
+              end
+           max := int$max(max, line.lim)
+           end
+       max := max + 1
+       vpos := -1
+       if delta < 0
+          then % are scrolling up
+               copy_region(topd, 0, top, 0, pos - top, max)
+               clear_region(pos, 0, d, max)
+               repll(temp, 0, al$size(temp), lines, top, d)
+               for ltemp: ldata in al$elements(temp) do
+                   zapc(ltemp.line, 0, ltemp.lim+1, ' ')
+                   ltemp.lim := -1
+                   ltemp.len := 0
+                   ltemp.str := ""
+                   end
+               shiftl(lines, topd, numshift, delta)
+               repll(lines, pos, d, temp, 0, d)
+          else % scrolling down
+               copy_region(top, 0, topd, 0, pos - top, max)
+               clear_region(top, 0, d, max)
+               repll(temp, 0, al$size(temp), lines, pos, d)
+               for ltemp: ldata in al$elements(temp) do
+                   zapc(ltemp.line, 0, ltemp.lim+1, ' ')
+                   ltemp.lim := -1
+                   ltemp.len := 0
+                   ltemp.str := ""
+                   end
+               shiftl(lines, top, numshift, delta)
+               repll(lines, top, d, temp, 0, d)
+          end
+       end scroll
+
+    should_scroll = proc (delta, num_saved, num_saved0: int) returns (bool)
+                     signals (clear, id_lines)
+       return(false)
+       end should_scroll
+
+    full_scroll = proc (delta: int) returns (bool)
+       return(false)
+       end full_scroll
+
+    bell = proc ()
+       x_feep(0)
+       end bell
+
+    highlight = proc (flag: bool)
+       if ~cdisp
+          then return end
+       if ~flag
+          then if high
+                  then dohigh(vpos, hpos, hvpos, hhpos)
+                       high := false
+                  end
+               return
+          end
+       h, v: int, sw: x_window := x_window$query_mouse(w)
+       h := int$min(int$max(0, (h - 1) / fwidth), hsize)
+       v := int$min(int$max(0, (v - 1) / fheight), vsize)
+       if h > 0  cand  ~(v = xvpos  cand  xmpos > xhpos  cand  h > xhpos)
+          then l: ldata := lines[v]
+               if h < l.len  cand  string$indexc(l.line[h - 1], " ^&!") > 0
+                  then i: int := int$max(h + 2, string$size(l.str) + 1)
+                       oh: int := h
+                       while true do
+                           h := _calc_hpos(l.str, i)
+                           if h <= oh
+                              then break end
+                           i := i - 1
+                           end
+                  end
+          end except when bounds: end
+       if ~high
+          then dohigh(vpos, hpos, v, h)
+        elseif v = hvpos  cand  h = hhpos
+          then return
+        elseif (v > vpos  cor  (v = vpos  cand  h > hpos))  cand
+               (hvpos > vpos  cor  (hvpos = vpos  cand  hhpos > hpos))
+          then dohigh(hvpos, hhpos, v, h)
+        elseif (v < vpos  cor  (v = vpos  cand  h < hpos))  cand
+               (hvpos < vpos  cor  (hvpos = vpos  cand  hhpos < hpos))
+          then dohigh(v, h, hvpos, hhpos)
+        else dohigh(vpos, hpos, hvpos, hhpos)
+             dohigh(vpos, hpos, v, h)
+        end
+       high := true
+       hvpos := v
+       hhpos := h
+       end highlight
+
+    dohigh = proc (v1, h1, v2, h2: int)
+       if v1 = v2
+          then if h1 > h2
+                  then h1, h2 := h2, h1 end
+        elseif v1 > v2
+          then v1, v2 := v2, v1
+               h1, h2 := h2, h1
+        end
+       if h1 < 0
+          then h1 := 0
+        elseif h1 > hsize1
+          then v1 := v1 + 1
+               h1 := 0
+        end
+       if v1 < 0
+          then v1 := 0
+               h1 := 0
+        elseif v1 > vsize1
+          then v1 := vsize1
+               h1 := hsize1
+        elseif v1 = vpos  cand  h1 = hpos
+          then h1 := h1 + 1 end
+       if v2 > vsize1
+          then v2 := vsize1
+               h2 := hsize1
+        elseif h2 > hsize
+          then h2 := hsize end
+       v: int
+       if hlmode
+          then v := 1 + v1 * fheight
+          else v := (v1 + 1) * fheight
+          end
+       while v1 < v2 do
+           h: int := lines[v1].len
+           if v1 = xvpos  cand  xmpos > xhpos
+              then h := xmpos end
+           if h1 < h
+              then dohigh1(v, h1, h) end
+           v := v + fheight
+           v1 := v1 + 1
+           h1 := 0
+           end
+       h2 := int$min(h2, lines[v2].len)
+       if v2 = xvpos  cand  xmpos > xhpos
+          then h2 := xmpos end
+       if h1 < h2
+          then dohigh1(v, h1, h2) end
+       end dohigh
+
+    dohigh1 = proc (v, h1, h2: int)
+       if hlmode
+          then x_window$pix_fill(w, 0, nobit, 1 + h1 * fwidth, v,
+                                 (h2 - h1) * fwidth, fheight, GXinvert,
+                                 planemask)
+          else x_window$line(w, 0, 1, 1,
+                             1 + h1 * fwidth, v, h2 * fwidth, v, GXinvert,
+                             planemask)
+          end
+       end dohigh1
+
+    redisplay = proc (win: x_window, x, y, width, height: int)
+       if win ~= w
+          then return end
+       h1: int := int$max(0, (x - 1) / fwidth)
+       h2: int := (x + width - 2) / fwidth
+       if h2 < h1
+          then return end
+       v1: int := int$max(0, (y - 1) / fheight)
+       v2: int := (y + height - 2) / fheight
+       if cdisp  cand
+          vpos >= v1  cand  vpos <= v2  cand  hpos >= h1  cand  hpos <= h2
+          then clear_region(vpos, hpos, 1, 1)
+               cdisp := false
+          end
+       ovpos: int := vpos
+       ohpos: int := hpos
+       for lpos: int in int$from_to(v1, v2) do
+           line: ldata := lines[lpos]
+           if line.lim < h1
+              then continue end
+           reposition(lpos, h1)
+           outa(line.line, h1, int$min(line.lim, h2) - h1 + 1)
+           if h2 >= hsize1  cand  line.len >= hsize
+              then reposition(lpos, hsize1)
+                   outc('!')
+              end
+           end except when bounds: end
+       if xmpos > xhpos  cand  xmpos > h1  cand  xhpos <= h2  cand
+          xvpos >= v1  cand  xvpos <= v2
+          then pos: int := int$max(xhpos, h1)
+               reposition(xvpos, pos)
+               outa(xline, pos, int$min(xmpos - 1, h2) - pos + 1)
+          end
+       set_cursor_pos(ovpos, ohpos, true)
+       end redisplay
+
+    unmapped = proc (win: x_window)
+       if win = w  cand  ow ~= x_window$none()
+          then w, ow := ow, w
+               f, of := of, f
+               fheight, oheight := oheight, fheight
+               fwidth, owidth := owidth, fwidth
+               redisplay(w, 1, 1, fwidth * hsize, fheight * vsize)
+          end
+       end unmapped
+
+    copy_region = proc (ovpos, ohpos, nvpos, nhpos, height, width: int)
+       x_window$move_area(w, 1 + ohpos * fwidth, 1 + ovpos * fheight,
+                          width * fwidth, height * fheight,
+                          1 + nhpos * fwidth, 1 + nvpos * fheight)
+       end copy_region
+
+    clear_region = proc (nvpos, nhpos, height, width: int)
+       x_window$pix_set(w, clearpix, 1 + nhpos * fwidth, 1 + nvpos * fheight,
+                        width * fwidth, height * fheight)
+       end clear_region
+
+    outc = proc (c: char)
+       x_window$text(w, string$c2s(c), f, textpix, clearpix,
+                     1 + chpos * fwidth, 1 + vpos * fheight)
+       chpos := chpos + 1
+       end outc
+
+    outa = proc (a: act, i, z: int) signals (bounds, negative_size)
+       x_window$texta(w, a, i, z, f, textpix, clearpix,
+                      1 + chpos * fwidth, 1 + vpos * fheight)
+       chpos := chpos + z
+       end outa
+
+    new_cursor = proc ()
+       cursbits = "\003\000\005\000\011\000\021\000\041\000\101\000" ||
+                  "\201\000\001\001\001\002\301\003\111\000\225\000" ||
+                  "\223\000\040\001\040\001\300\000"
+       maskbits = "\003\000\007\000\017\000\037\000\077\000\177\000" ||
+                  "\377\000\377\001\377\003\377\003\177\000\367\000" ||
+                  "\363\000\340\001\340\001\300\000"
+
+       cursor: x_cursor := x_cursor$scons(11, 16,
+                                          cursbits, maskbits,
+                                          clearpix, mousepix, 1, 1, mousefunc)
+       w.cursor := cursor
+       if ow ~= x_window$none()
+          then ow.cursor := cursor end
+       x_cursor$destroy(cursor)
+       end new_cursor
+
+    end screen