mirror of
https://github.com/reactos/reactos.git
synced 2025-04-19 12:08:55 +00:00
- 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:
parent
84269ab2d2
commit
11897d4d87
2 changed files with 111 additions and 65 deletions
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue