Patch title: Release 94 bulk changes
Abstract:
File: /pliant/graphic/console/framebuffer.pli
Key:
    Removed line
    Added line
   
module "/pliant/language/compiler.pli"
module "prototype.pli"
module "/pliant/language/compiler.pli"
module "prototype.pli"
module "/pliant/graphic/color/gamut.pli"


module "/pliant/language/os.pli"
module "/pliant/language/stream/pipe.pli"
module "/pliant/admin/file.pli"
module "/pliant/admin/execute.pli"
module "/pliant/fullpliant/this_computer.pli"
module "/pliant/linux/input/mapping.pli"
module "/pliant/language/type/text/str32.pli"
module "/pliant/util/encoding/utf8.pli"


module "/pliant/linux/input/terminal.pli"
module "framebuffer_common.pli"

constant fb_configure false
constant console_configure false
constant use_signals false
constant shrink_queue false
constant verbose false

if console_configure
  module "/pliant/language/stream.pli"
  module "/pliant/linux/kernel/device.pli"

function desable h
  arg Int h
  var uInt8 cmd := 0F5h ; os_write h addressof:cmd 1
  os_read h addressof:(var uInt8 ack) 1
  if ack<>0FAh
    console "mouse desable acked with " (cast ack Int) eol

function enable h
  arg Int h
  var uInt8 cmd := 0F4h ; os_write h addressof:cmd 1
  os_read h addressof:(var uInt8 ack) 1
  if ack<>0FAh
    console "mouse enable acked with " (cast ack Int) eol

function set_sample_rate h rate -> status
  arg Int h rate ; arg Status status
  var uInt8 cmd := 0F3h ; os_write h addressof:cmd 1
  os_read h addressof:(var uInt8 ack) 1
  if ack<>0FAh
    console "ack is " (cast ack Int) eol
    return failure
  var uInt8 cmd := rate ; os_write h addressof:cmd 1
  os_read h addressof:(var uInt8 ack) 1
  if ack<>0FAh
    return failure
  status := success

function get_id h -> id
  arg Int h id
  var uInt8 cmd := 0F2h ; os_write h addressof:cmd 1
  os_read h addressof:(var uInt8 ack) 1
  if ack<>0FAh
    return undefined
  os_read h addressof:(var uInt8 ack) 1
  id := ack


#------------------------------------------------------------------------------


type ConsoleEvent
  field Str event
  field Str key
  field Int buttons
  field Int x_or_x0 y_or_y0
  field Int x1 y1
  field Str options


type ConsoleFramebuffer
type ConsoleFramebuffer
  void
  field Int handle
  field Int terminal <- 0
  field Address buffer
  field ImagePrototype proto ; field Int pixel_size line_size
  field CBool locked
  field CBool copyarea <- true
  #
  field Int cursor_x cursor_y
  field Int cursor_x0 cursor_y0 cursor_x1 cursor_y1
  field CBool cursor_is_on
  field Int cursor_color cursor_border_color
  field Int cursor_thickness cursor_border_size cursor_size cursor_hole
  field Address cursor_buffer <- null
  field Sem paint_sem
  #
  field List:ConsoleEvent events
  field Int keyboard_handle <- undefined
  field Str keyboard_switch keyboard_modifier keyboard_last
  field Int mouse_handle <- undefined
  field CBool mouse_extended
  field Int mouse_divisor
  field Int mouse_buttons mouse_move_x mouse_move_y
  #
  if console_configure
    field CBool signal_handlers <- false
    field CBool active <- false
    field Stream in_pipe out_pipe


ConsoleFramebuffer maybe ConsoleFramebuffer
ConsolePrototype maybe ConsoleFramebuffer


method c open p options
  oarg_rw ConsoleFramebuffer c ; arg ImagePrototype p ; arg 


method c pixel x y -> adr
  arg ConsoleFramebuffer c ; arg Int x y ; arg Address adr
  check x>=0 and x<c:proto:size_x
  check y>=0 and y<c:proto:size_y
  adr := c:buffer translate Byte x*c:pixel_size+y*c:line_size


