mirror of
https://github.com/reactos/reactos.git
synced 2024-11-02 12:53:33 +00:00
83c238e490
- Simplify screen-buffers initialization. - Get rid of this CONSOLE_SCREEN_BUFFER_VTBL virtual table. - Move ConsoleInput to a proper header.
350 lines
10 KiB
C
350 lines
10 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Console Driver DLL
|
|
* FILE: win32ss/user/winsrv/consrv/condrv/conoutput.c
|
|
* PURPOSE: General Console Output Functions
|
|
* PROGRAMMERS: Jeffrey Morlan
|
|
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include <consrv.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
|
|
|
NTSTATUS
|
|
TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
|
|
IN PCONSOLE Console,
|
|
IN HANDLE ProcessHandle,
|
|
IN PTEXTMODE_BUFFER_INFO TextModeInfo);
|
|
NTSTATUS
|
|
GRAPHICS_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
|
|
IN PCONSOLE Console,
|
|
IN HANDLE ProcessHandle,
|
|
IN PGRAPHICS_BUFFER_INFO GraphicsInfo);
|
|
|
|
VOID
|
|
TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
|
|
VOID
|
|
GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
|
|
|
|
|
|
NTSTATUS
|
|
CONSOLE_SCREEN_BUFFER_Initialize(
|
|
OUT PCONSOLE_SCREEN_BUFFER* Buffer,
|
|
IN PCONSOLE Console,
|
|
IN CONSOLE_IO_OBJECT_TYPE Type,
|
|
IN SIZE_T Size)
|
|
{
|
|
if (Buffer == NULL || Console == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
*Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, max(sizeof(CONSOLE_SCREEN_BUFFER), Size));
|
|
if (*Buffer == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
/* Initialize the header with the default type */
|
|
ConSrvInitObject(&(*Buffer)->Header, Type /* SCREEN_BUFFER */, Console);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
|
|
{
|
|
switch (Buffer->Header.Type)
|
|
{
|
|
case TEXTMODE_BUFFER:
|
|
TEXTMODE_BUFFER_Destroy(Buffer);
|
|
break;
|
|
|
|
case GRAPHICS_BUFFER:
|
|
GRAPHICS_BUFFER_Destroy(Buffer);
|
|
break;
|
|
|
|
case SCREEN_BUFFER:
|
|
{
|
|
/* Free the palette handle */
|
|
if (Buffer->PaletteHandle != NULL)
|
|
DeleteObject(Buffer->PaletteHandle);
|
|
|
|
/* Free the screen buffer memory */
|
|
ConsoleFreeHeap(Buffer);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ConDrvCreateConsoleScreenBuffer
|
|
NTSTATUS
|
|
ConDrvCreateScreenBuffer(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
|
|
IN PCONSOLE Console,
|
|
IN HANDLE ProcessHandle OPTIONAL,
|
|
IN ULONG BufferType,
|
|
IN PVOID ScreenBufferInfo)
|
|
{
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
if ( Console == NULL || Buffer == NULL ||
|
|
(BufferType != CONSOLE_TEXTMODE_BUFFER && BufferType != CONSOLE_GRAPHICS_BUFFER) )
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Use the current process if ProcessHandle is NULL */
|
|
if (ProcessHandle == NULL)
|
|
ProcessHandle = NtCurrentProcess();
|
|
|
|
switch (BufferType)
|
|
{
|
|
case CONSOLE_TEXTMODE_BUFFER:
|
|
Status = TEXTMODE_BUFFER_Initialize(Buffer, Console, ProcessHandle,
|
|
(PTEXTMODE_BUFFER_INFO)ScreenBufferInfo);
|
|
break;
|
|
|
|
case CONSOLE_GRAPHICS_BUFFER:
|
|
Status = GRAPHICS_BUFFER_Initialize(Buffer, Console, ProcessHandle,
|
|
(PGRAPHICS_BUFFER_INFO)ScreenBufferInfo);
|
|
break;
|
|
|
|
default:
|
|
/* Never ever go there!! */
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
/* Insert the newly created screen buffer into the list, if succeeded */
|
|
if (NT_SUCCESS(Status)) InsertHeadList(&Console->BufferList, &(*Buffer)->ListEntry);
|
|
|
|
return Status;
|
|
}
|
|
|
|
static VOID
|
|
ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer);
|
|
|
|
VOID NTAPI
|
|
ConDrvDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer)
|
|
{
|
|
PCONSOLE Console = Buffer->Header.Console;
|
|
PCONSOLE_SCREEN_BUFFER NewBuffer;
|
|
|
|
/*
|
|
* We should notify temporarily the frontend because we are susceptible
|
|
* to delete the screen buffer it is using (which may be different from
|
|
* the active screen buffer in some cases), and because, if it actually
|
|
* uses the active screen buffer, we are going to nullify its pointer to
|
|
* change it.
|
|
*/
|
|
TermReleaseScreenBuffer(Console, Buffer);
|
|
|
|
RemoveEntryList(&Buffer->ListEntry);
|
|
if (Buffer == Console->ActiveBuffer)
|
|
{
|
|
/* Delete active buffer; switch to most recently created */
|
|
if (!IsListEmpty(&Console->BufferList))
|
|
{
|
|
NewBuffer = CONTAINING_RECORD(Console->BufferList.Flink,
|
|
CONSOLE_SCREEN_BUFFER,
|
|
ListEntry);
|
|
|
|
/* Tie console to new buffer and signal the change to the frontend */
|
|
ConioSetActiveScreenBuffer(NewBuffer);
|
|
}
|
|
else
|
|
{
|
|
Console->ActiveBuffer = NULL;
|
|
// InterlockedExchangePointer(&Console->ActiveBuffer, NULL);
|
|
}
|
|
}
|
|
|
|
CONSOLE_SCREEN_BUFFER_Destroy(Buffer);
|
|
}
|
|
|
|
static VOID
|
|
ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer)
|
|
{
|
|
PCONSOLE Console = Buffer->Header.Console;
|
|
Console->ActiveBuffer = Buffer;
|
|
// InterlockedExchangePointer(&Console->ActiveBuffer, Buffer);
|
|
TermSetActiveScreenBuffer(Console);
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
ConDrvSetConsoleActiveScreenBuffer(IN PCONSOLE Console,
|
|
IN PCONSOLE_SCREEN_BUFFER Buffer)
|
|
{
|
|
if (Console == NULL || Buffer == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
/* Validity check */
|
|
ASSERT(Console == Buffer->Header.Console);
|
|
|
|
if (Buffer == Console->ActiveBuffer) return STATUS_SUCCESS;
|
|
|
|
/* If old buffer has no handles, it's now unreferenced */
|
|
if (Console->ActiveBuffer->Header.ReferenceCount == 0)
|
|
{
|
|
ConDrvDeleteScreenBuffer(Console->ActiveBuffer);
|
|
}
|
|
|
|
/* Tie console to new buffer and signal the change to the frontend */
|
|
ConioSetActiveScreenBuffer(Buffer);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
PCONSOLE_SCREEN_BUFFER
|
|
ConDrvGetActiveScreenBuffer(IN PCONSOLE Console)
|
|
{
|
|
return (Console ? Console->ActiveBuffer : NULL);
|
|
}
|
|
|
|
/* PUBLIC DRIVER APIS *********************************************************/
|
|
|
|
NTSTATUS NTAPI
|
|
ConDrvInvalidateBitMapRect(IN PCONSOLE Console,
|
|
IN PCONSOLE_SCREEN_BUFFER Buffer,
|
|
IN PSMALL_RECT Region)
|
|
{
|
|
if (Console == NULL || Buffer == NULL || Region == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
/* Validity check */
|
|
ASSERT(Console == Buffer->Header.Console);
|
|
|
|
/* If the output buffer is the current one, redraw the correct portion of the screen */
|
|
if (Buffer == Console->ActiveBuffer) TermDrawRegion(Console, Region);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
ConDrvSetConsolePalette(IN PCONSOLE Console,
|
|
// IN PGRAPHICS_SCREEN_BUFFER Buffer,
|
|
IN PCONSOLE_SCREEN_BUFFER Buffer,
|
|
IN HPALETTE PaletteHandle,
|
|
IN UINT PaletteUsage)
|
|
{
|
|
BOOL Success;
|
|
|
|
/*
|
|
* Parameters validation
|
|
*/
|
|
if (Console == NULL || Buffer == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
if ( PaletteUsage != SYSPAL_STATIC &&
|
|
PaletteUsage != SYSPAL_NOSTATIC &&
|
|
PaletteUsage != SYSPAL_NOSTATIC256 )
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Validity check */
|
|
ASSERT(Console == Buffer->Header.Console);
|
|
|
|
/* Change the palette */
|
|
Success = TermSetPalette(Console, PaletteHandle, PaletteUsage);
|
|
if (Success)
|
|
{
|
|
/* Free the old palette handle if there was already one set */
|
|
if ( Buffer->PaletteHandle != NULL &&
|
|
Buffer->PaletteHandle != PaletteHandle )
|
|
{
|
|
DeleteObject(Buffer->PaletteHandle);
|
|
}
|
|
|
|
/* Save the new palette in the screen buffer */
|
|
Buffer->PaletteHandle = PaletteHandle;
|
|
Buffer->PaletteUsage = PaletteUsage;
|
|
}
|
|
|
|
return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
ConDrvGetConsoleCursorInfo(IN PCONSOLE Console,
|
|
IN PTEXTMODE_SCREEN_BUFFER Buffer,
|
|
OUT PCONSOLE_CURSOR_INFO CursorInfo)
|
|
{
|
|
if (Console == NULL || Buffer == NULL || CursorInfo == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
/* Validity check */
|
|
ASSERT(Console == Buffer->Header.Console);
|
|
|
|
*CursorInfo = Buffer->CursorInfo;
|
|
// CursorInfo->bVisible = Buffer->CursorInfo.bVisible;
|
|
// CursorInfo->dwSize = Buffer->CursorInfo.dwSize;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
ConDrvSetConsoleCursorInfo(IN PCONSOLE Console,
|
|
IN PTEXTMODE_SCREEN_BUFFER Buffer,
|
|
IN PCONSOLE_CURSOR_INFO CursorInfo)
|
|
{
|
|
ULONG Size;
|
|
BOOLEAN Visible, Success = TRUE;
|
|
|
|
if (Console == NULL || Buffer == NULL || CursorInfo == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
/* Validity check */
|
|
ASSERT(Console == Buffer->Header.Console);
|
|
|
|
Size = min(max(CursorInfo->dwSize, 1), 100);
|
|
Visible = CursorInfo->bVisible;
|
|
|
|
if ( (Size != Buffer->CursorInfo.dwSize) ||
|
|
(Visible && !Buffer->CursorInfo.bVisible) ||
|
|
(!Visible && Buffer->CursorInfo.bVisible) )
|
|
{
|
|
Buffer->CursorInfo.dwSize = Size;
|
|
Buffer->CursorInfo.bVisible = Visible;
|
|
|
|
Success = TermSetCursorInfo(Console, (PCONSOLE_SCREEN_BUFFER)Buffer);
|
|
}
|
|
|
|
return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
ConDrvSetConsoleCursorPosition(IN PCONSOLE Console,
|
|
IN PTEXTMODE_SCREEN_BUFFER Buffer,
|
|
IN PCOORD Position)
|
|
{
|
|
SHORT OldCursorX, OldCursorY;
|
|
|
|
if (Console == NULL || Buffer == NULL || Position == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
/* Validity check */
|
|
ASSERT(Console == Buffer->Header.Console);
|
|
|
|
if ( Position->X < 0 || Position->X >= Buffer->ScreenBufferSize.X ||
|
|
Position->Y < 0 || Position->Y >= Buffer->ScreenBufferSize.Y )
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
OldCursorX = Buffer->CursorPosition.X;
|
|
OldCursorY = Buffer->CursorPosition.Y;
|
|
Buffer->CursorPosition = *Position;
|
|
|
|
if ( ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer) &&
|
|
(!TermSetScreenInfo(Console, (PCONSOLE_SCREEN_BUFFER)Buffer, OldCursorX, OldCursorY)) )
|
|
{
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* EOF */
|