mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 12:23:24 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			830 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			830 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						||
    $Id$
 | 
						||
    This file is part of the Free Pascal run time library.
 | 
						||
    Copyright (c) 1999-2000 by Florian Klaempfl
 | 
						||
    member of the Free Pascal development team
 | 
						||
 | 
						||
    Video unit for linux
 | 
						||
 | 
						||
    See the file COPYING.FPC, included in this distribution,
 | 
						||
    for details about the copyright.
 | 
						||
 | 
						||
    This program is distributed in the hope that it will be useful,
 | 
						||
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						||
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | 
						||
 | 
						||
 **********************************************************************}
 | 
						||
unit Video;
 | 
						||
 | 
						||
interface
 | 
						||
 | 
						||
{$i videoh.inc}
 | 
						||
 | 
						||
implementation
 | 
						||
 | 
						||
uses
 | 
						||
  Unix, Strings, TermInfo;
 | 
						||
 | 
						||
{$i video.inc}
 | 
						||
 | 
						||
var
 | 
						||
  LastCursorType : byte;
 | 
						||
  TtyFd: Longint;
 | 
						||
  Console: Boolean;
 | 
						||
  OldVideoBuf: PVideoBuf;
 | 
						||
{$ifdef logging}
 | 
						||
  f: file;
 | 
						||
 | 
						||
const
 | 
						||
  logstart: string = '';
 | 
						||
  nl: char = #10;
 | 
						||
  logend: string = #10#10;
 | 
						||
{$endif logging}
 | 
						||
{$ASMMODE ATT}
 | 
						||
const
 | 
						||
  can_delete_term : boolean = false;
 | 
						||
  ACSIn : string = '';
 | 
						||
  ACSOut : string = '';
 | 
						||
  InACS : boolean =false;
 | 
						||
 | 
						||
function IsACS(var ch,ACSchar : char): boolean;
 | 
						||