if console_configure

  method c activate
    arg_rw ConsoleFramebuffer c
    c active := true
    # (var Stream tty) open "device:/tty"+(string c:terminal) out+safe
    # os_ioctl tty:stream_handle os_KDSETMODE (cast os_KD_GRAPHICS Address) # make console silent
    # tty close
    os_ioctl 0 os_KDSETMODE (cast os_KD_GRAPHICS Address) # console active
    os_ioctl c:handle FBIOGET_VSCREENINF0 addressof:(var fb_var_screeninfo info)
    info xoffset := 0 ; info yoffset :=0
    os_ioctl c:handle FBIOPAN_DISPLAY addressof:info
    for (var Int i) 0 255
      var uInt16 v16 := i*257
      var fb_cmap cmap ; cmap start := i ; cmap len := 1
      cmap red := addressof v16
      cmap green := addressof v16
      cmap blue := addressof v16
      cmap transp := null
      os_ioctl c:handle FBIOPUTCMAP addressof:cmap
  
  method c suspend
    arg_rw ConsoleFramebuffer c
    c active := false
    os_ioctl 0 os_KDSETMODE (cast os_KD_TEXT Address) # console active
  
  if use_signals
  
    gvar Pointer:ConsoleFramebuffer default_fb
    
    function terminal_enter_handler
      external_calling_convention
      default_fb activate
      default_fb:out_pipe raw_write addressof:(var uInt8 cmd) 1
    
    function terminal_leave_handler
      external_calling_convention
      default_fb suspend
  
    gvar os_sigaction sa1
    sa1 sa_handler := (the_function terminal_enter_handler) executable
    entry_root addressof:(the_function terminal_enter_handler)
    gvar os_sigaction sa2
    sa2 sa_handler := (the_function terminal_leave_handler) executable
    entry_root addressof:(the_function terminal_leave_handler)
  
  method c set_signal_handlers
    oarg_rw ConsoleFramebuffer c
    if c:signal_handlers
      return
    c signal_handlers := true
    stream_pipe (var Str in_name) (var Str out_name)
    c:in_pipe open in_name in+nocache+safe
    c:out_pipe open out_name out+nocache+safe
    if use_signals
      default_fb :> c
      (var Stream tty) open "device:/tty"+(string c:terminal) out+safe
      os_ioctl tty:stream_handle os_VT_GETMODE addressof:(var os_vt_mode mode)
      mode mode := os_VT_AUTO
      mode acqsig := 21 # SIGTTIN
      mode relsig := 22 # SIGTTOU
      os_ioctl tty:stream_handle os_VT_SETMODE addressof:(var os_vt_mode mode)
      tty close
      os_sigaction mode:acqsig sa1 (null map os_sigaction)
      os_sigaction mode:relsig sa2 (null map os_sigaction)
    else
      thread
        share c
        while true
          sleep 0.25
          var CBool old_active := c active
          os_ioctl 0 os_VT_GETSTATE addressof:(var os_vt_stat stat)
          var CBool new_active := stat:v_active=c:terminal
          if new_active and not old_active
            c activate
            c:out_pipe raw_write addressof:(var uInt8 cmd) 1
          eif old_active and not new_active
            c suspend


