/* * 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 #define NDEBUG #include /* 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 */