begin
 | 
						||
  IsACS:=false;
 | 
						||
  case ch of
 | 
						||
    #24, #30: {}
 | 
						||
      ch:='^';
 | 
						||
    #25, #31: {}
 | 
						||
      ch:='v';
 | 
						||
    #26, #16: {Never introduce a ctrl-Z ... }
 | 
						||
      ch:='>';
 | 
						||
    {#27,needed in Escape sequences} #17: {}
 | 
						||
      ch:='<';
 | 
						||
    #176, #177, #178: {°±²}
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='a';
 | 
						||
      end;
 | 
						||
    #180, #181, #182, #185: {´µ¶¹}
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='u';
 | 
						||
      end;
 | 
						||
    #183, #184, #187, #191: {·¸»¿}
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='k';
 | 
						||
      end;
 | 
						||
    #188, #189, #190, #217: {¼½¾Ù}
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='j';
 | 
						||
      end;
 | 
						||
    #192, #200, #211, #212: {ÀÈÓÔ}
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='m';
 | 
						||
      end;
 | 
						||
    #193, #202, #207, #208: {ÁÊÏÐ}
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='v';
 | 
						||
      end;
 | 
						||
    #194, #203, #209, #210: {ÂËÑÒ}
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='w';
 | 
						||
      end;
 | 
						||
    #195, #198, #199, #204: {ÃÆÇÌ}
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='t';
 | 
						||
      end;
 | 
						||
    #196, #205: {ÄÍ}
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='q';
 | 
						||
      end;
 | 
						||
    #179, #186: {³º}
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='x';
 | 
						||
      end;
 | 
						||
    #197, #206, #215, #216: {ÅÎר}
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='n';
 | 
						||
      end;
 | 
						||
    #201, #213, #214, #218: {ÉÕÖÚ}
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='l';
 | 
						||
      end;
 | 
						||
    #254: { þ }
 | 
						||
      begin
 | 
						||
        ch:='*';
 | 
						||
      end;
 | 
						||
    { Shadows for Buttons }
 | 
						||
    #220: { Ü }
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='a';
 | 
						||
      end;
 | 
						||
    #223: { ß }
 | 
						||
      begin
 | 
						||
        IsACS:=true;
 | 
						||
        ACSChar:='a';
 | 
						||
      end;
 | 
						||
  end;
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
function SendEscapeSeqNdx(Ndx: Word) : boolean;
 | 
						||
var
 | 
						||
  P,pdelay: PChar;
 | 
						||
begin
 | 
						||
  SendEscapeSeqNdx:=false;
 | 
						||
  if not assigned(cur_term_Strings) then
 | 
						||
    exit{RunError(219)};
 | 
						||
  P:=cur_term_Strings^[Ndx];
 | 
						||
  if assigned(p) then
 | 
						||
   begin { Do not transmit the delays }
 | 
						||
     pdelay:=strpos(p,'$<');
 | 
						||
     if assigned(pdelay) then
 | 
						||
       pdelay^:=#0;
 | 
						||
     fdWrite(TTYFd, P^, StrLen(P));
 | 
						||
     SendEscapeSeqNdx:=true;
 | 
						||
     if assigned(pdelay) then
 | 
						||
       pdelay^:='$';
 | 
						||
   end;
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
procedure SendEscapeSeq(const S: String);
 | 
						||
begin
 | 
						||
  fdWrite(TTYFd, S[1], Length(S));
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
Function IntStr(l:longint):string;
 | 
						||
var
 | 
						||
  s : string;
 | 
						||
begin
 | 
						||
  Str(l,s);
 | 
						||
  IntStr:=s;
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
Function XY2Ansi(x,y,ox,oy:longint):String;
 | 
						||
{
 | 
						||
  Returns a string with the escape sequences to go to X,Y on the screen
 | 
						||
}
 | 
						||
Begin
 | 
						||
  if y=oy then
 | 
						||
   begin
 | 
						||
     if x=ox then
 | 
						||
      begin
 | 
						||
        XY2Ansi:='';
 | 
						||
        exit;
 | 
						||
      end;
 | 
						||
     if x=1 then
 | 
						||
      begin
 | 
						||
        XY2Ansi:=#13;
 | 
						||
        exit;
 | 
						||
      end;
 | 
						||
     if x>ox then
 | 
						||
      begin
 | 
						||
        XY2Ansi:=#27'['+IntStr(x-ox)+'C';
 | 
						||
        exit;
 | 
						||
      end
 | 
						||
     else
 | 
						||
      begin
 | 
						||
        XY2Ansi:=#27'['+IntStr(ox-x)+'D';
 | 
						||
        exit;
 | 
						||
      end;
 | 
						||
   end;
 | 
						||
  if x=ox then
 | 
						||
   begin
 | 
						||
     if y>oy then
 | 
						||
      begin
 | 
						||
        XY2Ansi:=#27'['+IntStr(y-oy)+'B';
 | 
						||
        exit;
 | 
						||
      end
 | 
						||
     else
 | 
						||
      begin
 | 
						||
        XY2Ansi:=#27'['+IntStr(oy-y)+'A';
 | 
						||
        exit;
 | 
						||
      end;
 | 
						||
   end;
 | 
						||
  if (x=1) and (oy+1=y) then
 | 
						||
   XY2Ansi:=#13#10
 | 
						||
  else
 | 
						||
   XY2Ansi:=#27'['+IntStr(y)+';'+IntStr(x)+'H';
 | 
						||
End;
 | 
						||
 | 
						||
 | 
						||
 | 
						||
const
 | 
						||
  AnsiTbl : string[8]='04261537';
 | 
						||
Function Attr2Ansi(Attr,OAttr:longint):string;
 | 
						||
{
 | 
						||
  Convert Attr to an Ansi String, the Optimal code is calculate
 | 
						||
  with use of the old OAttr
 | 
						||
}
 | 
						||
var
 | 
						||
  hstr : string[16];
 | 
						||
  OFg,OBg,Fg,Bg : longint;
 | 
						||
 | 
						||
  procedure AddSep(ch:char);
 | 
						||
  begin
 | 
						||
    if length(hstr)>0 then
 | 
						||
     hstr:=hstr+';';
 | 
						||
    hstr:=hstr+ch;
 | 
						||
  end;
 | 
						||
 | 
						||
begin
 | 
						||
  if Attr=OAttr then
 | 
						||
   begin
 | 
						||
     Attr2Ansi:='';
 | 
						||
     exit;
 | 
						||
   end;
 | 
						||
  Hstr:='';
 | 
						||
  Fg:=Attr and $f;
 | 
						||
  Bg:=Attr shr 4;
 | 
						||
  OFg:=OAttr and $f;
 | 
						||
  OBg:=OAttr shr 4;
 | 
						||
  if (OFg<>7) or (Fg=7) or ((OFg>7) and (Fg<8)) or ((OBg>7) and (Bg<8)) then
 | 
						||
   begin
 | 
						||
     hstr:='0';
 | 
						||
     OFg:=7;
 | 
						||
     OBg:=0;
 | 
						||
   end;
 | 
						||
  if (Fg>7) and (OFg<8) then
 | 
						||
   begin
 | 
						||
     AddSep('1');
 | 
						||
     OFg:=OFg or 8;
 | 
						||
   end;
 | 
						||
  if (Bg and 8)<>(OBg and 8) then
 | 
						||
   begin
 | 
						||
     AddSep('5');
 | 
						||
     OBg:=OBg or 8;
 | 
						||
   end;
 | 
						||
  if (Fg<>OFg) then
 | 
						||
   begin
 | 
						||
     AddSep('3');
 | 
						||
     hstr:=hstr+AnsiTbl[(Fg and 7)+1];
 | 
						||
   end;
 | 
						||
  if (Bg<>OBg) then
 | 
						||
   begin
 | 
						||
     AddSep('4');
 | 
						||
     hstr:=hstr+AnsiTbl[(Bg and 7)+1];
 | 
						||
   end;
 | 
						||
  if hstr='0' then
 | 
						||
   hstr:='';
 | 
						||
  Attr2Ansi:=#27'['+hstr+'m';
 | 
						||
end;
 | 
						||
 | 
						||
procedure TransformUsingACS(var st : string);
 | 
						||
var
 | 
						||
  res : string;
 | 
						||
  i : longint;
 | 
						||
  ch,ACSch : char;
 | 
						||
begin
 | 
						||
  res:='';
 | 
						||
  for i:=1 to length(st) do
 | 
						||
    begin
 | 
						||
      ch:=st[i];
 | 
						||
      if IsACS(ch,ACSch) then
 | 
						||
        begin
 | 
						||
          if not InACS then
 | 
						||
            begin
 | 
						||
              res:=res+ACSIn;
 | 
						||
              InACS:=true;
 | 
						||
            end;
 | 
						||
          res:=res+ACSch;
 | 
						||
        end
 | 
						||
      else
 | 
						||
        begin
 | 
						||
          if InACS then
 | 
						||
            begin
 | 
						||
              res:=res+ACSOut;
 | 
						||
              InACS:=false;
 | 
						||
            end;
 | 
						||
          res:=res+ch;
 | 
						||
        end;
 | 
						||
    end;
 | 
						||
  st:=res;
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
procedure UpdateTTY(Force:boolean);
 | 
						||
type
 | 
						||
  tchattr=packed record
 | 
						||
    ch : char;
 | 
						||
    attr : byte;
 | 
						||
  end;
 | 
						||
var
 | 
						||
  outbuf   : array[0..1023+255] of char;
 | 
						||
  chattr   : tchattr;
 | 
						||
  skipped  : boolean;
 | 
						||
  outptr,
 | 
						||
  spaces,
 | 
						||
  eol,
 | 
						||
  x,y,
 | 
						||
  LastX,LastY,
 | 
						||
  SpaceAttr,
 | 
						||
  LastAttr : longint;
 | 
						||
  p,pold   : pvideocell;
 | 
						||
 | 
						||
  procedure outdata(hstr:string);
 | 
						||
  begin
 | 
						||
    while (eol>0) do
 | 
						||
     begin
 | 
						||
       hstr:=#13#10+hstr;
 | 
						||
       dec(eol);
 | 
						||
     end;
 | 
						||
    if NoExtendedFrame and (ACSIn<>'') and (ACSOut<>'') then
 | 
						||
      TransformUsingACS(Hstr);
 | 
						||
    move(hstr[1],outbuf[outptr],length(hstr));
 | 
						||
    inc(outptr,length(hstr));
 | 
						||
    if outptr>=1024 then
 | 
						||
     begin
 | 
						||
{$ifdef logging}
 | 
						||
       blockwrite(f,logstart[1],length(logstart));
 | 
						||
       blockwrite(f,nl,1);
 | 
						||
       blockwrite(f,outptr,sizeof(outptr));
 | 
						||
       blockwrite(f,nl,1);
 | 
						||
       blockwrite(f,outbuf,outptr);
 | 
						||
       blockwrite(f,nl,1);
 | 
						||
{$endif logging}
 | 
						||
       fdWrite(TTYFd,outbuf,outptr);
 | 
						||
       outptr:=0;
 | 
						||
     end;
 | 
						||
  end;
 | 
						||
 | 
						||
  procedure OutClr(c:byte);
 | 
						||
  begin
 | 
						||
    if c=LastAttr then
 | 
						||
     exit;
 | 
						||
    OutData(Attr2Ansi(c,LastAttr));
 | 
						||
    LastAttr:=c;
 | 
						||
  end;
 | 
						||
 | 
						||
  procedure OutSpaces;
 | 
						||
  begin
 | 
						||
    if (Spaces=0) then
 | 
						||
     exit;
 | 
						||
    OutClr(SpaceAttr);
 | 
						||
    OutData(Space(Spaces));
 | 
						||
    LastX:=x;
 | 
						||
    LastY:=y;
 | 
						||
    Spaces:=0;
 | 
						||
  end;
 | 
						||
 | 
						||
begin
 | 
						||
  OutPtr:=0;
 | 
						||
  Eol:=0;
 | 
						||
  skipped:=true;
 | 
						||
  p:=PVideoCell(VideoBuf);
 | 
						||
  pold:=PVideoCell(OldVideoBuf);
 | 
						||
{ init Attr and X,Y }
 | 
						||
  SendEscapeSeq(#27'[m'{#27'[H'});
 | 
						||
  LastAttr:=7;
 | 
						||
  LastX:=-1;
 | 
						||
  LastY:=-1;
 | 
						||
  for y:=1 to ScreenHeight do
 | 
						||
   begin
 | 
						||
     SpaceAttr:=0;
 | 
						||
     Spaces:=0;
 | 
						||
     for x:=1 to ScreenWidth do
 | 
						||
      begin
 | 
						||
        if (not force) and (p^=pold^) then
 | 
						||
         begin
 | 
						||
           if (Spaces>0) then
 | 
						||
            OutSpaces;
 | 
						||
           skipped:=true;
 | 
						||
         end
 | 
						||
        else
 | 
						||
         begin
 | 
						||
           if skipped then
 | 
						||
            begin
 | 
						||
              OutData(XY2Ansi(x,y,LastX,LastY));
 | 
						||
              LastX:=x;
 | 
						||
              LastY:=y;
 | 
						||
              skipped:=false;
 | 
						||
            end;
 | 
						||
           chattr:=tchattr(p^);
 | 
						||
           if chattr.ch in [#0,#255] then
 | 
						||
            chattr.ch:=' ';
 | 
						||
           if chattr.ch=' ' then
 | 
						||
            begin
 | 
						||
              if Spaces=0 then
 | 
						||
               SpaceAttr:=chattr.Attr;
 | 
						||
              if (chattr.attr and $f0)=(spaceattr and $f0) then
 | 
						||
               chattr.Attr:=SpaceAttr
 | 
						||
              else
 | 
						||
               begin
 | 
						||
                 OutSpaces;
 | 
						||
                 SpaceAttr:=chattr.Attr;
 | 
						||
               end;
 | 
						||
              inc(Spaces);
 | 
						||
            end
 | 
						||
           else
 | 
						||
            begin
 | 
						||
              if (Spaces>0) then
 | 
						||
               OutSpaces;
 | 
						||
              if ord(chattr.ch)<32 then
 | 
						||
                begin
 | 
						||
                  Chattr.Attr:= $ff xor Chattr.Attr;
 | 
						||
                  ChAttr.ch:= chr(ord(chattr.ch)+ord('A')-1);
 | 
						||
                end;
 | 
						||
              if LastAttr<>chattr.Attr then
 | 
						||
               OutClr(chattr.Attr);
 | 
						||
              OutData(chattr.ch);
 | 
						||
              LastX:=x+1;
 | 
						||
              LastY:=y;
 | 
						||
            end;
 | 
						||
           p^:=tvideocell(chattr);
 | 
						||
         end;
 | 
						||
        inc(p);
 | 
						||
        inc(pold);
 | 
						||
      end;
 | 
						||
     if (Spaces>0) then
 | 
						||
      OutSpaces;
 | 
						||
     if force then
 | 
						||
      inc(eol);
 | 
						||
   end;
 | 
						||
  eol:=0;
 | 
						||
  OutData(XY2Ansi(CursorX,CursorY,LastX,LastY));
 | 
						||
{$ifdef logging}
 | 
						||
  blockwrite(f,logstart[1],length(logstart));
 | 
						||
  blockwrite(f,nl,1);
 | 
						||
  blockwrite(f,outptr,sizeof(outptr));
 | 
						||
  blockwrite(f,nl,1);
 | 
						||
  blockwrite(f,outbuf,outptr);
 | 
						||
  blockwrite(f,nl,1);
 | 
						||
{$endif logging}
 | 
						||
  fdWrite(TTYFd,outbuf,outptr);
 | 
						||
  if InACS then
 | 
						||
    SendEscapeSeqNdx(exit_alt_charset_mode);
 | 
						||
end;
 | 
						||
 | 
						||
var
 | 
						||
  InitialVideoTio, preInitVideoTio, postInitVideoTio: Unix.termios;
 | 
						||
  inputRaw, outputRaw: boolean;
 | 
						||
 | 
						||
procedure saveRawSettings(const tio: Unix.termios);
 | 
						||
Begin
 | 
						||
  with tio do
 | 
						||
   begin
 | 
						||
     inputRaw :=
 | 
						||
       ((c_iflag and (IGNBRK or BRKINT or PARMRK or ISTRIP or
 | 
						||
                                INLCR or IGNCR or ICRNL or IXON)) = 0) and
 | 
						||
       ((c_lflag and (ECHO or ECHONL or ICANON or ISIG or IEXTEN)) = 0);
 | 
						||
     outPutRaw :=
 | 
						||
       ((c_oflag and OPOST) = 0) and
 | 
						||
       ((c_cflag and (CSIZE or PARENB)) = 0) and
 | 
						||
       ((c_cflag and CS8) <> 0);
 | 
						||
   end;
 | 
						||
end;
 | 
						||
 | 
						||
procedure restoreRawSettings(tio: Unix.termios);
 | 
						||
begin
 | 
						||
  with tio do
 | 
						||
    begin
 | 
						||
      if inputRaw then
 | 
						||
        begin
 | 
						||
          c_iflag := c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
 | 
						||
            INLCR or IGNCR or ICRNL or IXON));
 | 
						||
          c_lflag := c_lflag and
 | 
						||
            (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
 | 
						||
       end;
 | 
						||
     if outPutRaw then
 | 
						||
       begin
 | 
						||
         c_oflag := c_oflag and not(OPOST);
 | 
						||
         c_cflag := c_cflag and not(CSIZE or PARENB) or CS8;
 | 
						||
       end;
 | 
						||
   end;
 | 
						||
  TCSetAttr(1,TCSANOW,tio);
 | 
						||
end;
 | 
						||
 | 
						||
procedure TargetEntry;
 | 
						||
begin
 | 
						||
  TCGetAttr(1,InitialVideoTio);
 | 
						||
end;
 | 
						||
 | 
						||
procedure TargetExit;
 | 
						||
begin
 | 
						||
  TCSetAttr(1,TCSANOW,InitialVideoTio);
 | 
						||
end;
 | 
						||
 | 
						||
procedure prepareInitVideo;
 | 
						||
begin
 | 
						||
  TCGetAttr(1,preInitVideoTio);
 | 
						||
  saveRawSettings(preInitVideoTio);
 | 
						||
end;
 | 
						||
 | 
						||
procedure videoInitDone;
 | 
						||
begin
 | 
						||
  TCGetAttr(1,postInitVideoTio);
 | 
						||
  restoreRawSettings(postInitVideoTio);
 | 
						||
end;
 | 
						||
 | 
						||
procedure prepareDoneVideo;
 | 
						||
var
 | 
						||
  tio: Unix.termios;
 | 
						||
begin
 | 
						||
  TCGetAttr(1,tio);
 | 
						||
  saveRawSettings(tio);
 | 
						||
  TCSetAttr(1,TCSANOW,postInitVideoTio);
 | 
						||
end;
 | 
						||
 | 
						||
procedure doneVideoDone;
 | 
						||
begin
 | 
						||
  restoreRawSettings(preInitVideoTio);
 | 
						||
end;
 | 
						||
 | 
						||
procedure InitVideo;
 | 
						||
const
 | 
						||
  fontstr : string[3]=#27'(K';
 | 
						||
var
 | 
						||
  ThisTTY: String[30];
 | 
						||
  FName: String;
 | 
						||
  WS: packed record
 | 
						||
    ws_row, ws_col, ws_xpixel, ws_ypixel: Word;
 | 
						||
  end;
 | 
						||
  Err: Longint;
 | 
						||
  prev_term : TerminalCommon_ptr1;
 | 
						||
begin
 | 
						||
{$ifndef CPUI386}
 | 
						||
  LowAscii:=false;
 | 
						||
{$endif CPUI386}
 | 
						||
  if VideoBufSize<>0 then
 | 
						||
   begin
 | 
						||
     clearscreen;
 | 
						||
     if Console then
 | 
						||
      SetCursorPos(1,1)
 | 
						||
     else
 | 
						||
      begin
 | 
						||
        if not SendEscapeSeqNdx(cursor_home) then
 | 
						||
          SendEscapeSeq(#27'[H');
 | 
						||
      end;
 | 
						||
     exit;
 | 
						||
   end;
 | 
						||
  { check for tty }
 | 
						||
  ThisTTY:=TTYName(stdinputhandle);
 | 
						||
  if IsATTY(stdinputhandle) then
 | 
						||
   begin
 | 
						||
     { save current terminal characteristics and remove rawness }
 | 
						||
     prepareInitVideo;
 | 
						||
     { write code to set a correct font }
 | 
						||
     fdWrite(stdoutputhandle,fontstr[1],length(fontstr));
 | 
						||
     { running on a tty, find out whether locally or remotely }
 | 
						||
     if (Copy(ThisTTY, 1, 8) = '/dev/tty') and
 | 
						||
        (ThisTTY[9] >= '0') and (ThisTTY[9] <= '9') then
 | 
						||
      begin
 | 
						||
        { running on the console }
 | 
						||
        FName:='/dev/vcsa' + ThisTTY[9];
 | 
						||
        TTYFd:=fdOpen(FName, Octal(666), Open_RdWr); { open console }
 | 
						||
      end
 | 
						||
     else
 | 
						||
      TTYFd:=-1;
 | 
						||
     if TTYFd<>-1 then
 | 
						||
      Console:=true
 | 
						||
     else
 | 
						||
      begin
 | 
						||
        { running on a remote terminal, no error with /dev/vcsa }
 | 
						||
        Console:=False;
 | 
						||
        LowAscii:=false;
 | 
						||
        TTYFd:=stdoutputhandle;
 | 
						||
      end;
 | 
						||
     ioctl(stdinputhandle, TIOCGWINSZ, @WS);
 | 
						||
     if WS.ws_Col=0 then
 | 
						||
      WS.ws_Col:=80;
 | 
						||
     if WS.ws_Row=0 then
 | 
						||
      WS.ws_Row:=25;
 | 
						||
     ScreenWidth:=WS.ws_Col;
 | 
						||
     { TDrawBuffer only has FVMaxWidth elements
 | 
						||
       larger values lead to crashes }
 | 
						||
     if ScreenWidth> FVMaxWidth then
 | 
						||
       ScreenWidth:=FVMaxWidth;
 | 
						||
     ScreenHeight:=WS.ws_Row;
 | 
						||
     CursorX:=1;
 | 
						||
     CursorY:=1;
 | 
						||
     ScreenColor:=True;
 | 
						||
     { allocate pmode memory buffer }
 | 
						||
     VideoBufSize:=ScreenWidth*ScreenHeight*2;
 | 
						||
     GetMem(VideoBuf,VideoBufSize);
 | 
						||
     GetMem(OldVideoBuf,VideoBufSize);
 | 
						||
     { Start with a clear screen }
 | 
						||
     if not Console then
 | 
						||
      begin
 | 
						||
        prev_term:=cur_term;
 | 
						||
        setupterm(nil, stdoutputhandle, err);
 | 
						||
        can_delete_term:=assigned(prev_term) and (prev_term<>cur_term);
 | 
						||
        SendEscapeSeqNdx(cursor_home);
 | 
						||
        SendEscapeSeqNdx(cursor_normal);
 | 
						||
        SendEscapeSeqNdx(cursor_visible);
 | 
						||
        SendEscapeSeqNdx(enter_ca_mode);
 | 
						||
        SetCursorType(crUnderLine);
 | 
						||
      end
 | 
						||
     else if not assigned(cur_term) then
 | 
						||
       begin
 | 
						||
         setupterm(nil, stdoutputhandle, err);
 | 
						||
         can_delete_term:=false;
 | 
						||
       end;
 | 
						||
     if assigned(cur_term_Strings) then
 | 
						||
       begin
 | 
						||
         ACSIn:=StrPas(cur_term_Strings^[enter_alt_charset_mode]);
 | 
						||
         ACSOut:=StrPas(cur_term_Strings^[exit_alt_charset_mode]);
 | 
						||
         if (ACSIn<>'') and (ACSOut<>'') then
 | 
						||
           SendEscapeSeqNdx(ena_acs);
 | 
						||
         if pos('$<',ACSIn)>0 then
 | 
						||
           ACSIn:=Copy(ACSIn,1,Pos('$<',ACSIn)-1);
 | 
						||
         if pos('$<',ACSOut)>0 then
 | 
						||
           ACSOut:=Copy(ACSOut,1,Pos('$<',ACSOut)-1);
 | 
						||
       end
 | 
						||
     else
 | 
						||
       begin
 | 
						||
         ACSIn:='';
 | 
						||
         ACSOut:='';
 | 
						||
       end;
 | 
						||
     ClearScreen;
 | 
						||
{$ifdef logging}
 | 
						||
     assign(f,'video.log');
 | 
						||
     rewrite(f,1);
 | 
						||
{$endif logging}
 | 
						||
     { save new terminal characteristics and possible restore rawness }
 | 
						||
     videoInitDone;
 | 
						||
   end
 | 
						||
  else
 | 
						||
   ErrorCode:=errVioInit; { not a TTY }
 | 
						||
end;
 | 
						||
 | 
						||
procedure DoneVideo;
 | 
						||
begin
 | 
						||
  if VideoBufSize=0 then
 | 
						||
   exit;
 | 
						||
  prepareDoneVideo;
 | 
						||
  ClearScreen;
 | 
						||
  if Console then
 | 
						||
   SetCursorPos(1,1)
 | 
						||
  else
 | 
						||
   begin
 | 
						||
     SendEscapeSeqNdx(exit_ca_mode);
 | 
						||
     SendEscapeSeqNdx(cursor_home);
 | 
						||
     SendEscapeSeqNdx(cursor_normal);
 | 
						||
     SendEscapeSeqNdx(cursor_visible);
 | 
						||
     SetCursorType(crUnderLine);
 | 
						||
     SendEscapeSeq(#27'[H');
 | 
						||
   end;
 | 
						||
  FreeMem(VideoBuf,VideoBufSize);
 | 
						||
  FreeMem(OldVideoBuf,VideoBufSize);
 | 
						||
  VideoBufSize:=0;
 | 
						||
  ACSIn:='';
 | 
						||
  ACSOut:='';
 | 
						||
  doneVideoDone;
 | 
						||
  if can_delete_term then
 | 
						||
    begin
 | 
						||
      del_curterm(cur_term);
 | 
						||
      can_delete_term:=false;
 | 
						||
    end;
 | 
						||
{$ifdef logging}
 | 
						||
  close(f);
 | 
						||
{$endif logging}
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
procedure ClearScreen;
 | 
						||
begin
 | 
						||
  FillWord(VideoBuf^,VideoBufSize shr 1,$0720);
 | 
						||
  if Console then
 | 
						||
   UpdateScreen(true)
 | 
						||
  else
 | 
						||
   begin
 | 
						||
     SendEscapeSeq(#27'[0m');
 | 
						||
     SendEscapeSeqNdx(clear_screen);
 | 
						||
   end;
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
procedure UpdateScreen(Force: Boolean);
 | 
						||
var
 | 
						||
  DoUpdate : boolean;
 | 
						||
begin
 | 
						||
  if LockUpdateScreen<>0 then
 | 
						||
   exit;
 | 
						||
  if not force then
 | 
						||
   begin
 | 
						||
{$ifdef i386}
 | 
						||
     asm
 | 
						||
          movl    VideoBuf,%esi
 | 
						||
          movl    OldVideoBuf,%edi
 | 
						||
          movl    VideoBufSize,%ecx
 | 
						||
          shrl    $2,%ecx
 | 
						||
          repe
 | 
						||
          cmpsl
 | 
						||
          setne   DoUpdate
 | 
						||
     end;
 | 
						||
{$endif i386}
 | 
						||
   end
 | 
						||
  else
 | 
						||
   DoUpdate:=true;
 | 
						||
  if not DoUpdate then
 | 
						||
   exit;
 | 
						||
  if Console then
 | 
						||
   begin
 | 
						||
     fdSeek(TTYFd, 4, Seek_Set);
 | 
						||
     fdWrite(TTYFd, VideoBuf^,VideoBufSize);
 | 
						||
   end
 | 
						||
  else
 | 
						||
   begin
 | 
						||
     UpdateTTY(force);
 | 
						||
   end;
 | 
						||
  Move(VideoBuf^, OldVideoBuf^, VideoBufSize);
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
function GetCapabilities: Word;
 | 
						||
begin
 | 
						||
{ about cpColor... we should check the terminfo database... }
 | 
						||
  GetCapabilities:=cpUnderLine + cpBlink + cpColor;
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
procedure SetCursorPos(NewCursorX, NewCursorY: Word);
 | 
						||
var
 | 
						||
  Pos : array [1..2] of Byte;
 | 
						||
begin
 | 
						||
  if Console then
 | 
						||
   begin
 | 
						||
     fdSeek(TTYFd, 2, Seek_Set);
 | 
						||
     Pos[1]:=NewCursorX;
 | 
						||
     Pos[2]:=NewCursorY;
 | 
						||
     fdWrite(TTYFd, Pos, 2);
 | 
						||
   end
 | 
						||
  else
 | 
						||
   begin
 | 
						||
     { newcursorx,y is 0 based ! }
 | 
						||
     SendEscapeSeq(XY2Ansi(NewCursorX+1,NewCursorY+1,0,0));
 | 
						||
   end;
 | 
						||
  CursorX:=NewCursorX+1;
 | 
						||
  CursorY:=NewCursorY+1;
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
function GetCursorType: Word;
 | 
						||
begin
 | 
						||
  GetCursorType:=LastCursorType;
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
procedure SetCursorType(NewType: Word);
 | 
						||
begin
 | 
						||
  LastCursorType:=NewType;
 | 
						||
  case NewType of
 | 
						||
   crBlock :
 | 
						||
     Begin
 | 
						||
       If not SendEscapeSeqNdx(cursor_visible) then
 | 
						||
         SendEscapeSeq(#27'[?17;0;64c');
 | 
						||
     End;
 | 
						||
   crHidden :
 | 
						||
     Begin
 | 
						||
       If not SendEscapeSeqNdx(cursor_invisible) then
 | 
						||
         SendEscapeSeq(#27'[?1c');
 | 
						||
     End;
 | 
						||
  else
 | 
						||
    begin
 | 
						||
      If not SendEscapeSeqNdx(cursor_normal) then
 | 
						||
        SendEscapeSeq(#27'[?2c');
 | 
						||
    end;
 | 
						||
  end;
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
function DefaultVideoModeSelector(const VideoMode: TVideoMode; Params: Longint): Boolean;
 | 
						||
begin
 | 
						||
  DefaultVideoModeSelector:=false;
 | 
						||
end;
 | 
						||
 | 
						||
 | 
						||
procedure RegisterVideoModes;
 | 
						||
begin
 | 
						||
end;
 | 
						||
 | 
						||
initialization
 | 
						||
  RegisterVideoModes;
 | 
						||
 | 
						||
finalization
 | 
						||
  UnRegisterVideoModes;
 | 
						||
end.
 | 
						||
{
 | 
						||
  $Log$
 | 
						||
  Revision 1.2  2001-01-21 20:21:41  marco
 | 
						||
   * Rename fest II. Rtl OK
 | 
						||
 | 
						||
  Revision 1.1  2001/01/13 11:03:58  peter
 | 
						||
    * API 2 RTL commit
 | 
						||
 | 
						||
}
 | 
						||
 |