method c open p options -> status
  oarg_rw ConsoleFramebuffer c ; arg ImagePrototype p ; arg Str options ; arg ExtendedStatus status
  c handle := os_open "/dev/fb0" os_O_RDWR 0
  if c:handle<0
    return failure:"failed to open framebuffer device"
  if console_configure
    c terminal := options option "terminal" Int 0
    if c:terminal<>0
      kernel_make_device "device:/tty"+(string c:terminal)
      (var Stream tty) open "device:/tty"+(string c:terminal) out+safe
      tty writechars character:27+"[lb]?25l" # hide cursor
      tty close
      c set_signal_handlers
      os_ioctl 0 os_VT_ACTIVATE (cast c:terminal Address)
  else
    console character:27+"[lb]?25l"
    os_ioctl 0 os_KDSETMODE (cast os_KD_GRAPHICS Address) # console active
    os_ioctl c:handle FBIOGET_VSCREENINF0 addressof:(var fb_var_screeninfo info)
    if info:xres=1920 and info:yres=1200 and (file_query "file:/backup/nvidia_xfree_dump" standard)=success
      execute "vbetool vbestate save" output "file:/backup/nvidia_fb_dump"
      execute "vbetool vbestate restore" input "file:/backup/nvidia_xfree_dump"
    info xoffset := 0 ; info yoffset := 0
    os_ioctl c:handle FBIOPAN_DISPLAY addressof:info
    for (var Int i) 0 255
      var uInt16 v16 := i*257
      var fb_cmap cmap ; cmap start := i ; cmap len := 1
      cmap red := addressof v16
      cmap green := addressof v16
      cmap blue := addressof v16
      cmap transp := null
      os_ioctl c:handle FBIOPUTCMAP addressof:cmap
  var Int err := os_ioctl c:handle FBIOGET_VSCREENINF0 addressof:(var fb_var_screeninfo info)
  if err<>0
    os_close c:handle
    return failure:"failed to get framebuffer informations"
  if fb_configure
    if (options option "size_x")
      var fb_var_screeninfo info2 := info
      info2 xres := options option "size_x" Int info:xres
      info2 yres := options option "size_y" Int info:yres
      info2 bits_per_pixel := options option "bpp" Int info:bits_per_pixel
      info2 pixclock := options option "pixclock" Int 0
      if (info2:xres<>info:xres or info2:yres<>info:yres or info2:bits_per_pixel<>info:bits_per_pixel) and (os_ioctl c:handle FBIOPUT_VSCREENINF0 addressof:info2)<>0
        os_close c:handle
        return (failure "failed to change framebuffer configuration to "+string:(cast info:xres Int)+"x"+string:(cast info:yres Int)+"x"+string:(cast info:bits_per_pixel Int))
      var Int err := os_ioctl c:handle FBIOGET_VSCREENINF0 addressof:info
      if err<>0
        os_close c:handle
        return failure:"failed to get framebuffer informations"
      if info:xres<>info2:xres or info:yres<>info2:yres or info:bits_per_pixel<>info2:bits_per_pixel
        os_close c:handle
        return (failure "got "+string:(cast info:xres Int)+"x"+string:(cast info:yres Int)+"x"+string:(cast info:bits_per_pixel Int)+" instead of "+string:(cast info2:xres Int)+"x"+string:(cast info2:yres Int)+"x"+string:(cast info2:bits_per_pixel Int))
  var Float dpi := options option "dpi" Float 100
  c proto := image_prototype 0 0 info:xres/dpi*25.4 info:yres/dpi*25.4 info:xres info:yres color_gamut:(shunt info:bits_per_pixel=24 "bgr" "bgr32")
  c pixel_size := info:bits_per_pixel\8
  if false
    var Int err := os_ioctl c:handle FBIOGET_FSCREENINF0 addressof:(var fb_fix_screeninfo finfo)
    if err<>0
      os_close c:handle
      return failure:"failed to get framebuffer fixed informations"
    c line_size := shunt finfo:line_length<>0 finfo:line_length c:pixel_size*info:xres_virtual
  else
    c line_size := c:pixel_size*info:xres_virtual
  c buffer := os_mmap null c:proto:size_y*c:line_size os_PROT_READ+os_PROT_WRITE os_MAP_SHARED c:handle 0
  c locked := false
  c cursor_x := c:proto:size_x\2
  c cursor_y := c:proto:size_y\2
  c cursor_is_on := false
  c cursor_color := 0
  c cursor_border_color := 0FFFFFFh
  c cursor_thickness := 0
  c cursor_border_size := 1
  c cursor_size := 12
  c cursor_hole := -1
  c cursor_buffer := memory_allocate 2*(1+2*c:cursor_size+2*c:cursor_border_size)*(1+2*c:cursor_thickness+2*c:cursor_border_size)*Int:size null
  c keyboard_handle := -1
  c mouse_handle := -1
  if not (this_computer:env:"hardware":"mouse":"divisor" parse c:mouse_divisor)
    c mouse_divisor := 1
  c mouse_buttons := 0
  c mouse_move_x := 0
  c mouse_move_y := 0
  status := success


function get_pixel p -> v
  arg Address p ; arg Int v
  v := (p map uInt32_li) .and. 0FFFFFFh

