{ $Id$ This file is part of the Free Pascal Integrated Development Environment Copyright (c) 1998 by Berczi Gabor User screen support routines 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. **********************************************************************} {$i globdir.inc} unit FPUsrScr; interface uses {$ifdef win32} windows, {$endif win32} video,Objects; type PScreen = ^TScreen; TScreen = object(TObject) function GetWidth: integer; virtual; function GetHeight: integer; virtual; procedure GetLine(Line: integer; var Text, Attr: string); virtual; procedure GetCursorPos(var P: TPoint); virtual; procedure Capture; virtual; procedure SwitchTo; virtual; procedure SwitchBack; virtual; end; {$ifdef DOS} TDOSVideoInfo = record Mode : word; ScreenSize: word; Page : byte; Rows,Cols : integer; CurPos : TPoint; CurShapeT : integer; CurShapeB : integer; StateSize : word; StateBuf : pointer; end; PDOSScreen = ^TDOSScreen; TDOSScreen = object(TScreen) constructor Init; destructor Done; virtual; public function GetWidth: integer; virtual; function GetHeight: integer; virtual; procedure GetLine(Line: integer; var Text, Attr: string); virtual; procedure GetCursorPos(var P: TPoint); virtual; procedure Capture; virtual; procedure SwitchTo; virtual; procedure SwitchBack; virtual; private VideoInfo : TDOSVideoInfo; VBufferSize : longint; VIDEBufferSize : longint; VBuffer : PByteArray; VIDEBuffer : PByteArray; TM : TDOSVideoInfo; function GetLineStartOfs(Line: integer): word; procedure GetBuffer(Size: word); procedure FreeBuffer; procedure GetVideoMode(var MI: TDOSVideoInfo); procedure SetVideoMode(MI: TDOSVideoInfo); end; {$endif} {$ifdef Unix} PLinuxScreen = ^TLinuxScreen; TLinuxScreen = object(TScreen) constructor Init; destructor Done; virtual; public function GetWidth: integer; virtual; function GetHeight: integer; virtual; procedure GetLine(Line: integer; var Text, Attr: string); virtual; procedure GetCursorPos(var P: TPoint); virtual; procedure Capture; virtual; procedure SwitchTo; virtual; procedure SwitchBack; virtual; private IDE_screen: pvideobuf; IDE_size : longint; end; {$endif} {$ifdef win32} PWin32Screen = ^TWin32Screen; TWin32Screen = object(TScreen) constructor Init; destructor Done; virtual; public function GetWidth: integer; virtual; function GetHeight: integer; virtual; procedure GetLine(Line: integer; var Text, Attr: string); virtual; procedure GetCursorPos(var P: TPoint); virtual; procedure Capture; virtual; procedure SwitchTo; virtual; procedure SwitchBack; virtual; private DosScreenBufferHandle, IDEScreenBufferHandle : THandle; IDEActive : boolean; procedure BufferCopy(src,dest : THandle); end; {$endif} procedure InitUserScreen; procedure DoneUserScreen; const UserScreen : PScreen = nil; implementation uses Dos (* {$ifdef TP} {$ifdef DPMI} ,WinAPI {$endif} {$endif}*) {$ifdef FPC} {$ifdef GO32V2} ,Go32 {$endif} {$endif} {$ifdef VESA} ,VESA {$endif} ; function TScreen.GetWidth: integer; begin Getwidth:=0; Abstract; end; function TScreen.GetHeight: integer; begin Getheight:=0; Abstract; end; procedure TScreen.GetLine(Line: integer; var Text, Attr: string); begin Abstract; end; procedure TScreen.GetCursorPos(var P: TPoint); begin Abstract; end; procedure TScreen.Capture; begin Abstract; end; procedure TScreen.SwitchTo; begin Abstract; end; procedure TScreen.SwitchBack; begin Abstract; end; {**************************************************************************** TDOSScreen ****************************************************************************} {$ifdef DOS} constructor TDOSScreen.Init; begin inherited Init; Capture; end; destructor TDOSScreen.Done; begin inherited Done; FreeBuffer; end; function TDOSScreen.GetWidth: integer; begin GetWidth:=VideoInfo.Cols; end; function TDOSScreen.GetHeight: integer; begin GetHeight:=VideoInfo.Rows; end; procedure TDOSScreen.GetLine(Line: integer; var Text, Attr: string); var X: integer; W: word; begin Text:=''; Attr:=''; if LineTM.ScreenSize) then begin if assigned(VIDEBuffer) then FreeMem(VIDEBuffer,VIDEBufferSize); GetMem(VIDEBuffer,TM.ScreenSize); VIDEBufferSize:=TM.ScreenSize; end; {$ifdef FPC} DosmemGet(VSeg,SOfs,VIDEBuffer^,TM.ScreenSize); {$else} Move(ptr(VSeg,SOfs)^,VIDEBuffer^,TM.ScreenSize); {$endif} SetVideoMode(VideoInfo); if VideoInfo.Mode=7 then VSeg:=SegB000 else VSeg:=SegB800; SOfs:=MemW[Seg0040:$4e]; {$ifdef FPC} DosmemPut(VSeg,SOfs,VBuffer^,VideoInfo.ScreenSize); {$else} Move(VBuffer^,ptr(VSeg,SOfs)^,VideoInfo.ScreenSize); {$endif} end; procedure TDOSScreen.SwitchBack; var VSeg,SOfs: word; begin Capture; SetVideoMode(TM); if VideoInfo.Mode=7 then VSeg:=SegB000 else VSeg:=SegB800; SOfs:=MemW[Seg0040:$4e]; if assigned(VIDEBuffer) then {$ifdef FPC} DosmemPut(VSeg,SOfs,VIDEBuffer^,TM.ScreenSize); {$else} Move(VIDEBuffer^,ptr(VSeg,SOfs)^,TM.ScreenSize); {$endif} end; function TDOSScreen.GetLineStartOfs(Line: integer): word; begin GetLineStartOfs:=(VideoInfo.Cols*Line)*2; end; procedure TDOSScreen.GetBuffer(Size: word); begin if (VBuffer<>nil) and (VBufferSize=Size) then Exit; if VBuffer<>nil then FreeBuffer; VBufferSize:=Size; GetMem(VBuffer,VBufferSize); end; procedure TDOSScreen.FreeBuffer; begin if (VBuffer<>nil) and (VBufferSize>0) then FreeMem(VBuffer,VBufferSize); VBuffer:=nil; end; procedure TDOSScreen.GetVideoMode(var MI: TDOSVideoInfo); var r: registers; {$ifdef TP} P: pointer; Sel: longint; (* {$I realintr.inc} *) {$endif} begin if (MI.StateSize>0) and (MI.StateBuf<>nil) then begin FreeMem(MI.StateBuf,MI.StateSize); MI.StateBuf:=nil; end; MI.ScreenSize:=MemW[Seg0040:$4c]; r.ah:=$0f; intr($10,r); MI.Mode:=r.al; MI.Page:=r.bh; MI.Cols:=r.ah; {$ifdef VESA} VESAGetMode(MI.Mode); {$endif} MI.Rows:=MI.ScreenSize div (MI.Cols*2); if MI.Rows=51 then MI.Rows:=50; r.ah:=$03; r.bh:=MI.Page; intr($10,r); with MI do begin CurPos.X:=r.dl; CurPos.Y:=r.dh; CurShapeT:=r.ch; CurShapeB:=r.cl; end; (* {$ifdef TP} { check VGA functions } MI.StateSize:=0; r.ah:=$1c; r.al:=0; r.cx:=7; intr($10,r); if (r.al=$1c) and ((r.flags and fCarry)=0) and (r.bx>0) then begin MI.StateSize:=r.bx; GetMem(MI.StateBuf,MI.StateSize); FillChar(MI.StateBuf^,MI.StateSize,0); P:=MI.StateBuf; {$ifdef DPMI} Sel:=GlobalDosAlloc(MI.StateSize); P:=Ptr(Sel shr 16,0); {$endif} r.ah:=$1c; r.al:=1; r.cx:=7; r.es:=PtrRec(P).Seg; r.bx:=PtrRec(P).Ofs; {$ifdef DPMI}realintr($10,r);{$else}intr($10,r);{$endif} {$ifdef DPMI} Move(Ptr(Sel and $ffff,0)^,MI.StateBuf^,MI.StateSize); GlobalDosFree(Sel and $ffff); {$endif} end; {$endif} *) end; procedure TDOSScreen.SetVideoMode(MI: TDOSVideoInfo); var r: registers; CM: TDOSVideoInfo; {$ifdef TP} P: pointer; Sel: longint; {$I realintr.inc} {$endif} begin FillChar(CM,sizeof(CM),0); GetVideoMode(CM); if (CM.Mode<>MI.Mode) or (CM.Cols<>MI.Cols) or (CM.Rows<>MI.Rows) then begin {$ifdef VESA} if MI.Mode>=$100 then VESASetMode(MI.Mode) else {$endif} begin r.ah:=$00; r.al:=MI.Mode; intr($10,r); end; if (MI.Mode=3) and (MI.Cols=80) and (MI.Rows=50) then begin r.ax:=$1112; r.bx:=$0; intr($10,r); end; end; r.ah:=$05; r.al:=MI.Page; intr($10,r); r.ah:=$02; r.bh:=MI.Page; r.dl:=MI.CurPos.X; r.dh:=MI.CurPos.Y; intr($10,r); r.ah:=$01; r.ch:=MI.CurShapeT; r.cl:=MI.CurShapeB; intr($10,r); (* {$ifdef TP} if (MI.StateSize>0) and (MI.StateBuf<>nil) then begin P:=MI.StateBuf; {$ifdef DPMI} Sel:=GlobalDosAlloc(MI.StateSize); Move(MI.StateBuf^,ptr(Sel and $ffff,0)^,MI.StateSize); P:=Ptr(Sel shr 16,0); {$endif} r.ah:=$1c; r.al:=2; r.cx:=7; r.es:=PtrRec(P).Seg; r.bx:=PtrRec(P).Ofs; {$ifdef DPMI}realintr($10,r);{$else}intr($10,r);{$endif} {$ifdef DPMI} GlobalDosFree(Sel and $ffff); {$endif} end; {$endif} *) end; {$endif} {**************************************************************************** TLinuxScreen ****************************************************************************} {$ifdef Unix} constructor TLinuxScreen.Init; begin inherited Init; IDE_screen := nil; end; destructor TLinuxScreen.Done; begin inherited Done; end; function TLinuxScreen.GetWidth: integer; begin GetWidth:=ScreenWidth; end; function TLinuxScreen.GetHeight: integer; begin GetHeight:=ScreenHeight; end; procedure TLinuxScreen.GetLine(Line: integer; var Text, Attr: string); begin Text:=''; Attr:=''; end; procedure TLinuxScreen.GetCursorPos(var P: TPoint); begin P.X:=0; P.Y:=0; end; procedure TLinuxScreen.Capture; begin if assigned(IDE_screen) then dispose(IDE_screen); getmem(IDE_screen,videobufsize); Ide_size:=videobufsize; move(videobuf^,IDE_screen^,videobufsize); end; procedure TLinuxScreen.SwitchTo; begin end; procedure TLinuxScreen.SwitchBack; begin if IDE_screen = nil then exit; move(IDE_screen^,videobuf^,videobufsize); freemem(IDE_screen,Ide_size); IDE_screen := nil; end; {$endif} {**************************************************************************** TWin32Screen ****************************************************************************} {$ifdef win32} constructor TWin32Screen.Init; var SecurityAttr : Security_attributes; BigWin : Coord; res : boolean; Error : dword; begin inherited Init; SecurityAttr.nLength:=SizeOf(Security_attributes); SecurityAttr.lpSecurityDescriptor:=nil; SecurityAttr.bInheritHandle:=false; DosScreenBufferHandle:=CreateConsoleScreenBuffer( GENERIC_READ or GENERIC_WRITE, 0,SecurityAttr, CONSOLE_TEXTMODE_BUFFER,nil); IDEScreenBufferHandle:=GetStdHandle(STD_OUTPUT_HANDLE); {$ifdef win32bigwin} BigWin.X:=80; BigWin.Y:=50; SetConsoleScreenBufferSize(DosScreenBufferHandle,BigWin); SetConsoleScreenBufferSize(IDEScreenBufferHandle,BigWin); BigWin.X:=80; BigWin.Y:=50; { Try to allow to store more info } res:=SetConsoleScreenBufferSize(DosScreenBufferHandle,BigWin); if not res then error:=GetLastError; {$endif win32bigwin} Capture; SwitchBack; end; destructor TWin32Screen.Done; begin { copy the Dos buffer content into the original ScreenBuffer which remains the startup std_output_handle PM } BufferCopy(DosScreenBufferHandle,IDEScreenBufferHandle); SetConsoleActiveScreenBuffer(IDEScreenBufferHandle); SetStdHandle(Std_Output_Handle,IDEScreenBufferHandle); CloseHandle(DosScreenBufferHandle); inherited Done; end; function TWin32Screen.GetWidth: integer; var ConsoleScreenBufferInfo : Console_screen_buffer_info; begin GetConsoleScreenBufferInfo(DosScreenBufferHandle, @ConsoleScreenBufferInfo); GetWidth:=ConsoleScreenBufferInfo.dwSize.X; {GetWidth:=ScreenWidth;} end; function TWin32Screen.GetHeight: integer; var ConsoleScreenBufferInfo : Console_screen_buffer_info; begin GetConsoleScreenBufferInfo(DosScreenBufferHandle, @ConsoleScreenBufferInfo); GetHeight:=ConsoleScreenBufferInfo.dwSize.Y; {GetHeight:=ScreenHeight;} end; procedure TWin32Screen.GetLine(Line: integer; var Text, Attr: string); type CharInfoArray = Array [0..255] of Char_Info; var LineBuf : ^CharInfoArray; BufSize,BufCoord : Coord; i,LineSize : longint; WriteRegion : SMALL_RECT; begin GetMem(LineBuf,SizeOf(CharInfoArray)); LineSize:=ScreenWidth; If LineSize>256 then LineSize:=256; BufSize.X:=LineSize; BufSize.Y:=1; BufCoord.X:=0; BufCoord.Y:=0; with WriteRegion do begin Top :=Line; Left :=0; Bottom := Line+1; Right := LineSize-1; end; ReadConsoleOutput(DosScreenBufferHandle, PChar_info(LineBuf), BufSize, BufCoord, @WriteRegion); for i:=1 to LineSize do begin Text[i]:=LineBuf^[i-1].AsciiChar; Attr[i]:=char(byte(LineBuf^[i-1].Attributes)); end; FreeMem(LineBuf,SizeOf(CharInfoArray)); Text[0]:=char(byte(LineSize)); Attr[0]:=char(byte(LineSize)); end; procedure TWin32Screen.GetCursorPos(var P: TPoint); var ConsoleScreenBufferInfo : Console_screen_buffer_info; begin GetConsoleScreenBufferInfo(DosScreenBufferHandle, @ConsoleScreenBufferInfo); P.X:=ConsoleScreenBufferInfo.dwCursorPosition.X; P.Y:=ConsoleScreenBufferInfo.dwCursorPosition.Y; end; procedure TWin32Screen.BufferCopy(Src, Dest : THandle); type CharInfoArray = Array [0..256*255-1] of Char_Info; var LineBuf : ^CharInfoArray; BufSize,BufCoord : Coord; LineSize : longint; WriteRegion : SMALL_RECT; ConsoleScreenBufferInfo : Console_screen_buffer_info; begin GetMem(LineBuf,SizeOf(CharInfoArray)); LineSize:=ScreenWidth; If LineSize>256 then LineSize:=256; BufSize.X:=LineSize; BufSize.Y:=ScreenHeight; BufCoord.X:=0; BufCoord.Y:=0; with WriteRegion do begin Top :=0; Left :=0; Bottom := ScreenHeight-1; Right := LineSize-1; end; ReadConsoleOutput(Src, PChar_info(LineBuf), BufSize, BufCoord, @WriteRegion); WriteConsoleOutput(Dest, PChar_info(LineBuf), BufSize, BufCoord, @WriteRegion); FreeMem(LineBuf,SizeOf(CharInfoArray)); GetConsoleScreenBufferInfo(Src, @ConsoleScreenBufferInfo); SetConsoleCursorPosition(Dest, ConsoleScreenBufferInfo.dwCursorPosition); end; procedure TWin32Screen.Capture; begin BufferCopy(IDEScreenBufferHandle,DosScreenBufferHandle); end; procedure TWin32Screen.SwitchTo; begin SetConsoleActiveScreenBuffer(DosScreenBufferHandle); SetStdHandle(Std_Output_Handle,DosScreenBufferHandle); IDEActive:=false; end; procedure TWin32Screen.SwitchBack; begin SetConsoleActiveScreenBuffer(IDEScreenBufferHandle); SetStdHandle(Std_Output_Handle,IDEScreenBufferHandle); IDEActive:=true; end; {$endif} {**************************************************************************** Initialize ****************************************************************************} procedure InitUserScreen; begin {$ifdef DOS} UserScreen:=New(PDOSScreen, Init); {$else} {$ifdef Unix} UserScreen:=New(PLinuxScreen, Init); {$else} {$ifdef Win32} UserScreen:=New(PWin32Screen, Init); {$else} UserScreen:=New(PScreen, Init); {$endif Win32} {$endif Unix} {$endif Dos} end; procedure DoneUserScreen; begin if UserScreen<>nil then begin UserScreen^.SwitchTo; Dispose(UserScreen, Done); UserScreen:=nil; end; end; end. { $Log$ Revision 1.6 2000-11-15 00:14:10 pierre new merge Revision 1.1.2.4 2000/11/14 09:23:56 marco * Second batch Revision 1.5 2000/10/31 22:35:55 pierre * New big merge from fixes branch Revision 1.1.2.3 2000/10/10 21:24:56 pierre * avoid writing past IDE_screen buffer length Revision 1.4 2000/09/18 16:42:56 jonas * for some reason, tlinuxscreen.switchto() contained some saving code while it should've been empty (like in the fixes branch) Revision 1.3 2000/08/22 09:41:40 pierre * first big merge from fixes branch Revision 1.2 2000/08/21 10:57:01 jonas * IDE screen saving/restoring implemented for Linux (merged from fixes branch) Revision 1.1.2.2 2000/08/21 12:10:19 jonas * fixed errors in my previous commit, it now works properly Revision 1.1.2.1 2000/08/21 10:51:13 jonas * IDE screen saving/restoring implemented for Linux Revision 1.1 2000/07/13 09:48:36 michael + Initial import }