mirror of
https://github.com/reactos/reactos.git
synced 2025-04-04 04:26:32 +00:00
823 lines
24 KiB
C
823 lines
24 KiB
C
/* $Id: guiconsole.c,v 1.13 2004/04/09 20:03:16 navaraf Exp $
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: subsys/csrss/win32csr/guiconsole.c
|
|
* PURPOSE: Implementation of gui-mode consoles
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <windows.h>
|
|
#include "conio.h"
|
|
#include "guiconsole.h"
|
|
#include "win32csr.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* Not defined in any header file */
|
|
extern VOID STDCALL PrivateCsrssManualGuiCheck(LONG Check);
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
typedef struct GUI_CONSOLE_DATA_TAG
|
|
{
|
|
HFONT Font;
|
|
unsigned CharWidth;
|
|
unsigned CharHeight;
|
|
PWCHAR LineBuffer;
|
|
BOOL CursorBlinkOn;
|
|
BOOL ForceCursorOff;
|
|
CRITICAL_SECTION Lock;
|
|
HDC MemoryDC;
|
|
HBITMAP MemoryBitmap;
|
|
} GUI_CONSOLE_DATA, *PGUI_CONSOLE_DATA;
|
|
|
|
#ifndef WM_APP
|
|
#define WM_APP 0x8000
|
|
#endif
|
|
#define PM_CREATE_CONSOLE (WM_APP + 1)
|
|
#define PM_DESTROY_CONSOLE (WM_APP + 2)
|
|
|
|
#define CURSOR_BLINK_TIME 500
|
|
|
|
static BOOL Initialized = FALSE;
|
|
static HWND NotifyWnd;
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
static VOID FASTCALL
|
|
GuiConsoleGetDataPointers(HWND hWnd, PCSRSS_CONSOLE *Console, PGUI_CONSOLE_DATA *GuiData)
|
|
{
|
|
*Console = (PCSRSS_CONSOLE) GetWindowLongW(hWnd, GWL_USERDATA);
|
|
*GuiData = (NULL == *Console ? NULL : (*Console)->PrivateData);
|
|
}
|
|
|
|
static BOOL FASTCALL
|
|
GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
|
|
{
|
|
RECT Rect;
|
|
PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Create->lpCreateParams;
|
|
PGUI_CONSOLE_DATA GuiData;
|
|
HDC Dc;
|
|
HFONT OldFont;
|
|
TEXTMETRICW Metrics;
|
|
|
|
GuiData = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
|
|
sizeof(GUI_CONSOLE_DATA) +
|
|
(Console->Size.X + 1) * sizeof(WCHAR));
|
|
if (NULL == GuiData)
|
|
{
|
|
DPRINT1("GuiConsoleNcCreate: HeapAlloc failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
InitializeCriticalSection(&GuiData->Lock);
|
|
|
|
GuiData->LineBuffer = (PWCHAR)(GuiData + 1);
|
|
|
|
GuiData->Font = CreateFontW(12, 0, 0, TA_BASELINE, FW_NORMAL,
|
|
FALSE, FALSE, FALSE, ANSI_CHARSET,
|
|
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
|
|
DEFAULT_QUALITY, FIXED_PITCH | FF_DONTCARE,
|
|
L"Bitstream Vera Sans Mono");
|
|
if (NULL == GuiData->Font)
|
|
{
|
|
DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
|
|
DeleteCriticalSection(&GuiData->Lock);
|
|
HeapFree(Win32CsrApiHeap, 0, GuiData);
|
|
return FALSE;
|
|
}
|
|
Dc = GetDC(hWnd);
|
|
if (NULL == Dc)
|
|
{
|
|
DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
|
|
DeleteObject(GuiData->Font);
|
|
DeleteCriticalSection(&GuiData->Lock);
|
|
HeapFree(Win32CsrApiHeap, 0, GuiData);
|
|
return FALSE;
|
|
}
|
|
OldFont = SelectObject(Dc, GuiData->Font);
|
|
if (NULL == OldFont)
|
|
{
|
|
DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
|
|
ReleaseDC(hWnd, Dc);
|
|
DeleteObject(GuiData->Font);
|
|
DeleteCriticalSection(&GuiData->Lock);
|
|
HeapFree(Win32CsrApiHeap, 0, GuiData);
|
|
return FALSE;
|
|
}
|
|
if (! GetTextMetricsW(Dc, &Metrics))
|
|
{
|
|
DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
|
|
SelectObject(Dc, OldFont);
|
|
ReleaseDC(hWnd, Dc);
|
|
DeleteObject(GuiData->Font);
|
|
DeleteCriticalSection(&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;
|
|
|
|
Console->PrivateData = GuiData;
|
|
SetWindowLongW(hWnd, GWL_USERDATA, (LONG) Console);
|
|
|
|
GetWindowRect(hWnd, &Rect);
|
|
Rect.right = Rect.left + Console->Size.X * GuiData->CharWidth +
|
|
2 * GetSystemMetrics(SM_CXFIXEDFRAME);
|
|
Rect.bottom = Rect.top + Console->Size.Y * GuiData->CharHeight +
|
|
2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION);
|
|
MoveWindow(hWnd, Rect.left, Rect.top, Rect.right - Rect.left,
|
|
Rect.bottom - Rect.top, FALSE);
|
|
|
|
SetTimer(hWnd, 1, CURSOR_BLINK_TIME, NULL);
|
|
|
|
return (BOOL) DefWindowProcW(hWnd, WM_NCCREATE, 0, (LPARAM) Create);
|
|
}
|
|
|
|
static COLORREF FASTCALL
|
|
GuiConsoleRGBFromAttribute(BYTE Attribute)
|
|
{
|
|
int Red = (Attribute & 0x04 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
|
|
int Green = (Attribute & 0x02 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
|
|
int Blue = (Attribute & 0x01 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
|
|
|
|
return RGB(Red, Green, Blue);
|
|
}
|
|
|
|
static VOID FASTCALL
|
|
GuiConsoleSetTextColors(HDC Dc, BYTE Attribute)
|
|
{
|
|
SetTextColor(Dc, GuiConsoleRGBFromAttribute(Attribute & 0x0f));
|
|
SetBkColor(Dc, GuiConsoleRGBFromAttribute((Attribute & 0xf0) >> 4));
|
|
}
|
|
|
|
static VOID FASTCALL
|
|
GuiConsoleGetLogicalCursorPos(PCSRSS_SCREEN_BUFFER Buff, ULONG *CursorX, ULONG *CursorY)
|
|
{
|
|
*CursorX = Buff->CurrentX;
|
|
if (Buff->CurrentY < Buff->ShowY)
|
|
{
|
|
*CursorY = Buff->MaxY - Buff->ShowY + Buff->CurrentY;
|
|
}
|
|
else
|
|
{
|
|
*CursorY = Buff->CurrentY - Buff->ShowY;
|
|
}
|
|
}
|
|
|
|
VOID FASTCALL
|
|
GuiConsoleUpdateBitmap(HWND hWnd, RECT rc)
|
|
{
|
|
PCSRSS_CONSOLE Console;
|
|
PGUI_CONSOLE_DATA GuiData;
|
|
PCSRSS_SCREEN_BUFFER Buff;
|
|
HDC Dc;
|
|
ULONG TopLine, BottomLine, LeftChar, RightChar;
|
|
ULONG Line, Char, Start;
|
|
PBYTE From;
|
|
PWCHAR To;
|
|
BYTE LastAttribute, Attribute;
|
|
ULONG CursorX, CursorY, CursorHeight;
|
|
HBRUSH CursorBrush, OldBrush;
|
|
|
|
GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
|
|
if (NULL != Console && NULL != GuiData && NULL != Console->ActiveBuffer)
|
|
{
|
|
Buff = Console->ActiveBuffer;
|
|
EnterCriticalSection(&Buff->Header.Lock);
|
|
Dc = GetDC(hWnd);
|
|
if (rc.right <= rc.left || rc.bottom <= rc.top)
|
|
{
|
|
ReleaseDC(hWnd, Dc);
|
|
LeaveCriticalSection(&Buff->Header.Lock);
|
|
return;
|
|
}
|
|
|
|
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(GuiData->MemoryDC, LastAttribute);
|
|
|
|
for (Line = TopLine; Line <= BottomLine; Line++)
|
|
{
|
|
if (Line + Buff->ShowY < Buff->MaxY)
|
|
{
|
|
From = Buff->Buffer + ((Line + Buff->ShowY) * Buff->MaxX + LeftChar) * 2;
|
|
}
|
|
else
|
|
{
|
|
From = Buff->Buffer +
|
|
((Line - (Buff->MaxY - Buff->ShowY)) * Buff->MaxX + LeftChar) * 2;
|
|
}
|
|
Attribute = *(From + 1);
|
|
Start = LeftChar;
|
|
To = GuiData->LineBuffer;
|
|
for (Char = LeftChar; Char <= RightChar; Char++)
|
|
{
|
|
if (*(From + 1) != Attribute)
|
|
{
|
|
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(GuiData->MemoryDC, Attribute);
|
|
LastAttribute = Attribute;
|
|
}
|
|
}
|
|
*((PBYTE) To) = *From;
|
|
*(((PBYTE) To) + 1) = '\0';
|
|
To++;
|
|
From += 2;
|
|
}
|
|
TextOutW(GuiData->MemoryDC, Start * GuiData->CharWidth, Line * GuiData->CharHeight,
|
|
GuiData->LineBuffer, RightChar - Start + 1);
|
|
}
|
|
|
|
if (Buff->CursorInfo.bVisible && GuiData->CursorBlinkOn
|
|
&&! GuiData->ForceCursorOff)
|
|
{
|
|
GuiConsoleGetLogicalCursorPos(Buff, &CursorX, &CursorY);
|
|
if (LeftChar <= CursorX && CursorX <= RightChar &&
|
|
TopLine <= CursorY && CursorY <= BottomLine)
|
|
{
|
|
CursorHeight = (GuiData->CharHeight * Buff->CursorInfo.dwSize) / 100;
|
|
if (CursorHeight < 1)
|
|
{
|
|
CursorHeight = 1;
|
|
}
|
|
From = Buff->Buffer + (Buff->CurrentY * Buff->MaxX + Buff->CurrentX) * 2 + 1;
|
|
CursorBrush = CreateSolidBrush(GuiConsoleRGBFromAttribute(*From));
|
|
OldBrush = SelectObject(GuiData->MemoryDC, CursorBrush);
|
|
PatBlt(GuiData->MemoryDC, CursorX * GuiData->CharWidth,
|
|
CursorY * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
|
|
GuiData->CharWidth, CursorHeight, PATCOPY);
|
|
SelectObject(GuiData->MemoryDC, OldBrush);
|
|
DeleteObject(CursorBrush);
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
Dc = BeginPaint (hWnd, &Ps);
|
|
EndPaint (hWnd, &Ps);
|
|
}
|
|
}
|
|
|
|
static VOID FASTCALL
|
|
GuiConsoleHandleKey(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PCSRSS_CONSOLE Console;
|
|
PGUI_CONSOLE_DATA GuiData;
|
|
MSG Message;
|
|
|
|
GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
|
|
Message.hwnd = hWnd;
|
|
Message.message = msg;
|
|
Message.wParam = wParam;
|
|
Message.lParam = lParam;
|
|
|
|
ConioProcessKey(&Message, Console, FALSE);
|
|
}
|
|
|
|
static VOID FASTCALL
|
|
GuiIntDrawRegion(PGUI_CONSOLE_DATA GuiData, HWND Wnd, RECT *Region)
|
|
{
|
|
RECT RegionRect;
|
|
|
|
RegionRect.left = Region->left * GuiData->CharWidth;
|
|
RegionRect.top = Region->top * GuiData->CharHeight;
|
|
RegionRect.right = (Region->right + 1) * GuiData->CharWidth;
|
|
RegionRect.bottom = (Region->bottom + 1) * GuiData->CharHeight;
|
|
|
|
GuiConsoleUpdateBitmap(Wnd, RegionRect);
|
|
}
|
|
|
|
static VOID STDCALL
|
|
GuiDrawRegion(PCSRSS_CONSOLE Console, RECT *Region)
|
|
{
|
|
PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
|
|
|
|
if (NULL == Console->hWindow || NULL == GuiData)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GuiIntDrawRegion(GuiData, Console->hWindow, Region);
|
|
}
|
|
|
|
static VOID FASTCALL
|
|
GuiInvalidateCell(PGUI_CONSOLE_DATA GuiData, HWND Wnd, UINT x, UINT y)
|
|
{
|
|
RECT CellRect;
|
|
|
|
CellRect.left = x;
|
|
CellRect.top = y;
|
|
CellRect.right = x;
|
|
CellRect.bottom = y;
|
|
|
|
GuiIntDrawRegion(GuiData, Wnd, &CellRect);
|
|
}
|
|
|
|
static VOID STDCALL
|
|
GuiWriteStream(PCSRSS_CONSOLE Console, RECT *Region, UINT CursorStartX, UINT CursorStartY,
|
|
UINT ScrolledLines, CHAR *Buffer, UINT Length)
|
|
{
|
|
PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
|
|
PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
|
|
LONG CursorEndX, CursorEndY;
|
|
RECT Source, Dest;
|
|
|
|
if (NULL == Console->hWindow || NULL == GuiData)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (0 != ScrolledLines)
|
|
{
|
|
Source.left = 0;
|
|
Source.top = ScrolledLines;
|
|
Source.right = Console->Size.X - 1;
|
|
Source.bottom = ScrolledLines + Region->top - 1;
|
|
Dest.left = 0;
|
|
Dest.top = 0;
|
|
Dest.right = Console->Size.X - 1;
|
|
Dest.bottom = Region->top - 1;
|
|
|
|
GuiConsoleCopyRegion(Console->hWindow, &Source, &Dest);
|
|
}
|
|
|
|
GuiIntDrawRegion(GuiData, Console->hWindow, Region);
|
|
|
|
if (CursorStartX < Region->left || Region->right < CursorStartX
|
|
|| CursorStartY < Region->top || Region->bottom < CursorStartY)
|
|
{
|
|
GuiInvalidateCell(GuiData, Console->hWindow, CursorStartX, CursorStartY);
|
|
}
|
|
|
|
ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
|
|
&CursorEndX, &CursorEndY);
|
|
if ((CursorEndX < Region->left || Region->right < CursorEndX
|
|
|| CursorEndY < Region->top || Region->bottom < CursorEndY)
|
|
&& (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
|
|
{
|
|
GuiInvalidateCell(GuiData, Console->hWindow, CursorEndX, CursorEndY);
|
|
}
|
|
}
|
|
|
|
static BOOL STDCALL
|
|
GuiSetCursorInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
|
|
{
|
|
RECT UpdateRect;
|
|
|
|
if (Console->ActiveBuffer == Buff)
|
|
{
|
|
ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
|
|
&UpdateRect.left, &UpdateRect.top);
|
|
UpdateRect.right = UpdateRect.left;
|
|
UpdateRect.bottom = UpdateRect.top;
|
|
ConioDrawRegion(Console, &UpdateRect);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL STDCALL
|
|
GuiSetScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff, UINT OldCursorX, UINT OldCursorY)
|
|
{
|
|
RECT UpdateRect;
|
|
|
|
if (Console->ActiveBuffer == Buff)
|
|
{
|
|
/* Redraw char at old position (removes cursor) */
|
|
UpdateRect.left = OldCursorX;
|
|
UpdateRect.top = OldCursorY;
|
|
UpdateRect.right = OldCursorX;
|
|
UpdateRect.bottom = OldCursorY;
|
|
ConioDrawRegion(Console, &UpdateRect);
|
|
/* Redraw char at new position (shows cursor) */
|
|
ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
|
|
&(UpdateRect.left), &(UpdateRect.top));
|
|
UpdateRect.right = UpdateRect.left;
|
|
UpdateRect.bottom = UpdateRect.top;
|
|
ConioDrawRegion(Console, &UpdateRect);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static VOID FASTCALL
|
|
GuiConsoleHandleTimer(HWND hWnd)
|
|
{
|
|
PCSRSS_CONSOLE Console;
|
|
PGUI_CONSOLE_DATA GuiData;
|
|
RECT CursorRect;
|
|
ULONG CursorX, CursorY;
|
|
|
|
GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
|
|
GuiData->CursorBlinkOn = ! GuiData->CursorBlinkOn;
|
|
|
|
GuiConsoleGetLogicalCursorPos(Console->ActiveBuffer, &CursorX, &CursorY);
|
|
CursorRect.left = CursorX;
|
|
CursorRect.top = CursorY;
|
|
CursorRect.right = CursorX;
|
|
CursorRect.bottom = CursorY;
|
|
GuiDrawRegion(Console, &CursorRect);
|
|
}
|
|
|
|
static VOID FASTCALL
|
|
GuiConsoleHandleClose(HWND hWnd)
|
|
{
|
|
/* FIXME for now, just ignore close requests */
|
|
}
|
|
|
|
static VOID FASTCALL
|
|
GuiConsoleHandleNcDestroy(HWND hWnd)
|
|
{
|
|
PCSRSS_CONSOLE Console;
|
|
PGUI_CONSOLE_DATA GuiData;
|
|
|
|
GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
|
|
KillTimer(hWnd, 1);
|
|
Console->PrivateData = NULL;
|
|
DeleteDC(GuiData->MemoryDC);
|
|
DeleteCriticalSection(&GuiData->Lock);
|
|
HeapFree(Win32CsrApiHeap, 0, GuiData);
|
|
}
|
|
|
|
static LRESULT CALLBACK
|
|
GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT Result;
|
|
|
|
switch(msg)
|
|
{
|
|
case WM_NCCREATE:
|
|
Result = (LRESULT) GuiConsoleHandleNcCreate(hWnd, (CREATESTRUCTW *) lParam);
|
|
break;
|
|
case WM_PAINT:
|
|
GuiConsoleHandlePaint(hWnd);
|
|
Result = 0;
|
|
break;
|
|
case WM_KEYDOWN:
|
|
case WM_KEYUP:
|
|
case WM_SYSKEYDOWN:
|
|
case WM_SYSKEYUP:
|
|
case WM_CHAR:
|
|
GuiConsoleHandleKey(hWnd, msg, wParam, lParam);
|
|
Result = 0;
|
|
break;
|
|
case WM_TIMER:
|
|
GuiConsoleHandleTimer(hWnd);
|
|
Result = 0;
|
|
break;
|
|
case WM_CLOSE:
|
|
GuiConsoleHandleClose(hWnd);
|
|
Result = 0;
|
|
break;
|
|
case WM_NCDESTROY:
|
|
GuiConsoleHandleNcDestroy(hWnd);
|
|
Result = 0;
|
|
break;
|
|
default:
|
|
Result = DefWindowProcW(hWnd, msg, wParam, lParam);
|
|
break;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
static LRESULT CALLBACK
|
|
GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HWND NewWindow;
|
|
LONG WindowCount;
|
|
PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) lParam;
|
|
|
|
switch(msg)
|
|
{
|
|
case WM_CREATE:
|
|
SetWindowLongW(hWnd, GWL_USERDATA, 0);
|
|
return 0;
|
|
case PM_CREATE_CONSOLE:
|
|
NewWindow = CreateWindowW(L"Win32CsrConsole",
|
|
Console->Title.Buffer,
|
|
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
(HINSTANCE) GetModuleHandleW(NULL),
|
|
(PVOID) Console);
|
|
Console->hWindow = NewWindow;
|
|
if (NULL != NewWindow)
|
|
{
|
|
SetWindowLongW(hWnd, GWL_USERDATA, GetWindowLongW(hWnd, GWL_USERDATA) + 1);
|
|
ShowWindow(NewWindow, SW_SHOW);
|
|
}
|
|
return (LRESULT) NewWindow;
|
|
case PM_DESTROY_CONSOLE:
|
|
DestroyWindow(Console->hWindow);
|
|
Console->hWindow = NULL;
|
|
WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
|
|
WindowCount--;
|
|
SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
|
|
if (0 == WindowCount)
|
|
{
|
|
NotifyWnd = NULL;
|
|
DestroyWindow(hWnd);
|
|
PrivateCsrssManualGuiCheck(-1);
|
|
PostQuitMessage(0);
|
|
}
|
|
return 0;
|
|
default:
|
|
return DefWindowProcW(hWnd, msg, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
static DWORD STDCALL
|
|
GuiConsoleGuiThread(PVOID Data)
|
|
{
|
|
MSG msg;
|
|
PHANDLE GraphicsStartupEvent = (PHANDLE) Data;
|
|
|
|
NotifyWnd = CreateWindowW(L"Win32CsrCreateNotify",
|
|
L"",
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
(HINSTANCE) GetModuleHandleW(NULL),
|
|
NULL);
|
|
if (NULL == NotifyWnd)
|
|
{
|
|
PrivateCsrssManualGuiCheck(-1);
|
|
SetEvent(*GraphicsStartupEvent);
|
|
return 1;
|
|
}
|
|
|
|
SetEvent(*GraphicsStartupEvent);
|
|
|
|
while(GetMessageW(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessageW(&msg);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static BOOL FASTCALL
|
|
GuiInit(VOID)
|
|
{
|
|
HDESK Desktop;
|
|
NTSTATUS Status;
|
|
WNDCLASSEXW wc;
|
|
|
|
Desktop = OpenDesktopW(L"Default", 0, FALSE, GENERIC_ALL);
|
|
if (NULL == Desktop)
|
|
{
|
|
DPRINT1("Failed to open desktop\n");
|
|
return FALSE;
|
|
}
|
|
Status = NtSetInformationProcess(NtCurrentProcess(),
|
|
ProcessDesktop,
|
|
&Desktop,
|
|
sizeof(Desktop));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Cannot set default desktop.\n");
|
|
return FALSE;
|
|
}
|
|
if (! SetThreadDesktop(Desktop))
|
|
{
|
|
DPRINT1("Failed to set thread desktop\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (NULL == NotifyWnd)
|
|
{
|
|
PrivateCsrssManualGuiCheck(+1);
|
|
}
|
|
|
|
wc.cbSize = sizeof(WNDCLASSEXW);
|
|
wc.lpszClassName = L"Win32CsrCreateNotify";
|
|
wc.lpfnWndProc = GuiConsoleNotifyWndProc;
|
|
wc.style = 0;
|
|
wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = NULL;
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hIconSm = NULL;
|
|
if (RegisterClassExW(&wc) == 0)
|
|
{
|
|
DPRINT1("Failed to register notify wndproc\n");
|
|
return FALSE;
|
|
}
|
|
|
|
wc.cbSize = sizeof(WNDCLASSEXW);
|
|
wc.lpszClassName = L"Win32CsrConsole";
|
|
wc.lpfnWndProc = GuiConsoleWndProc;
|
|
wc.style = 0;
|
|
wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
|
|
wc.hIcon = LoadIconW(Win32CsrDllHandle, MAKEINTRESOURCEW(1));
|
|
wc.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW));
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hIconSm = LoadImageW(Win32CsrDllHandle, MAKEINTRESOURCEW(1), IMAGE_ICON,
|
|
GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
|
|
LR_SHARED);
|
|
if (RegisterClassExW(&wc) == 0)
|
|
{
|
|
DPRINT1("Failed to register console wndproc\n");
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static VOID STDCALL
|
|
GuiInitScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer)
|
|
{
|
|
Buffer->DefaultAttrib = 0x0f;
|
|
}
|
|
|
|
STATIC BOOL STDCALL
|
|
GuiChangeTitle(PCSRSS_CONSOLE Console)
|
|
{
|
|
SendMessageW(Console->hWindow, WM_SETTEXT, 0, (LPARAM) Console->Title.Buffer);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
STATIC BOOL STDCALL
|
|
GuiChangeIcon(PCSRSS_CONSOLE Console)
|
|
{
|
|
SendMessageW(Console->hWindow, WM_SETICON, ICON_BIG, (LPARAM)Console->hWindowIcon);
|
|
SendMessageW(Console->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)Console->hWindowIcon);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static VOID STDCALL
|
|
GuiCleanupConsole(PCSRSS_CONSOLE Console)
|
|
{
|
|
SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM) Console);
|
|
}
|
|
|
|
static CSRSS_CONSOLE_VTBL GuiVtbl =
|
|
{
|
|
GuiInitScreenBuffer,
|
|
GuiWriteStream,
|
|
GuiDrawRegion,
|
|
GuiSetCursorInfo,
|
|
GuiSetScreenInfo,
|
|
GuiChangeTitle,
|
|
GuiCleanupConsole,
|
|
GuiChangeIcon
|
|
};
|
|
|
|
NTSTATUS FASTCALL
|
|
GuiInitConsole(PCSRSS_CONSOLE Console)
|
|
{
|
|
HANDLE GraphicsStartupEvent;
|
|
HANDLE ThreadHandle;
|
|
|
|
if (! Initialized)
|
|
{
|
|
Initialized = TRUE;
|
|
if (! GuiInit())
|
|
{
|
|
Initialized = FALSE;
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
Console->Vtbl = &GuiVtbl;
|
|
Console->Size.X = 80;
|
|
Console->Size.Y = 25;
|
|
if (NULL == NotifyWnd)
|
|
{
|
|
GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
if (NULL == GraphicsStartupEvent)
|
|
{
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
ThreadHandle = CreateThread(NULL,
|
|
0,
|
|
GuiConsoleGuiThread,
|
|
(PVOID) &GraphicsStartupEvent,
|
|
0,
|
|
NULL);
|
|
if (NULL == ThreadHandle)
|
|
{
|
|
NtClose(GraphicsStartupEvent);
|
|
DPRINT1("Win32Csr: Failed to create graphics console thread. Expect problems\n");
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
|
|
CloseHandle(ThreadHandle);
|
|
|
|
WaitForSingleObject(GraphicsStartupEvent, INFINITE);
|
|
CloseHandle(GraphicsStartupEvent);
|
|
|
|
if (NULL == NotifyWnd)
|
|
{
|
|
DPRINT1("Win32Csr: Failed to create notification window.\n");
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, 0, (LPARAM) Console);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID STDCALL
|
|
GuiConsoleCopyRegion(HWND hWnd,
|
|
RECT *Source,
|
|
RECT *Dest)
|
|
{
|
|
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 */
|