function set_pixel p v
  arg Address p ; arg Int v
  p map uInt32_li := (p map uInt32_li) .and. 0FF000000h .or. v

method c cursor_on
  arg_rw ConsoleFramebuffer c
  if console_configure and not c:active or c:cursor_is_on
    return
  c cursor_x0 := max c:cursor_x-c:cursor_size-c:cursor_border_size 0
  var Int x0 := max c:cursor_x-c:cursor_thickness-c:cursor_border_size 0
  c cursor_y0 := max c:cursor_y-c:cursor_size-c:cursor_border_size 0
  c cursor_x1 := min c:cursor_x+c:cursor_size+c:cursor_border_size+1 c:proto:size_x
  var Int x1 := min c:cursor_x+c:cursor_thickness+c:cursor_border_size+1 c:proto:size_x
  c cursor_y1 := min c:cursor_y+c:cursor_size+c:cursor_border_size+1 c:proto:size_y
  var Address b := c cursor_buffer
  for (var Int y) c:cursor_y0 c:cursor_y1-1
    var CBool mid := (abs y-c:cursor_y)<=c:cursor_thickness+c:cursor_border_size
    var Address p := c pixel (shunt mid c:cursor_x0 x0) y
    for (var Int x) (shunt mid c:cursor_x0 x0) (shunt mid c:cursor_x1 x1)-1
      if (abs x-c:cursor_x)<=c:cursor_thickness and (abs y-c:cursor_y)<=c:cursor_size or (abs y-c:cursor_y)<=c:cursor_thickness and (abs x-c:cursor_x)<=c:cursor_size
        if (abs x-c:cursor_x)>c:cursor_hole or (abs y-c:cursor_y)>c:cursor_hole
          b map Int := get_pixel p ; b := b translate Int
          set_pixel p c:cursor_color
      else
        b map Int := get_pixel p ; b := b translate Int
        set_pixel p c:cursor_border_color
      p := p translate Byte c:proto:pixel_size
  c cursor_is_on := true

method c cursor_off
  arg_rw ConsoleFramebuffer c
  if console_configure and not c:active or not c:cursor_is_on
    return
  var Int x0 := max c:cursor_x-c:cursor_thickness-c:cursor_border_size 0
  var Int x1 := min c:cursor_x+c:cursor_thickness+c:cursor_border_size+1 c:proto:size_x
  var Address b := c cursor_buffer
  for (var Int y) c:cursor_y0 c:cursor_y1-1
    var CBool mid := (abs y-c:cursor_y)<=c:cursor_thickness+c:cursor_border_size
    var Address p := c pixel (shunt mid c:cursor_x0 x0) y
    for (var Int x) (shunt mid c:cursor_x0 x0) (shunt mid c:cursor_x1 x1)-1
      if (abs x-c:cursor_x)<=c:cursor_thickness and (abs y-c:cursor_y)<=c:cursor_size or (abs y-c:cursor_y)<=c:cursor_thickness and (abs x-c:cursor_x)<=c:cursor_size
        if (abs x-c:cursor_x)>c:cursor_hole or (abs y-c:cursor_y)>c:cursor_hole
          set_pixel p (b map Int) ; b := b translate Int
      else
        set_pixel p (b map Int) ; b := b translate Int
      p := p translate Byte c:proto:pixel_size
  c cursor_is_on := false

method c cursor_off x0 y0 x1 y1
  arg_rw ConsoleFramebuffer c ; arg Int x0 y0 x1 y1
  if x0<c:cursor_x1 and y0<c:cursor_y1 and x1>c:cursor_x0 and y1>c:cursor_y0
    c cursor_off


method c query -> p
  oarg_rw ConsoleFramebuffer c ; arg ImagePrototype p
method c query -> p
  oarg_rw ConsoleFramebuffer c ; arg ImagePrototype p
  p := c proto



method c paint img tx ty
  oarg_rw ConsoleFramebuffer c ; oarg_rw ImagePrototype img 
method c paint img tx ty
  oarg_rw ConsoleFramebuffer c ; oarg_rw ImagePrototype img 
  if console_configure and not c:active
    return
  c:paint_sem request
  c cursor_off tx ty tx+img:size_x ty+img:size_y
  for (var Int y) 0 img:size_y-1
    img read 0 y img:size_x (c pixel tx ty+y)
  c cursor_on
  c:paint_sem release



