- Implemented double buffering for a console windows. Currently the second buffer

is a memory bitmap. All screen buffer updates does also write to the bitmap and
  the screen is updated by invalidating the update region. The previous version
  has released the screen buffer lock while scrolling up. It is not possible to
  release the lock while a write to the screen buffer is in progress. If the text
  output routines are faster, we should change the second buffer from a bitmap
  to character array.

svn path=/trunk/; revision=8578
This commit is contained in:
Hartmut Birr 2004-03-07 21:00:11 +00:00
parent 84269ab2d2
commit 11897d4d87
2 changed files with 111 additions and 65 deletions

View file

@ -1,4 +1,4 @@
/* $Id: guiconsole.c,v 1.10 2004/02/04 00:05:46 gvg Exp $
/* $Id: guiconsole.c,v 1.11 2004/03/07 21:00:11 hbirr Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
@ -29,6 +29,9 @@ typedef struct GUI_CONSOLE_DATA_TAG
PWCHAR LineBuffer;
BOOL CursorBlinkOn;
BOOL ForceCursorOff;
CRITICAL_SECTION Lock;
HDC MemoryDC;
HBITMAP MemoryBitmap;
} GUI_CONSOLE_DATA, *PGUI_CONSOLE_DATA;
#ifndef WM_APP
@ -37,8 +40,6 @@ typedef struct GUI_CONSOLE_DATA_TAG
#define PM_CREATE_CONSOLE (WM_APP + 1)
#define PM_DESTROY_CONSOLE (WM_APP + 2)
#define PM_COPY_REGION (WM_APP + 100)
#define CURSOR_BLINK_TIME 500
static BOOL Initialized = FALSE;
@ -62,8 +63,9 @@ GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
HDC Dc;
HFONT OldFont;
TEXTMETRICW Metrics;
NTSTATUS Status;
GuiData = HeapAlloc(Win32CsrApiHeap, 0,
GuiData = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
sizeof(GUI_CONSOLE_DATA) +
(Console->Size.X + 1) * sizeof(WCHAR));
if (NULL == GuiData)
@ -71,6 +73,15 @@ GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
DPRINT1("GuiConsoleNcCreate: HeapAlloc failed\n");
return FALSE;
}
Status = RtlInitializeCriticalSection(&GuiData->Lock);
if (!NT_SUCCESS(Status))
{
DPRINT1("RtlInitializeCriticalSection failed, Status=%x\n", Status);
HeapFree(Win32CsrApiHeap, 0, GuiData);
return FALSE;
}
GuiData->LineBuffer = (PWCHAR)(GuiData + 1);
GuiData->Font = CreateFontW(12, 0, 0, TA_BASELINE, FW_NORMAL,
@ -81,6 +92,7 @@ GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
if (NULL == GuiData->Font)
{
DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
RtlDeleteCriticalSection(&GuiData->Lock);
HeapFree(Win32CsrApiHeap, 0, GuiData);
return FALSE;
}
@ -88,6 +100,8 @@ GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
if (NULL == Dc)
{
DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
DeleteObject(GuiData->Font);
RtlDeleteCriticalSection(&GuiData->Lock);
HeapFree(Win32CsrApiHeap, 0, GuiData);
return FALSE;
}
@ -96,6 +110,8 @@ GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
{
DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
ReleaseDC(hWnd, Dc);
DeleteObject(GuiData->Font);
RtlDeleteCriticalSection(&GuiData->Lock);
HeapFree(Win32CsrApiHeap, 0, GuiData);
return FALSE;
}
@ -104,12 +120,23 @@ GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
SelectObject(Dc, OldFont);
ReleaseDC(hWnd, Dc);
DeleteObject(GuiData->Font);
RtlDeleteCriticalSection(&GuiData->Lock);
HeapFree(Win32CsrApiHeap, 0, GuiData);
return FALSE;
}
GuiData->CharWidth = Metrics.tmMaxCharWidth;
GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
SelectObject(Dc, OldFont);
GuiData->MemoryDC = CreateCompatibleDC(Dc);
GuiData->MemoryBitmap = CreateCompatibleBitmap(Dc,
Console->Size.X * GuiData->CharWidth,
Console->Size.Y * GuiData->CharHeight);
DeleteObject(SelectObject(GuiData->MemoryDC, GuiData->MemoryBitmap));
DeleteObject(SelectObject(GuiData->MemoryDC, GuiData->Font));
ReleaseDC(hWnd, Dc);
GuiData->CursorBlinkOn = TRUE;
GuiData->ForceCursorOff = FALSE;
@ -161,17 +188,15 @@ GuiConsoleGetLogicalCursorPos(PCSRSS_SCREEN_BUFFER Buff, ULONG *CursorX, ULONG *
}
}
static VOID FASTCALL
GuiConsoleHandlePaint(HWND hWnd)
VOID FASTCALL
GuiConsoleUpdateBitmap(HWND hWnd, RECT rc)
{
PAINTSTRUCT Ps;
HDC Dc;
PCSRSS_CONSOLE Console;
PGUI_CONSOLE_DATA GuiData;
PCSRSS_SCREEN_BUFFER Buff;
unsigned TopLine, BottomLine, LeftChar, RightChar;
unsigned Line, Char, Start;
HFONT OldFont;
HDC Dc;
ULONG TopLine, BottomLine, LeftChar, RightChar;
ULONG Line, Char, Start;
PBYTE From;
PWCHAR To;
BYTE LastAttribute, Attribute;
@ -182,23 +207,24 @@ GuiConsoleHandlePaint(HWND hWnd)
if (NULL != Console && NULL != GuiData && NULL != Console->ActiveBuffer)
{
Buff = Console->ActiveBuffer;
EnterCriticalSection(&(Buff->Header.Lock));
Dc = BeginPaint(hWnd, &Ps);
if (Ps.rcPaint.right <= Ps.rcPaint.left || Ps.rcPaint.bottom <= Ps.rcPaint.top)
EnterCriticalSection(&Buff->Header.Lock);
Dc = GetDC(hWnd);
if (rc.right <= rc.left || rc.bottom <= rc.top)
{
EndPaint(hWnd, &Ps);
LeaveCriticalSection(&(Buff->Header.Lock));
ReleaseDC(hWnd, Dc);
LeaveCriticalSection(&Buff->Header.Lock);
return;
}
OldFont = SelectObject(Dc, GuiData->Font);
TopLine = Ps.rcPaint.top / GuiData->CharHeight;
BottomLine = (Ps.rcPaint.bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1;
LeftChar = Ps.rcPaint.left / GuiData->CharWidth;
RightChar = (Ps.rcPaint.right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1;
EnterCriticalSection(&GuiData->Lock);
TopLine = rc.top / GuiData->CharHeight;
BottomLine = (rc.bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1;
LeftChar = rc.left / GuiData->CharWidth;
RightChar = (rc.right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1;
LastAttribute = Buff->Buffer[(TopLine * Buff->MaxX + LeftChar) * 2 + 1];
GuiConsoleSetTextColors(Dc, LastAttribute);
GuiConsoleSetTextColors(GuiData->MemoryDC, LastAttribute);
for (Line = TopLine; Line <= BottomLine; Line++)
{
if (Line + Buff->ShowY < Buff->MaxY)
@ -217,14 +243,14 @@ GuiConsoleHandlePaint(HWND hWnd)
{
if (*(From + 1) != Attribute)
{
TextOutW(Dc, Start * GuiData->CharWidth, Line * GuiData->CharHeight,
TextOutW(GuiData->MemoryDC, Start * GuiData->CharWidth, Line * GuiData->CharHeight,
GuiData->LineBuffer, Char - Start);
Start = Char;
To = GuiData->LineBuffer;
Attribute = *(From + 1);
if (Attribute != LastAttribute)
{
GuiConsoleSetTextColors(Dc, Attribute);
GuiConsoleSetTextColors(GuiData->MemoryDC, Attribute);
LastAttribute = Attribute;
}
}
@ -233,12 +259,10 @@ GuiConsoleHandlePaint(HWND hWnd)
To++;
From += 2;
}
TextOutW(Dc, Start * GuiData->CharWidth, Line * GuiData->CharHeight,
TextOutW(GuiData->MemoryDC, Start * GuiData->CharWidth, Line * GuiData->CharHeight,
GuiData->LineBuffer, RightChar - Start + 1);
}
SelectObject(Dc, OldFont);
if (Buff->CursorInfo.bVisible && GuiData->CursorBlinkOn
&&! GuiData->ForceCursorOff)
{
@ -253,17 +277,42 @@ GuiConsoleHandlePaint(HWND hWnd)
}
From = Buff->Buffer + (Buff->CurrentY * Buff->MaxX + Buff->CurrentX) * 2 + 1;
CursorBrush = CreateSolidBrush(GuiConsoleRGBFromAttribute(*From));
OldBrush = SelectObject(Dc, CursorBrush);
PatBlt(Dc, CursorX * GuiData->CharWidth,
OldBrush = SelectObject(GuiData->MemoryDC, CursorBrush);
PatBlt(GuiData->MemoryDC, CursorX * GuiData->CharWidth,
CursorY * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
GuiData->CharWidth, CursorHeight, PATCOPY);
SelectObject(Dc, OldBrush);
SelectObject(GuiData->MemoryDC, OldBrush);
DeleteObject(CursorBrush);
}
}
EndPaint(hWnd, &Ps);
LeaveCriticalSection(&(Buff->Header.Lock));
LeaveCriticalSection(&GuiData->Lock);
ReleaseDC(hWnd, Dc);
LeaveCriticalSection(&Buff->Header.Lock);
InvalidateRect(hWnd, &rc, FALSE);
}
}
VOID FASTCALL
GuiConsoleHandlePaint(HWND hWnd)
{
PAINTSTRUCT Ps;
HDC Dc;
PCSRSS_CONSOLE Console;
PGUI_CONSOLE_DATA GuiData;
GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
if (NULL != Console && NULL != GuiData)
{
EnterCriticalSection(&GuiData->Lock);
Dc = BeginPaint (hWnd, &Ps);
BitBlt(Dc, Ps.rcPaint.left, Ps.rcPaint.top,
Ps.rcPaint.right - Ps.rcPaint.left + 1,
Ps.rcPaint.bottom - Ps.rcPaint.top + 1, GuiData->MemoryDC,
Ps.rcPaint.left, Ps.rcPaint.top, SRCCOPY);
EndPaint (hWnd, &Ps);
LeaveCriticalSection(&GuiData->Lock);
}
else
{
@ -288,25 +337,6 @@ GuiConsoleHandleKey(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
ConioProcessKey(&Message, Console, FALSE);
}
static VOID FASTCALL
GuiConsoleHandleCopyRegion(HWND hWnd, PRECT Source, PRECT Dest)
{
RECT ClientRect, ScrollRect;
PGUI_CONSOLE_DATA GuiData;
PCSRSS_CONSOLE Console;
GetClientRect(hWnd, &ClientRect);
GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
ScrollRect.left = min(Source->left, Dest->left) * GuiData->CharWidth;
ScrollRect.top = min(Source->top, Dest->top) * GuiData->CharHeight;
ScrollRect.right = max(Source->right, Dest->right) * GuiData->CharWidth;
ScrollRect.bottom = max(Source->bottom, Dest->bottom) * GuiData->CharHeight;
ScrollWindow(hWnd,
(Dest->left - Source->left) * GuiData->CharWidth,
(Dest->top - Source->top) * GuiData->CharHeight,
&ScrollRect, &ClientRect);
}
static VOID FASTCALL
GuiIntDrawRegion(PGUI_CONSOLE_DATA GuiData, HWND Wnd, RECT *Region)
{
@ -317,7 +347,7 @@ GuiIntDrawRegion(PGUI_CONSOLE_DATA GuiData, HWND Wnd, RECT *Region)
RegionRect.right = (Region->right + 1) * GuiData->CharWidth;
RegionRect.bottom = (Region->bottom + 1) * GuiData->CharHeight;
InvalidateRect(Wnd, &RegionRect, FALSE);
GuiConsoleUpdateBitmap(Wnd, RegionRect);
}
static VOID STDCALL
@ -371,7 +401,7 @@ GuiWriteStream(PCSRSS_CONSOLE Console, RECT *Region, UINT CursorStartX, UINT Cur
Dest.right = Console->Size.X - 1;
Dest.bottom = Region->top - 1;
GuiConsoleCopyRegion(Console, &Source, &Dest);
GuiConsoleCopyRegion(Console->hWindow, &Source, &Dest);
}
GuiIntDrawRegion(GuiData, Console->hWindow, Region);
@ -467,6 +497,8 @@ GuiConsoleHandleNcDestroy(HWND hWnd)
GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
KillTimer(hWnd, 1);
Console->PrivateData = NULL;
DeleteDC(GuiData->MemoryDC);
RtlDeleteCriticalSection(&GuiData->Lock);
HeapFree(Win32CsrApiHeap, 0, GuiData);
}
@ -496,9 +528,6 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
GuiConsoleHandleTimer(hWnd);
Result = 0;
break;
case PM_COPY_REGION:
GuiConsoleHandleCopyRegion(hWnd, (PRECT) wParam, (PRECT) lParam);
break;
case WM_CLOSE:
GuiConsoleHandleClose(hWnd);
Result = 0;
@ -744,6 +773,7 @@ GuiInitConsole(PCSRSS_CONSOLE Console)
DPRINT1("Win32Csr: Failed to create graphics console thread. Expect problems\n");
return STATUS_UNSUCCESSFUL;
}
SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
CloseHandle(ThreadHandle);
WaitForSingleObject(GraphicsStartupEvent, INFINITE);
@ -762,13 +792,29 @@ GuiInitConsole(PCSRSS_CONSOLE Console)
}
VOID STDCALL
GuiConsoleCopyRegion(PCSRSS_CONSOLE Console,
GuiConsoleCopyRegion(HWND hWnd,
RECT *Source,
RECT *Dest)
{
LeaveCriticalSection(&(Console->ActiveBuffer->Header.Lock));
SendMessageW(Console->hWindow, PM_COPY_REGION, (WPARAM) Source, (LPARAM) Dest);
EnterCriticalSection(&(Console->ActiveBuffer->Header.Lock));
RECT ScrollRect;
PGUI_CONSOLE_DATA GuiData;
PCSRSS_CONSOLE Console;
GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
ScrollRect.left = Dest->left * GuiData->CharWidth;
ScrollRect.right = (Dest->right + 1) * GuiData->CharWidth;
ScrollRect.top = Dest->top * GuiData->CharHeight;
ScrollRect.bottom = (Dest->bottom + 1) * GuiData->CharHeight;
EnterCriticalSection(&GuiData->Lock);
BitBlt(GuiData->MemoryDC, ScrollRect.left, ScrollRect.top,
ScrollRect.right - ScrollRect.left, ScrollRect.bottom - ScrollRect.top,
GuiData->MemoryDC, Source->left * GuiData->CharWidth, Source->top * GuiData->CharHeight, SRCCOPY);
LeaveCriticalSection(&GuiData->Lock);
InvalidateRect(hWnd, &ScrollRect, FALSE);
}
/* EOF */

View file

@ -1,4 +1,4 @@
/* $Id: guiconsole.h,v 1.2 2004/01/11 17:31:16 gvg Exp $
/* $Id: guiconsole.h,v 1.3 2004/03/07 21:00:11 hbirr Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
@ -10,7 +10,7 @@
extern NTSTATUS FASTCALL GuiInitConsole(PCSRSS_CONSOLE Console);
extern VOID STDCALL GuiConsoleDrawRegion(PCSRSS_CONSOLE Console, SMALL_RECT Region);
extern VOID STDCALL GuiConsoleCopyRegion(PCSRSS_CONSOLE Console,
extern VOID STDCALL GuiConsoleCopyRegion(HWND hWnd,
RECT *Source,
RECT *Dest);
extern VOID STDCALL GuiConsoleChangeTitle(PCSRSS_CONSOLE Console);