method c copy x0 y0 x1 y1 xx yy
  oarg_rw ConsoleFramebuffer c ; arg Int x0 y0 x1 y1 xx yy
method c copy x0 y0 x1 y1 xx yy
  oarg_rw ConsoleFramebuffer c ; arg Int x0 y0 x1 y1 xx yy
  if console_configure and not c:active
    return
  c:paint_sem request
  c cursor_off x0 y0 x1 y1
  c cursor_off xx yy xx+x1-x0 yy+y1-y0
  part do_copy
    if c:copyarea
      var fb_copyarea area
      area dx := xx
      area dy := yy
      area width := x1-x0
      area height := y1-y0
      area sx := x0
      area sy := y0
      if (os_ioctl c:handle FBIO_COPYAREA addressof:area)<>0
        c copyarea := false
        restart do_copy
    else
      var Int segsize := (x1-x0)*c:proto:pixel_size
      if yy<y0
        for (var Int y) y0 y1-1
          memory_copy (c pixel x0 y) (c pixel xx yy+y-y0) segsize
      eif yy>y0
        for (var Int y) y1-1 y0 step -1
          memory_copy (c pixel x0 y) (c pixel xx yy+y-y0) segsize
      else
        for (var Int y) y0 y1-1
          memory_move (c pixel x0 y) (c pixel xx y) segsize
  c cursor_on
  c:paint_sem release


method c event key buttons x_or_x0 y_or_y0 x1 y1 -> event
  oarg_rw ConsoleFramebuffer c ; arg_w Str key ; arg_w Int b


method c keyboard_read h
  arg_rw ConsoleFramebuffer c ; arg Int h
  var Str extended := ""
  os_read h addressof:(var uInt8 ch) 1
  if ch>=224
    extended := character "a":number+ch-224 ; os_read h addressof:(var uInt8 ch) 1
  var CBool pressed := (ch .and. 80h)=0
  var Str key := string:(cast (ch .and. 7Fh) Int)+extended
  var Data:KeyboardLayout l :> keyboard_database:data:layout this_computer:env:"hardware":"keyboard":"layout"
  var Str head tail
  if { var Data:Str k :> l:key c:keyboard_modifier+key ; exists k }
    head := "" ; tail := k
  eif { var Data:Str k :> l:key key ; exists k }
    head := c keyboard_modifier ; tail := k
  else
    head := "" ; tail := ""
  if { var Data:Str m :> l:modifier key ; m<>"" }
    if (shunt pressed 1 0)=(shunt (c:keyboard_switch search m -1)=(-1) 1 0)
      if (c:keyboard_modifier search m -1)=(-1)
        c keyboard_modifier += m+" "
    else
      c keyboard_modifier := replace c:keyboard_modifier m+" " ""
    head := ""
  if { var Data:Str s :> l:switch key ; s<>"" }
    if pressed and key<>c:keyboard_last
      if (c:keyboard_switch search s -1)=(-1)
        c keyboard_switch += s+" "
      else
        c keyboard_switch := replace c:keyboard_switch s+" " ""
      os_ioctl h os_KDSETLED (cast (shunt c:keyboard_switch<>"" os_LED_CAP 0) Address)
      c keyboard_modifier := c keyboard_switch
    head := ""
  if tail<>""
    var ConsoleEvent ev
    if (tail parse (var Int code)) and head=""
      ev event := shunt pressed "character" "uncharacter"
      ev key := utf8_encode character32:code
    eif (tail parse (var Int code))
      ev event := shunt pressed "press" "release"
      ev key := head+(utf8_encode character32:code)
    else
      ev event := shunt pressed "press" "release"
      ev key := head+tail
    ev buttons := c mouse_buttons
    ev x_or_x0 := c cursor_x
    ev y_or_y0 := c cursor_y
    ev x1 := undefined
    ev y1 := undefined
    ev options := "keycode "+key
    c events += ev

method c mouse_read h
  arg_rw ConsoleFramebuffer c ; arg Int h
  os_read h addressof:(var uInt8 cmd) 1
  if (cmd .and. 8)=0
    return
  os_read h addressof:(var uInt8 x8) 1
  os_read h addressof:(var uInt8 y8) 1
  if c:mouse_extended
    os_read h addressof:(var uInt8 z8) 1
  var Int buttons := (cmd .and. 1)+(cmd .and. 2)*2+(cmd .and. 4)\2 # +(shunt c:mouse_extended (z8 .and. 30h)\2 0)
  if (cmd .and. 0C0h)=0 # no movement overflow
    c mouse_move_x += (shunt (cmd .and. 10h)<>0 -256 0) .or. x8
    c mouse_move_y += (shunt (cmd .and. 20h)<>0 -256 0) .or. y8
    if c:mouse_extended
      var Int move_z := shunt (z8 .and. 08h)<>0 (-16 .or. (z8 .and. 0Fh)) (z8 .and. 0Fh)
      while move_z<>0
        var ConsoleEvent ev
        ev event := "press"
        ev key := shunt move_z<0 "up" "down"
        ev buttons := c mouse_buttons
        ev x_or_x0 := c cursor_x
        ev y_or_y0 := c cursor_y
        ev x1 := undefined
        ev y1 := undefined
        c events += ev
        move_z += shunt move_z<0 1 -1
  var Int dx := c:mouse_move_x\c:mouse_divisor ; c mouse_move_x := c:mouse_move_x%c:mouse_divisor
  var Int dy := c:mouse_move_y\c:mouse_divisor ; c mouse_move_y := c:mouse_move_y%c:mouse_divisor
  if c:locked
    if dx<>0 or dy<>0
      if shrink_queue
        var Pointer:ConsoleEvent l :> c:events last
        if exists:l and l:event="scroll"
          dx += l x_or_x0
          dy -= l y_or_y0
          c:events remove l
          # console "*"
      var ConsoleEvent ev
      ev event := "scroll"
      ev key := ""
      ev buttons := buttons
      ev x_or_x0 := dx
      ev y_or_y0 := -dy
      ev x1 := c cursor_x
      ev y1 := c cursor_y
      c events += ev
  else
    var Int cx := min (max c:cursor_x+dx 0) c:proto:size_x-1
    var Int cy := min (max c:cursor_y-dy 0) c:proto:size_y-1
    if cx<>c:cursor_x or cy<>c:cursor_y
      if shrink_queue
        var Pointer:ConsoleEvent l :> c:events last
        if exists:l and l:event="move"
          c:events remove l
          # console "-"
      var ConsoleEvent ev
      ev event := "move"
      ev key := ""
      ev buttons := buttons
      ev x_or_x0 := cx
      ev y_or_y0 := cy
      ev x1 := undefined
      ev y1 := undefined
      c events += ev
      c:paint_sem request
      c cursor_off
      c cursor_x := cx
      c cursor_y := cy
      c cursor_on
      c:paint_sem release
  for (var Int i) 0 7
    if (buttons .and. 2^i)<>(c:mouse_buttons .and. 2^i)
      var ConsoleEvent ev
      ev event := shunt (buttons .and. 2^i)<>0 "press" "release"
      ev key := "button"+(string i+1)
      ev buttons := buttons
      ev x_or_x0 := c cursor_x
      ev y_or_y0 := c cursor_y
      ev x1 := undefined
      ev y1 := undefined
      c events += ev
  c mouse_buttons := buttons

if console_configure

  method c add_redraw_event
    arg_rw ConsoleFramebuffer c
    c:in_pipe raw_read addressof:(var uInt8 drop) 1
    var ConsoleEvent ev
    ev event := "redraw"
    ev key := ""
    ev x_or_x0 := 0
    ev y_or_y0 := 0
    ev x1 := c:proto size_x
    ev y1 := c:proto size_y
    c events += ev

method c event key buttons x_or_x0 y_or_y0 x1 y1 options -> event
  oarg_rw ConsoleFramebuffer c ; arg_w Str key ; arg_w Int buttons x_or_x0 y_or_y0 x1 y1 ; arg_w Str options ; arg Str event
  if c:keyboard_handle<0
    var Str device := this_computer:env:"hardware":"keyboard":"device"
    if device=""
      device := "device:/tty"+(string c:terminal) # could be device:/input/keyboard
    c keyboard_handle := os_open file_os_name:device os_O_RDONLY 0
    if c:keyboard_handle>=0
      os_ioctl c:keyboard_handle os_TCGETS addressof:(var os_TermIOs ios)
      ios c_iflag := 0 # ios:c_iflag .and. .not. os_IXOFF
      ios c_lflag := 0 # ios:c_lflag .and. .not. os_ISIG .and. .not. os_ICANON .and. .not. os_ECHO
      os_ioctl c:keyboard_handle os_TCSETS addressof:ios
      os_ioctl c:keyboard_handle os_KDSKBMODE (cast os_K_RAW Address)
  if c:mouse_handle<0
    var Str device := this_computer:env:"hardware":"mouse":"linux_device"
    if device=""
      device := "device:/input/mice" # was device:/psaux with Linux 2.4
    c mouse_handle := os_open file_os_name:device os_O_RDWR 0
    c mouse_extended := false
    desable c:mouse_handle
    if (set_sample_rate c:mouse_handle 200)=success and (set_sample_rate c:mouse_handle 200)=success and (set_sample_rate c:mouse_handle 80)=success
      var Int id := get_id c:mouse_handle
      if id=4
        if verbose
          console "switching to mouse extended mode" eol
        c mouse_extended := true
      eif verbose
        console "mouse model is " id eol
    eif verbose
      console "failed to setup mouse" eol
    enable c:mouse_handle
  if console_configure
    c set_signal_handlers
  constant hcount (shunt console_configure 3 2)
  var (Array os_pollfd hcount) fds
  fds:0 fd := c keyboard_handle
  fds:0 events := os_POLLIN
  fds:0 revents := 0
  fds:1 fd := c mouse_handle
  fds:1 events := os_POLLIN
  fds:1 revents := 0
  if console_configure
    fds:2 fd := c:in_pipe:stream_handle
    fds:2 events := os_POLLIN
    fds:2 revents := 0
  while not (exists c:events:first)
    var Int err := os_poll addressof:fds hcount -1
    if err<0
      console "failed to wait for event" eol
      event := "" ; key := "" ; x_or_x0 := undefined ; y_or_y0 := undefined ; x1 := undefined ; y1 := undefined ; options := ""
      return
    if fds:0:revents<>0
      c keyboard_read c:keyboard_handle
    eif fds:1:revents<>0
      c mouse_read c:mouse_handle
    eif console_configure and fds:2:revents<>0
      c add_redraw_event
  if shrink_queue
    while (os_poll addressof:fds hcount 0)>0
      if fds:0:revents<>0
        c keyboard_read c:keyboard_handle
      eif fds:1:revents<>0
        c mouse_read c:mouse_handle
      eif console_configure and fds:3:revents<>0
        c add_redraw_event
  var Pointer:ConsoleEvent ev :> c:events first
  event := ev event
  key := ev key
  buttons := ev buttons
  x_or_x0 := ev x_or_x0
  y_or_y0 := ev y_or_y0
  x1 := ev x1
  y1 := ev y1
  c:events remove ev
  if console_configure and not use_signals and event="press" and (key parse "ctrl alt F" (var Int i)) and i>=1 and i<=2
    c suspend
    os_ioctl 0 os_VT_ACTIVATE (cast i Address)
  # console "event " event " key " key " buttons " buttons " " x_or_x0 " " y_or_y0 " " x1 " " y1 eol


method c lock_pointer locked
  oarg_rw ConsoleFramebuffer c ; arg CBool locked
  c locked := locked


method c close
  oarg_rw ConsoleFramebuffer c
method c close
  oarg_rw ConsoleFramebuffer c
  os_close c:handle
  if c:keyboard_handle>=0
    os_close c:keyboard_handle ; c keyboard_handle := undefined
  if c:mouse_handle>=0
    os_close c:mouse_handle ; c mouse_handle := undefined
  memory_free c:cursor_buffer ; c cursor_buffer := null


graphic_console_record "framebuffer" ConsoleFramebuffer


graphic_console_record "framebuffer" ConsoleFramebuffer