diff --git a/reactos/dll/cpl/console/console.c b/reactos/dll/cpl/console/console.c index c3657520fbd..a674aa018a1 100644 --- a/reactos/dll/cpl/console/console.c +++ b/reactos/dll/cpl/console/console.c @@ -93,7 +93,6 @@ InitConsoleDefaults(PCONSOLE_PROPS pConInfo) pConInfo->ci.HistoryBufferSize = 50; pConInfo->ci.NumberOfHistoryBuffers = 4; pConInfo->ci.HistoryNoDup = FALSE; - pConInfo->ci.FullScreen = FALSE; pConInfo->ci.QuickEdit = FALSE; pConInfo->ci.InsertMode = TRUE; // pConInfo->ci.InputBufferSize; @@ -119,6 +118,8 @@ InitConsoleDefaults(PCONSOLE_PROPS pConInfo) GuiInfo->FontWeight = FW_DONTCARE; GuiInfo->UseRasterFonts = TRUE; + GuiInfo->FullScreen = FALSE; + GuiInfo->ShowWindow = SW_SHOWNORMAL; GuiInfo->AutoPosition = TRUE; GuiInfo->WindowOrigin.x = 0; GuiInfo->WindowOrigin.y = 0; diff --git a/reactos/dll/cpl/console/layout.c b/reactos/dll/cpl/console/layout.c index e6fd38ec8e3..e4e69788901 100644 --- a/reactos/dll/cpl/console/layout.c +++ b/reactos/dll/cpl/console/layout.c @@ -273,8 +273,8 @@ LayoutProc(HWND hwndDlg, sheight = wheight; } } - swidth = max(swidth, 1); - sheight = max(sheight, 1); + swidth = min(max(swidth , 1), 0xFFFF); + sheight = min(max(sheight, 1), 0xFFFF); if (lppsn->hdr.idFrom == IDC_UPDOWN_SCREEN_BUFFER_WIDTH || lppsn->hdr.idFrom == IDC_UPDOWN_SCREEN_BUFFER_HEIGHT) { @@ -292,10 +292,10 @@ LayoutProc(HWND hwndDlg, } } - pConInfo->ci.ScreenBufferSize.X = swidth; - pConInfo->ci.ScreenBufferSize.Y = sheight; - pConInfo->ci.ConsoleSize.X = wwidth; - pConInfo->ci.ConsoleSize.Y = wheight; + pConInfo->ci.ScreenBufferSize.X = (SHORT)swidth; + pConInfo->ci.ScreenBufferSize.Y = (SHORT)sheight; + pConInfo->ci.ConsoleSize.X = (SHORT)wwidth; + pConInfo->ci.ConsoleSize.Y = (SHORT)wheight; GuiInfo->WindowOrigin.x = left; GuiInfo->WindowOrigin.y = top; PropSheet_Changed(GetParent(hwndDlg), hwndDlg); @@ -319,15 +319,15 @@ LayoutProc(HWND hwndDlg, DWORD sheight, swidth; DWORD left, top; - wwidth = GetDlgItemInt(hwndDlg, IDC_EDIT_WINDOW_SIZE_WIDTH, NULL, FALSE); + wwidth = GetDlgItemInt(hwndDlg, IDC_EDIT_WINDOW_SIZE_WIDTH, NULL, FALSE); wheight = GetDlgItemInt(hwndDlg, IDC_EDIT_WINDOW_SIZE_HEIGHT, NULL, FALSE); - swidth = GetDlgItemInt(hwndDlg, IDC_EDIT_SCREEN_BUFFER_WIDTH, NULL, FALSE); + swidth = GetDlgItemInt(hwndDlg, IDC_EDIT_SCREEN_BUFFER_WIDTH, NULL, FALSE); sheight = GetDlgItemInt(hwndDlg, IDC_EDIT_SCREEN_BUFFER_HEIGHT, NULL, FALSE); - left = GetDlgItemInt(hwndDlg, IDC_EDIT_WINDOW_POS_LEFT, NULL, FALSE); - top = GetDlgItemInt(hwndDlg, IDC_EDIT_WINDOW_POS_TOP, NULL, FALSE); + left = GetDlgItemInt(hwndDlg, IDC_EDIT_WINDOW_POS_LEFT, NULL, FALSE); + top = GetDlgItemInt(hwndDlg, IDC_EDIT_WINDOW_POS_TOP, NULL, FALSE); - swidth = max(swidth, 1); - sheight = max(sheight, 1); + swidth = min(max(swidth , 1), 0xFFFF); + sheight = min(max(sheight, 1), 0xFFFF); /* Automatically adjust window size when screen buffer decreases */ if (wwidth > swidth) @@ -342,10 +342,10 @@ LayoutProc(HWND hwndDlg, wheight = sheight; } - pConInfo->ci.ScreenBufferSize.X = swidth; - pConInfo->ci.ScreenBufferSize.Y = sheight; - pConInfo->ci.ConsoleSize.X = wwidth; - pConInfo->ci.ConsoleSize.Y = wheight; + pConInfo->ci.ScreenBufferSize.X = (SHORT)swidth; + pConInfo->ci.ScreenBufferSize.Y = (SHORT)sheight; + pConInfo->ci.ConsoleSize.X = (SHORT)wwidth; + pConInfo->ci.ConsoleSize.Y = (SHORT)wheight; GuiInfo->WindowOrigin.x = left; GuiInfo->WindowOrigin.y = top; PropSheet_Changed(GetParent(hwndDlg), hwndDlg); diff --git a/reactos/dll/cpl/console/options.c b/reactos/dll/cpl/console/options.c index 9ba28cfcdfd..e3a19140cee 100644 --- a/reactos/dll/cpl/console/options.c +++ b/reactos/dll/cpl/console/options.c @@ -23,6 +23,7 @@ OptionsProc(HWND hwndDlg, LPARAM lParam) { PCONSOLE_PROPS pConInfo; + PGUI_CONSOLE_INFO GuiInfo; LRESULT lResult; HWND hDlgCtrl; LPPSHNOTIFY lppsn; @@ -70,6 +71,7 @@ OptionsProc(HWND hwndDlg, case WM_COMMAND: { if (!pConInfo) break; + GuiInfo = pConInfo->TerminalInfo.TermInfo; switch (LOWORD(wParam)) { @@ -93,13 +95,13 @@ OptionsProc(HWND hwndDlg, } case IDC_RADIO_DISPLAY_WINDOW: { - pConInfo->ci.FullScreen = FALSE; + GuiInfo->FullScreen = FALSE; PropSheet_Changed(GetParent(hwndDlg), hwndDlg); break; } case IDC_RADIO_DISPLAY_FULL: { - pConInfo->ci.FullScreen = TRUE; + GuiInfo->FullScreen = TRUE; PropSheet_Changed(GetParent(hwndDlg), hwndDlg); break; } @@ -167,6 +169,7 @@ static void UpdateDialogElements(HWND hwndDlg, PCONSOLE_PROPS pConInfo) { + PGUI_CONSOLE_INFO GuiInfo = pConInfo->TerminalInfo.TermInfo; HWND hDlgCtrl; TCHAR szBuffer[MAX_PATH]; @@ -225,7 +228,7 @@ UpdateDialogElements(HWND hwndDlg, PCONSOLE_PROPS pConInfo) SendMessage(hDlgCtrl, BM_SETCHECK, (LPARAM)BST_UNCHECKED, 0); /* Update full/window screen */ - if (pConInfo->ci.FullScreen) + if (GuiInfo->FullScreen) { hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_DISPLAY_FULL); SendMessage(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, 0); diff --git a/reactos/dll/win32/kernel32/client/console/console.c b/reactos/dll/win32/kernel32/client/console/console.c index c0e2286bda2..657196dca34 100644 --- a/reactos/dll/win32/kernel32/client/console/console.c +++ b/reactos/dll/win32/kernel32/client/console/console.c @@ -438,16 +438,38 @@ GetNumberOfConsoleFonts(VOID) /* - * @unimplemented (Undocumented) + * @implemented (Undocumented) + * @note See http://blog.airesoft.co.uk/2012/10/things-ms-can-do-that-they-dont-tell-you-about-console-graphics/ */ -DWORD +BOOL WINAPI -InvalidateConsoleDIBits(DWORD Unknown0, - DWORD Unknown1) +InvalidateConsoleDIBits(IN HANDLE hConsoleOutput, + IN PSMALL_RECT lpRect) { - DPRINT1("InvalidateConsoleDIBits(0x%x, 0x%x) UNIMPLEMENTED!\n", Unknown0, Unknown1); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; + NTSTATUS Status; + CONSOLE_API_MESSAGE ApiMessage; + PCONSOLE_INVALIDATEDIBITS InvalidateDIBitsRequest = &ApiMessage.Data.InvalidateDIBitsRequest; + + if (lpRect == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + InvalidateDIBitsRequest->OutputHandle = hConsoleOutput; + InvalidateDIBitsRequest->Region = *lpRect; + + Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, + NULL, + CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepInvalidateBitMapRect), + sizeof(CONSOLE_INVALIDATEDIBITS)); + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return FALSE; + } + + return TRUE; } @@ -1445,8 +1467,8 @@ SetConsoleWindowInfo(HANDLE hConsoleOutput, } SetWindowInfoRequest->OutputHandle = hConsoleOutput; - SetWindowInfoRequest->Absolute = bAbsolute; - SetWindowInfoRequest->WindowRect = *lpConsoleWindow; + SetWindowInfoRequest->Absolute = bAbsolute; + SetWindowInfoRequest->WindowRect = *lpConsoleWindow; Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, NULL, @@ -1803,31 +1825,68 @@ CreateConsoleScreenBuffer(DWORD dwDesiredAccess, { NTSTATUS Status; CONSOLE_API_MESSAGE ApiMessage; + PCONSOLE_CREATESCREENBUFFER CreateScreenBufferRequest = &ApiMessage.Data.CreateScreenBufferRequest; + PCSR_CAPTURE_BUFFER CaptureBuffer = NULL; + PCONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo = /*(PCONSOLE_GRAPHICS_BUFFER_INFO)*/lpScreenBufferData; if ( (dwDesiredAccess & ~(GENERIC_READ | GENERIC_WRITE)) || (dwShareMode & ~(FILE_SHARE_READ | FILE_SHARE_WRITE)) || - (dwFlags != CONSOLE_TEXTMODE_BUFFER) ) + (dwFlags != CONSOLE_TEXTMODE_BUFFER && dwFlags != CONSOLE_GRAPHICS_BUFFER) ) { SetLastError(ERROR_INVALID_PARAMETER); return INVALID_HANDLE_VALUE; } - ApiMessage.Data.CreateScreenBufferRequest.Access = dwDesiredAccess; - ApiMessage.Data.CreateScreenBufferRequest.ShareMode = dwShareMode; - ApiMessage.Data.CreateScreenBufferRequest.Inheritable = + CreateScreenBufferRequest->ScreenBufferType = dwFlags; + CreateScreenBufferRequest->Access = dwDesiredAccess; + CreateScreenBufferRequest->ShareMode = dwShareMode; + CreateScreenBufferRequest->Inheritable = (lpSecurityAttributes ? lpSecurityAttributes->bInheritHandle : FALSE); + if (dwFlags == CONSOLE_GRAPHICS_BUFFER) + { + if (CreateScreenBufferRequest->Inheritable || GraphicsBufferInfo == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return INVALID_HANDLE_VALUE; + } + + CreateScreenBufferRequest->GraphicsBufferInfo = *GraphicsBufferInfo; + + CaptureBuffer = CsrAllocateCaptureBuffer(1, GraphicsBufferInfo->dwBitMapInfoLength); + if (CaptureBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + CsrCaptureMessageBuffer(CaptureBuffer, + (PVOID)GraphicsBufferInfo->lpBitMapInfo, + GraphicsBufferInfo->dwBitMapInfoLength, + (PVOID*)&CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMapInfo); + } + Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, - NULL, + CaptureBuffer, CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepCreateScreenBuffer), sizeof(CONSOLE_CREATESCREENBUFFER)); + + if (CaptureBuffer) + CsrFreeCaptureBuffer(CaptureBuffer); + if (!NT_SUCCESS(Status)) { BaseSetLastNTError(Status); return INVALID_HANDLE_VALUE; } - return ApiMessage.Data.CreateScreenBufferRequest.OutputHandle; + if (dwFlags == CONSOLE_GRAPHICS_BUFFER && GraphicsBufferInfo) + { + GraphicsBufferInfo->hMutex = CreateScreenBufferRequest->GraphicsBufferInfo.hMutex ; + GraphicsBufferInfo->lpBitMap = CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMap; + } + + return CreateScreenBufferRequest->OutputHandle; } @@ -2296,7 +2355,7 @@ GetConsoleInputExeNameA(DWORD nBufferLength, LPSTR lpBuffer) /* Initialize strings for conversion */ RtlInitUnicodeString(&BufferU, Buffer); BufferA.Length = 0; - BufferA.MaximumLength = nBufferLength; + BufferA.MaximumLength = (USHORT)nBufferLength; BufferA.Buffer = lpBuffer; /* Convert unicode name to ansi, copying as much chars as fit */ diff --git a/reactos/dll/win32/kernel32/client/console/history.c b/reactos/dll/win32/kernel32/client/console/history.c index 5924e4a5871..ae8e93de9a0 100644 --- a/reactos/dll/win32/kernel32/client/console/history.c +++ b/reactos/dll/win32/kernel32/client/console/history.c @@ -46,7 +46,7 @@ IntCaptureMessageString(PCSR_CAPTURE_BUFFER CaptureBuffer, Size = MultiByteToWideChar(CP_ACP, 0, String, Size, RequestString->Buffer, Size * sizeof(WCHAR)) * sizeof(WCHAR); } - RequestString->Length = RequestString->MaximumLength = Size; + RequestString->Length = RequestString->MaximumLength = (USHORT)Size; } diff --git a/reactos/include/psdk/winbase.h b/reactos/include/psdk/winbase.h index 82fdeea7536..a123ebd76ae 100644 --- a/reactos/include/psdk/winbase.h +++ b/reactos/include/psdk/winbase.h @@ -194,7 +194,6 @@ extern "C" { #define PROFILE_USER 0x10000000 #define PROFILE_KERNEL 0x20000000 #define PROFILE_SERVER 0x40000000 -#define CONSOLE_TEXTMODE_BUFFER 1 #define CREATE_NEW 1 #define CREATE_ALWAYS 2 #define OPEN_EXISTING 3 diff --git a/reactos/include/psdk/wincon.h b/reactos/include/psdk/wincon.h index bbc1bfe6920..90998c9c600 100644 --- a/reactos/include/psdk/wincon.h +++ b/reactos/include/psdk/wincon.h @@ -24,12 +24,15 @@ extern "C" { /* * Console display modes */ +// These codes are answered by GetConsoleDisplayMode +#define CONSOLE_WINDOWED 0 #define CONSOLE_FULLSCREEN 1 -#define CONSOLE_FULLSCREEN_HARDWARE 2 #if (_WIN32_WINNT >= 0x0600) #define CONSOLE_OVERSTRIKE 1 #endif +#define CONSOLE_FULLSCREEN_HARDWARE 2 +// These codes should be given to SetConsoleDisplayMode #define CONSOLE_FULLSCREEN_MODE 1 #define CONSOLE_WINDOWED_MODE 2 @@ -53,6 +56,12 @@ extern "C" { #define COMMON_LVB_REVERSE_VIDEO 0x4000 #define COMMON_LVB_UNDERSCORE 0x8000 +/* + * Screen buffer types + */ +#define CONSOLE_TEXTMODE_BUFFER 1 +#define CONSOLE_GRAPHICS_BUFFER 2 /* Undocumented, see http://blog.airesoft.co.uk/2012/10/things-ms-can-do-that-they-dont-tell-you-about-console-graphics/ */ + /* * Control handler codes */ @@ -154,29 +163,35 @@ typedef struct _CHAR_INFO { } Char; WORD Attributes; } CHAR_INFO,*PCHAR_INFO; + typedef struct _SMALL_RECT { SHORT Left; SHORT Top; SHORT Right; SHORT Bottom; } SMALL_RECT,*PSMALL_RECT; + typedef struct _CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; } CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO; + typedef struct _COORD { SHORT X; SHORT Y; } COORD, *PCOORD; + typedef struct _CONSOLE_SELECTION_INFO { DWORD dwFlags; COORD dwSelectionAnchor; SMALL_RECT srSelection; } CONSOLE_SELECTION_INFO, *PCONSOLE_SELECTION_INFO; + typedef struct _CONSOLE_FONT_INFO { DWORD nFont; COORD dwFontSize; } CONSOLE_FONT_INFO, *PCONSOLE_FONT_INFO; + typedef struct _CONSOLE_SCREEN_BUFFER_INFO { COORD dwSize; COORD dwCursorPosition; @@ -184,7 +199,20 @@ typedef struct _CONSOLE_SCREEN_BUFFER_INFO { SMALL_RECT srWindow; COORD dwMaximumWindowSize; } CONSOLE_SCREEN_BUFFER_INFO,*PCONSOLE_SCREEN_BUFFER_INFO; + +/* Undocumented, see http://blog.airesoft.co.uk/2012/10/things-ms-can-do-that-they-dont-tell-you-about-console-graphics/ */ +#if defined(_WINGDI_) && !defined(NOGDI) +typedef struct _CONSOLE_GRAPHICS_BUFFER_INFO { + DWORD dwBitMapInfoLength; + LPBITMAPINFO lpBitMapInfo; + DWORD dwUsage; // DIB_PAL_COLORS or DIB_RGB_COLORS + HANDLE hMutex; + PVOID lpBitMap; +} CONSOLE_GRAPHICS_BUFFER_INFO, *PCONSOLE_GRAPHICS_BUFFER_INFO; +#endif + typedef BOOL(CALLBACK *PHANDLER_ROUTINE)(_In_ DWORD); + typedef struct _KEY_EVENT_RECORD { BOOL bKeyDown; WORD wRepeatCount; @@ -198,18 +226,21 @@ typedef struct _KEY_EVENT_RECORD { } #ifdef __GNUC__ /* gcc's alignment is not what win32 expects */ - PACKED +PACKED #endif KEY_EVENT_RECORD; + typedef struct _MOUSE_EVENT_RECORD { COORD dwMousePosition; DWORD dwButtonState; DWORD dwControlKeyState; DWORD dwEventFlags; } MOUSE_EVENT_RECORD; -typedef struct _WINDOW_BUFFER_SIZE_RECORD { COORD dwSize; } WINDOW_BUFFER_SIZE_RECORD; -typedef struct _MENU_EVENT_RECORD { UINT dwCommandId; } MENU_EVENT_RECORD,*PMENU_EVENT_RECORD; + +typedef struct _WINDOW_BUFFER_SIZE_RECORD { COORD dwSize; } WINDOW_BUFFER_SIZE_RECORD; +typedef struct _MENU_EVENT_RECORD { UINT dwCommandId; } MENU_EVENT_RECORD,*PMENU_EVENT_RECORD; typedef struct _FOCUS_EVENT_RECORD { BOOL bSetFocus; } FOCUS_EVENT_RECORD; + typedef struct _INPUT_RECORD { WORD EventType; union { @@ -322,6 +353,9 @@ BOOL WINAPI GetConsoleMode(HANDLE,PDWORD); UINT WINAPI GetConsoleOutputCP(VOID); BOOL WINAPI GetConsoleScreenBufferInfo(_In_ HANDLE, _Out_ PCONSOLE_SCREEN_BUFFER_INFO); +/* Undocumented, see http://blog.airesoft.co.uk/2012/10/things-ms-can-do-that-they-dont-tell-you-about-console-graphics/ */ +BOOL WINAPI InvalidateConsoleDIBits(_In_ HANDLE, _In_ PSMALL_RECT); + DWORD WINAPI GetConsoleTitleA( @@ -342,6 +376,7 @@ BOOL APIENTRY SetConsoleDisplayMode(_In_ HANDLE hConsoleOutput, _In_ DWORD dwFla COORD WINAPI GetLargestConsoleWindowSize(_In_ HANDLE); BOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE,PDWORD); BOOL WINAPI GetNumberOfConsoleMouseButtons(_Out_ PDWORD); + BOOL WINAPI PeekConsoleInputA(HANDLE,PINPUT_RECORD,DWORD,PDWORD); BOOL diff --git a/reactos/include/reactos/subsys/win/conmsg.h b/reactos/include/reactos/subsys/win/conmsg.h index 366fe2e297a..ee650048760 100644 --- a/reactos/include/reactos/subsys/win/conmsg.h +++ b/reactos/include/reactos/subsys/win/conmsg.h @@ -60,7 +60,7 @@ typedef enum _CONSRV_API_NUMBER ConsolepGetTitle, ConsolepSetTitle, ConsolepCreateScreenBuffer, - // ConsolepInvalidateBitMapRect, + ConsolepInvalidateBitMapRect, // ConsolepVDMOperation, // ConsolepSetCursor, // ConsolepShowCursor, @@ -236,8 +236,6 @@ typedef struct DWORD ConsoleMode; } CONSOLE_GETSETCONSOLEMODE, *PCONSOLE_GETSETCONSOLEMODE; - -#define CONSOLE_WINDOWED 0 /* Internal console hardware state */ typedef struct { // HANDLE OutputHandle; @@ -266,11 +264,17 @@ typedef struct typedef struct { - HANDLE OutputHandle; /* Handle to newly created screen buffer */ + HANDLE OutputHandle; /* Handle to newly created screen buffer */ + DWORD ScreenBufferType; /* Type of the screen buffer: CONSOLE_TEXTMODE_BUFFER or CONSOLE_GRAPHICS_BUFFER */ + /* + * If we are creating a graphics screen buffer, + * this structure holds the initialization information. + */ + CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo; DWORD Access; DWORD ShareMode; - BOOL Inheritable; + BOOL Inheritable; } CONSOLE_CREATESCREENBUFFER, *PCONSOLE_CREATESCREENBUFFER; typedef struct @@ -278,6 +282,12 @@ typedef struct HANDLE OutputHandle; /* Handle to screen buffer to switch to */ } CONSOLE_SETACTIVESCREENBUFFER, *PCONSOLE_SETACTIVESCREENBUFFER; +typedef struct +{ + HANDLE OutputHandle; + SMALL_RECT Region; +} CONSOLE_INVALIDATEDIBITS, *PCONSOLE_INVALIDATEDIBITS; + typedef struct { DWORD Length; @@ -624,6 +634,7 @@ typedef struct _CONSOLE_API_MESSAGE CONSOLE_GETSETHWSTATE HardwareStateRequest; /* Console window */ + CONSOLE_INVALIDATEDIBITS InvalidateDIBitsRequest; CONSOLE_GETSETCONSOLETITLE TitleRequest; CONSOLE_GETLARGESTWINDOWSIZE GetLargestWindowSizeRequest; CONSOLE_SETWINDOWINFO SetWindowInfoRequest; diff --git a/reactos/win32ss/user/consrv/CMakeLists.txt b/reactos/win32ss/user/consrv/CMakeLists.txt index 2519d33fced..f43f2da9b13 100644 --- a/reactos/win32ss/user/consrv/CMakeLists.txt +++ b/reactos/win32ss/user/consrv/CMakeLists.txt @@ -12,18 +12,36 @@ list(APPEND SOURCE alias.c coninput.c conoutput.c + graphics.c + text.c console.c handle.c init.c lineinput.c settings.c - consrv.rc frontends/gui/guiterm.c frontends/gui/guisettings.c + frontends/gui/graphics.c + frontends/gui/text.c frontends/tui/tuiterm.c ${CMAKE_CURRENT_BINARY_DIR}/consrv.def) -add_library(consrv SHARED ${SOURCE}) +add_library(consrv SHARED + ${SOURCE} + consrv.rc) + +# +# Explicitely enable MS extensions to be able to use unnamed (anonymous) nested structs. +# +# FIXME: http://www.cmake.org/Bug/view.php?id=12998 +if(MSVC) + ## NOTE: No need to specify it as we use MSVC :) + #add_target_compile_flags(consrv "/Ze") + ##set_source_files_properties(${SOURCE} PROPERTIES COMPILE_FLAGS "/Ze") +else() + add_target_compile_flags(consrv "-fms-extensions") + #set_source_files_properties(${SOURCE} PROPERTIES COMPILE_FLAGS "-fms-extensions") +endif() target_link_libraries(consrv win32ksys ${PSEH_LIB} uuid) # win32ksys because of NtUser...() diff --git a/reactos/win32ss/user/consrv/api.h b/reactos/win32ss/user/consrv/api.h index 5819706d409..b37f5d792e1 100644 --- a/reactos/win32ss/user/consrv/api.h +++ b/reactos/win32ss/user/consrv/api.h @@ -24,6 +24,7 @@ CSR_API(SrvFlushConsoleInputBuffer); CSR_API(SrvGetConsoleNumberOfInputEvents); /* conoutput.c */ +CSR_API(SrvInvalidateBitMapRect); CSR_API(SrvReadConsoleOutput); CSR_API(SrvWriteConsole); CSR_API(SrvWriteConsoleOutput); diff --git a/reactos/win32ss/user/consrv/coninput.c b/reactos/win32ss/user/consrv/coninput.c index 6793b5d5b6c..525ae013a68 100644 --- a/reactos/win32ss/user/consrv/coninput.c +++ b/reactos/win32ss/user/consrv/coninput.c @@ -82,7 +82,7 @@ ConioProcessInputEvent(PCONSOLE Console, if (Console->InputBuffer.Mode & ENABLE_LINE_INPUT && (vk == VK_PAUSE || (vk == 'S' && (cks & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) && - !(cks & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))))) + !(cks & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))))) { ConioPause(Console, PAUSED_FROM_KEYBOARD); return STATUS_SUCCESS; @@ -101,8 +101,8 @@ ConioProcessInputEvent(PCONSOLE Console, /* add event to the queue */ ConInRec = ConsoleAllocHeap(0, sizeof(ConsoleInput)); - if (ConInRec == NULL) - return STATUS_INSUFFICIENT_RESOURCES; + if (ConInRec == NULL) return STATUS_INSUFFICIENT_RESOURCES; + ConInRec->InputEvent = *InputEvent; InsertTailList(&Console->InputBuffer.InputEvents, &ConInRec->ListEntry); @@ -178,7 +178,6 @@ ConioProcessKey(PCONSOLE Console, MSG* msg) * or translated keys may be involved. */ static UINT LastVirtualKey = 0; DWORD ShiftState; - UINT RepeatCount; WCHAR UnicodeChar; UINT VirtualKeyCode; UINT VirtualScanCode; @@ -193,8 +192,7 @@ ConioProcessKey(PCONSOLE Console, MSG* msg) return; } - RepeatCount = 1; - VirtualScanCode = (msg->lParam >> 16) & 0xff; + VirtualScanCode = HIWORD(msg->lParam) & 0xFF; Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR || msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR; @@ -218,17 +216,17 @@ ConioProcessKey(PCONSOLE Console, MSG* msg) Chars, 2, 0, - 0); + NULL); UnicodeChar = (1 == RetChars ? Chars[0] : 0); } er.EventType = KEY_EVENT; er.Event.KeyEvent.bKeyDown = Down; - er.Event.KeyEvent.wRepeatCount = RepeatCount; - er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar; - er.Event.KeyEvent.dwControlKeyState = ShiftState; + er.Event.KeyEvent.wRepeatCount = 1; er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode; er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode; + er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar; + er.Event.KeyEvent.dwControlKeyState = ShiftState; if (ConioProcessKeyCallback(Console, msg, diff --git a/reactos/win32ss/user/consrv/conio.h b/reactos/win32ss/user/consrv/conio.h index 7235ac21422..677a3eddd04 100644 --- a/reactos/win32ss/user/consrv/conio.h +++ b/reactos/win32ss/user/consrv/conio.h @@ -10,6 +10,8 @@ /* Macros used to call functions in the FRONTEND_VTBL virtual table */ +#define ConioCleanupConsole(Console) \ + (Console)->TermIFace.Vtbl->CleanupConsole(Console) #define ConioDrawRegion(Console, Region) \ (Console)->TermIFace.Vtbl->DrawRegion((Console), (Region)) #define ConioWriteStream(Console, Block, CurStartX, CurStartY, ScrolledLines, Buffer, Length) \ @@ -19,26 +21,24 @@ (Console)->TermIFace.Vtbl->SetCursorInfo((Console), (Buff)) #define ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY) \ (Console)->TermIFace.Vtbl->SetScreenInfo((Console), (Buff), (OldCursorX), (OldCursorY)) -#define ConioUpdateScreenInfo(Console, Buff) \ - (Console)->TermIFace.Vtbl->UpdateScreenInfo((Console), (Buff)) -#define ConioIsBufferResizeSupported(Console) \ - (Console)->TermIFace.Vtbl->IsBufferResizeSupported(Console) -#define ConioChangeTitle(Console) \ - (Console)->TermIFace.Vtbl->ChangeTitle(Console) -#define ConioCleanupConsole(Console) \ - (Console)->TermIFace.Vtbl->CleanupConsole(Console) -#define ConioChangeIcon(Console, hWindowIcon) \ - (Console)->TermIFace.Vtbl->ChangeIcon((Console), (hWindowIcon)) -// #define ConioResizeBuffer(Console, Buff, Size) (Console)->TermIFace.Vtbl->ResizeBuffer((Console), (Buff), (Size)) #define ConioResizeTerminal(Console) \ (Console)->TermIFace.Vtbl->ResizeTerminal(Console) #define ConioProcessKeyCallback(Console, Msg, KeyStateMenu, ShiftState, VirtualKeyCode, Down) \ (Console)->TermIFace.Vtbl->ProcessKeyCallback((Console), (Msg), (KeyStateMenu), (ShiftState), (VirtualKeyCode), (Down)) -#define ConioGetLargestConsoleWindowSize(Console, pSize) \ - (Console)->TermIFace.Vtbl->GetLargestConsoleWindowSize((Console), (pSize)) -#define ConioGetConsoleWindowHandle(Console) \ - (Console)->TermIFace.Vtbl->GetConsoleWindowHandle(Console) #define ConioRefreshInternalInfo(Console) \ (Console)->TermIFace.Vtbl->RefreshInternalInfo(Console) +#define ConioChangeTitle(Console) \ + (Console)->TermIFace.Vtbl->ChangeTitle(Console) +#define ConioChangeIcon(Console, hWindowIcon) \ + (Console)->TermIFace.Vtbl->ChangeIcon((Console), (hWindowIcon)) +#define ConioGetConsoleWindowHandle(Console) \ + (Console)->TermIFace.Vtbl->GetConsoleWindowHandle(Console) +#define ConioGetLargestConsoleWindowSize(Console, pSize) \ + (Console)->TermIFace.Vtbl->GetLargestConsoleWindowSize((Console), (pSize)) +#define ConioGetDisplayMode(Console) \ + (Console)->TermIFace.Vtbl->GetDisplayMode(Console) +#define ConioSetDisplayMode(Console, NewMode) \ + (Console)->TermIFace.Vtbl->SetDisplayMode((Console), (NewMode)) + /* EOF */ diff --git a/reactos/win32ss/user/consrv/conoutput.c b/reactos/win32ss/user/consrv/conoutput.c index 08f3cb9e9fc..d74f76dee06 100644 --- a/reactos/win32ss/user/consrv/conoutput.c +++ b/reactos/win32ss/user/consrv/conoutput.c @@ -2,7 +2,7 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Console Server DLL * FILE: win32ss/user/consrv/conoutput.c - * PURPOSE: Console Output functions + * PURPOSE: General Console Output Functions * PROGRAMMERS: Jeffrey Morlan * Hermes Belusca-Maito (hermes.belusca@sfr.fr) */ @@ -19,1238 +19,159 @@ #define NDEBUG #include -/* -// Define wmemset(...) -#include -#define HAVE_WMEMSET -*/ - - -/* GLOBALS ********************************************************************/ - -#define TAB_WIDTH 8 - -#define ConioInitRect(Rect, top, left, bottom, right) \ -do { \ - ((Rect)->Top) = top; \ - ((Rect)->Left) = left; \ - ((Rect)->Bottom) = bottom; \ - ((Rect)->Right) = right; \ -} while (0) - -#define ConioIsRectEmpty(Rect) \ - (((Rect)->Left > (Rect)->Right) || ((Rect)->Top > (Rect)->Bottom)) - -#define ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \ - WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL) - -#define ConsoleAnsiCharToUnicodeChar(Console, dWChar, sChar) \ - MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1) - /* PRIVATE FUNCTIONS **********************************************************/ -PBYTE FASTCALL -ConioCoordToPointer(PCONSOLE_SCREEN_BUFFER Buff, ULONG X, ULONG Y) -{ - return &Buff->Buffer[2 * (((Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y) * Buff->ScreenBufferSize.X + X)]; -} +NTSTATUS +TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer, + IN OUT PCONSOLE Console, + IN PTEXTMODE_BUFFER_INFO TextModeInfo); +NTSTATUS +GRAPHICS_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer, + IN OUT PCONSOLE Console, + IN PGRAPHICS_BUFFER_INFO GraphicsInfo); -static VOID FASTCALL -ClearLineBuffer(PCONSOLE_SCREEN_BUFFER Buff) -{ - PBYTE Ptr = ConioCoordToPointer(Buff, 0, Buff->CursorPosition.Y); - SHORT Pos; +VOID +TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer); +VOID +GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer); - for (Pos = 0; Pos < Buff->ScreenBufferSize.X; Pos++) - { - /* Fill the cell */ - *Ptr++ = ' '; - *Ptr++ = (BYTE)Buff->ScreenDefaultAttrib; - } -} -NTSTATUS FASTCALL -ConSrvCreateScreenBuffer(IN OUT PCONSOLE Console, - OUT PCONSOLE_SCREEN_BUFFER* Buffer, - IN COORD ScreenBufferSize, - IN USHORT ScreenAttrib, - IN USHORT PopupAttrib, - IN ULONG DisplayMode, - IN BOOLEAN IsCursorVisible, - IN ULONG CursorSize) +NTSTATUS +CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer, + IN OUT PCONSOLE Console, + IN SIZE_T Size) { - if (Console == NULL || Buffer == NULL) + if (Buffer == NULL || Console == NULL) return STATUS_INVALID_PARAMETER; - *Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(CONSOLE_SCREEN_BUFFER)); - if (NULL == *Buffer) - { - return STATUS_INSUFFICIENT_RESOURCES; - } + *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, SCREEN_BUFFER, Console); - (*Buffer)->ScreenBufferSize = ScreenBufferSize; - - (*Buffer)->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, (*Buffer)->ScreenBufferSize.X * (*Buffer)->ScreenBufferSize.Y * 2); - if (NULL == (*Buffer)->Buffer) - { - ConsoleFreeHeap(*Buffer); - return STATUS_INSUFFICIENT_RESOURCES; - } - - (*Buffer)->ShowX = 0; - (*Buffer)->ShowY = 0; - (*Buffer)->VirtualY = 0; - - (*Buffer)->CursorBlinkOn = (*Buffer)->ForceCursorOff = FALSE; - (*Buffer)->CursorInfo.bVisible = (IsCursorVisible && (CursorSize != 0)); - (*Buffer)->CursorInfo.dwSize = min(max(CursorSize, 0), 100); - - (*Buffer)->ScreenDefaultAttrib = ScreenAttrib; - (*Buffer)->PopupDefaultAttrib = PopupAttrib; - /* initialize buffer to be empty with default attributes */ - for ((*Buffer)->CursorPosition.Y = 0 ; (*Buffer)->CursorPosition.Y < (*Buffer)->ScreenBufferSize.Y; (*Buffer)->CursorPosition.Y++) - { - ClearLineBuffer(*Buffer); - } - (*Buffer)->CursorPosition.X = 0; - (*Buffer)->CursorPosition.Y = 0; - - (*Buffer)->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT; - (*Buffer)->DisplayMode = DisplayMode; - - InsertHeadList(&Console->BufferList, &(*Buffer)->ListEntry); + (*Buffer)->Vtbl = NULL; return STATUS_SUCCESS; } -static VOID FASTCALL -ConioNextLine(PCONSOLE_SCREEN_BUFFER Buff, SMALL_RECT* UpdateRect, UINT *ScrolledLines) +VOID +CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer) { - /* If we hit bottom, slide the viewable screen */ - if (++Buff->CursorPosition.Y == Buff->ScreenBufferSize.Y) - { - Buff->CursorPosition.Y--; - if (++Buff->VirtualY == Buff->ScreenBufferSize.Y) - { - Buff->VirtualY = 0; - } - (*ScrolledLines)++; - ClearLineBuffer(Buff); - if (UpdateRect->Top != 0) - { - UpdateRect->Top--; - } - } - UpdateRect->Left = 0; - UpdateRect->Right = Buff->ScreenBufferSize.X - 1; - UpdateRect->Bottom = Buff->CursorPosition.Y; + if (Buffer->Header.Type == TEXTMODE_BUFFER) + TEXTMODE_BUFFER_Destroy(Buffer); + else if (Buffer->Header.Type == GRAPHICS_BUFFER) + GRAPHICS_BUFFER_Destroy(Buffer); + else if (Buffer->Header.Type == SCREEN_BUFFER) + ConsoleFreeHeap(Buffer); + // else + // do_nothing; } NTSTATUS FASTCALL -ConioWriteConsole(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff, - CHAR *Buffer, DWORD Length, BOOL Attrib) +ConSrvCreateScreenBuffer(OUT PCONSOLE_SCREEN_BUFFER* Buffer, + IN OUT PCONSOLE Console, + IN ULONG BufferType, + IN PVOID ScreenBufferInfo) { - UINT i; - PBYTE Ptr; - SMALL_RECT UpdateRect; - SHORT CursorStartX, CursorStartY; - UINT ScrolledLines; + NTSTATUS Status = STATUS_SUCCESS; - CursorStartX = Buff->CursorPosition.X; - CursorStartY = Buff->CursorPosition.Y; - UpdateRect.Left = Buff->ScreenBufferSize.X; - UpdateRect.Top = Buff->CursorPosition.Y; - UpdateRect.Right = -1; - UpdateRect.Bottom = Buff->CursorPosition.Y; - ScrolledLines = 0; - - for (i = 0; i < Length; i++) + if ( Console == NULL || Buffer == NULL || + (BufferType != CONSOLE_TEXTMODE_BUFFER && BufferType != CONSOLE_GRAPHICS_BUFFER) ) { - /* - * If we are in processed mode, interpret special characters and - * display them correctly. Otherwise, just put them into the buffer. - */ - if (Buff->Mode & ENABLE_PROCESSED_OUTPUT) - { - /* --- CR --- */ - if (Buffer[i] == '\r') - { - Buff->CursorPosition.X = 0; - UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); - UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); - continue; - } - /* --- LF --- */ - else if (Buffer[i] == '\n') - { - Buff->CursorPosition.X = 0; - ConioNextLine(Buff, &UpdateRect, &ScrolledLines); - continue; - } - /* --- BS --- */ - else if (Buffer[i] == '\b') - { - /* Only handle BS if we're not on the first pos of the first line */ - if (0 != Buff->CursorPosition.X || 0 != Buff->CursorPosition.Y) - { - if (0 == Buff->CursorPosition.X) - { - /* slide virtual position up */ - Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1; - Buff->CursorPosition.Y--; - UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y); - } - else - { - Buff->CursorPosition.X--; - } - Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); - Ptr[0] = ' '; - Ptr[1] = (BYTE)Buff->ScreenDefaultAttrib; - UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); - UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); - } - continue; - } - /* --- TAB --- */ - else if (Buffer[i] == '\t') - { - UINT EndX; - - UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); - EndX = (Buff->CursorPosition.X + TAB_WIDTH) & ~(TAB_WIDTH - 1); - EndX = min(EndX, (UINT)Buff->ScreenBufferSize.X); - Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); - while (Buff->CursorPosition.X < EndX) - { - *Ptr++ = ' '; - *Ptr++ = (BYTE)Buff->ScreenDefaultAttrib; - Buff->CursorPosition.X++; - } - UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X - 1); - if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X) - { - if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT) - { - Buff->CursorPosition.X = 0; - ConioNextLine(Buff, &UpdateRect, &ScrolledLines); - } - else - { - Buff->CursorPosition.X--; - } - } - continue; - } - // /* --- BEL ---*/ - // else if (Buffer[i] == '\a') - // { - // // FIXME: This MUST BE moved to the terminal emulator frontend!! - // DPRINT1("Bell\n"); - // // SendNotifyMessage(Console->hWindow, PM_CONSOLE_BEEP, 0, 0); - // continue; - // } - } - UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); - UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); - Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); - Ptr[0] = Buffer[i]; - if (Attrib) - { - Ptr[1] = (BYTE)Buff->ScreenDefaultAttrib; - } - Buff->CursorPosition.X++; - if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X) - { - if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT) - { - Buff->CursorPosition.X = 0; - ConioNextLine(Buff, &UpdateRect, &ScrolledLines); - } - else - { - Buff->CursorPosition.X = CursorStartX; - } - } + return STATUS_INVALID_PARAMETER; } - if (!ConioIsRectEmpty(&UpdateRect) && Buff == Console->ActiveBuffer) + if (BufferType == CONSOLE_TEXTMODE_BUFFER) { - ConioWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY, - ScrolledLines, Buffer, Length); + Status = TEXTMODE_BUFFER_Initialize(Buffer, + Console, + (PTEXTMODE_BUFFER_INFO)ScreenBufferInfo); } - - return STATUS_SUCCESS; -} - -__inline BOOLEAN ConioGetIntersection( - SMALL_RECT* Intersection, - SMALL_RECT* Rect1, - SMALL_RECT* Rect2) -{ - if (ConioIsRectEmpty(Rect1) || - (ConioIsRectEmpty(Rect2)) || - (Rect1->Top > Rect2->Bottom) || - (Rect1->Left > Rect2->Right) || - (Rect1->Bottom < Rect2->Top) || - (Rect1->Right < Rect2->Left)) + else if (BufferType == CONSOLE_GRAPHICS_BUFFER) { - /* The rectangles do not intersect */ - ConioInitRect(Intersection, 0, -1, 0, -1); - return FALSE; - } - - ConioInitRect(Intersection, - max(Rect1->Top, Rect2->Top), - max(Rect1->Left, Rect2->Left), - min(Rect1->Bottom, Rect2->Bottom), - min(Rect1->Right, Rect2->Right)); - - return TRUE; -} - -__inline BOOLEAN ConioGetUnion( - SMALL_RECT* Union, - SMALL_RECT* Rect1, - SMALL_RECT* Rect2) -{ - if (ConioIsRectEmpty(Rect1)) - { - if (ConioIsRectEmpty(Rect2)) - { - ConioInitRect(Union, 0, -1, 0, -1); - return FALSE; - } - else - { - *Union = *Rect2; - } - } - else if (ConioIsRectEmpty(Rect2)) - { - *Union = *Rect1; + Status = GRAPHICS_BUFFER_Initialize(Buffer, + Console, + (PGRAPHICS_BUFFER_INFO)ScreenBufferInfo); } else { - ConioInitRect(Union, - min(Rect1->Top, Rect2->Top), - min(Rect1->Left, Rect2->Left), - max(Rect1->Bottom, Rect2->Bottom), - max(Rect1->Right, Rect2->Right)); + /* Never ever go there!! */ + ASSERT(FALSE); } - return TRUE; -} + /* Insert the newly created screen buffer into the list, if succeeded */ + if (NT_SUCCESS(Status)) InsertHeadList(&Console->BufferList, &(*Buffer)->ListEntry); -/* - * Move from one rectangle to another. We must be careful about the order that - * this is done, to avoid overwriting parts of the source before they are moved. - */ -static VOID FASTCALL -ConioMoveRegion(PCONSOLE_SCREEN_BUFFER ScreenBuffer, - SMALL_RECT* SrcRegion, - SMALL_RECT* DstRegion, - SMALL_RECT* ClipRegion, - WORD Fill) -{ - int Width = ConioRectWidth(SrcRegion); - int Height = ConioRectHeight(SrcRegion); - int SX, SY; - int DX, DY; - int XDelta, YDelta; - int i, j; - - SY = SrcRegion->Top; - DY = DstRegion->Top; - YDelta = 1; - if (SY < DY) - { - /* Moving down: work from bottom up */ - SY = SrcRegion->Bottom; - DY = DstRegion->Bottom; - YDelta = -1; - } - for (i = 0; i < Height; i++) - { - PWORD SRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, SY); - PWORD DRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, DY); - - SX = SrcRegion->Left; - DX = DstRegion->Left; - XDelta = 1; - if (SX < DX) - { - /* Moving right: work from right to left */ - SX = SrcRegion->Right; - DX = DstRegion->Right; - XDelta = -1; - } - for (j = 0; j < Width; j++) - { - WORD Cell = SRow[SX]; - if (SX >= ClipRegion->Left && SX <= ClipRegion->Right - && SY >= ClipRegion->Top && SY <= ClipRegion->Bottom) - { - SRow[SX] = Fill; - } - if (DX >= ClipRegion->Left && DX <= ClipRegion->Right - && DY >= ClipRegion->Top && DY <= ClipRegion->Bottom) - { - DRow[DX] = Cell; - } - SX += XDelta; - DX += XDelta; - } - SY += YDelta; - DY += YDelta; - } -} - -NTSTATUS FASTCALL -ConioResizeBuffer(PCONSOLE Console, - PCONSOLE_SCREEN_BUFFER ScreenBuffer, - COORD Size) -{ - BYTE * Buffer; - DWORD Offset = 0; - BYTE * OldPtr; - USHORT CurrentY; - BYTE * OldBuffer; -#ifdef HAVE_WMEMSET - USHORT value = MAKEWORD(' ', ScreenBuffer->ScreenDefaultAttrib); -#else - DWORD i; -#endif - DWORD diff; - - /* Buffer size is not allowed to be smaller than window size */ - if (Size.X < Console->ConsoleSize.X || Size.Y < Console->ConsoleSize.Y) - return STATUS_INVALID_PARAMETER; - - if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y) - { - // FIXME: Trigger a buffer resize event ?? - return STATUS_SUCCESS; - } - - if (!ConioIsBufferResizeSupported(Console)) return STATUS_NOT_SUPPORTED; - - Buffer = ConsoleAllocHeap(0, Size.X * Size.Y * 2); - if (!Buffer) return STATUS_NO_MEMORY; - - DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y); - OldBuffer = ScreenBuffer->Buffer; - - for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++) - { - OldPtr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY); - if (Size.X <= ScreenBuffer->ScreenBufferSize.X) - { - /* reduce size */ - RtlCopyMemory(&Buffer[Offset], OldPtr, Size.X * 2); - Offset += (Size.X * 2); - } - else - { - /* enlarge size */ - RtlCopyMemory(&Buffer[Offset], OldPtr, ScreenBuffer->ScreenBufferSize.X * 2); - Offset += (ScreenBuffer->ScreenBufferSize.X * 2); - - diff = Size.X - ScreenBuffer->ScreenBufferSize.X; - /* zero new part of it */ -#ifdef HAVE_WMEMSET - wmemset((PWCHAR)&Buffer[Offset], value, diff); -#else - for (i = 0; i < diff; i++) - { - Buffer[Offset++] = ' '; - Buffer[Offset++] = (BYTE)ScreenBuffer->ScreenDefaultAttrib; - } -#endif - } - } - - if (Size.Y > ScreenBuffer->ScreenBufferSize.Y) - { - diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y); -#ifdef HAVE_WMEMSET - wmemset((PWCHAR)&Buffer[Offset], value, diff); -#else - for (i = 0; i < diff; i++) - { - Buffer[Offset++] = ' '; - Buffer[Offset++] = (BYTE)ScreenBuffer->ScreenDefaultAttrib; - } -#endif - } - - (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer); - ConsoleFreeHeap(OldBuffer); - ScreenBuffer->ScreenBufferSize = Size; - ScreenBuffer->VirtualY = 0; - - /* Ensure cursor and window are within buffer */ - if (ScreenBuffer->CursorPosition.X >= Size.X) - ScreenBuffer->CursorPosition.X = Size.X - 1; - if (ScreenBuffer->CursorPosition.Y >= Size.Y) - ScreenBuffer->CursorPosition.Y = Size.Y - 1; - if (ScreenBuffer->ShowX > Size.X - Console->ConsoleSize.X) - ScreenBuffer->ShowX = Size.X - Console->ConsoleSize.X; - if (ScreenBuffer->ShowY > Size.Y - Console->ConsoleSize.Y) - ScreenBuffer->ShowY = Size.Y - Console->ConsoleSize.Y; - - /* - * Trigger a buffer resize event - */ - if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT) - { - INPUT_RECORD er; - - er.EventType = WINDOW_BUFFER_SIZE_EVENT; - er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize; - - ConioProcessInputEvent(Console, &er); - } - - /* TODO: Should update scrollbar, but can't use anything that - * calls SendMessage or it could cause deadlock --> Use PostMessage */ - // TODO: Tell the terminal to resize its scrollbars. - - return STATUS_SUCCESS; + return Status; } VOID WINAPI ConioDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer) { PCONSOLE Console = Buffer->Header.Console; + PCONSOLE_SCREEN_BUFFER NewBuffer; RemoveEntryList(&Buffer->ListEntry); if (Buffer == Console->ActiveBuffer) { - /* Deleted active buffer; switch to most recently created */ + /* Delete active buffer; switch to most recently created */ Console->ActiveBuffer = NULL; if (!IsListEmpty(&Console->BufferList)) { - Console->ActiveBuffer = CONTAINING_RECORD(Console->BufferList.Flink, CONSOLE_SCREEN_BUFFER, ListEntry); - ConioDrawConsole(Console); + NewBuffer = CONTAINING_RECORD(Console->BufferList.Flink, + CONSOLE_SCREEN_BUFFER, + ListEntry); + ConioSetActiveScreenBuffer(NewBuffer); } } - ConsoleFreeHeap(Buffer->Buffer); - ConsoleFreeHeap(Buffer); + CONSOLE_SCREEN_BUFFER_Destroy(Buffer); } VOID FASTCALL ConioDrawConsole(PCONSOLE Console) { SMALL_RECT Region; + PCONSOLE_SCREEN_BUFFER ActiveBuffer = Console->ActiveBuffer; - ConioInitRect(&Region, 0, 0, Console->ConsoleSize.Y - 1, Console->ConsoleSize.X - 1); - ConioDrawRegion(Console, &Region); -} - -static VOID FASTCALL -ConioComputeUpdateRect(PCONSOLE_SCREEN_BUFFER Buff, SMALL_RECT* UpdateRect, PCOORD Start, UINT Length) -{ - if (Buff->ScreenBufferSize.X <= Start->X + Length) + if (ActiveBuffer) { - UpdateRect->Left = 0; - } - else - { - UpdateRect->Left = Start->X; - } - if (Buff->ScreenBufferSize.X <= Start->X + Length) - { - UpdateRect->Right = Buff->ScreenBufferSize.X - 1; - } - else - { - UpdateRect->Right = Start->X + Length - 1; - } - UpdateRect->Top = Start->Y; - UpdateRect->Bottom = Start->Y + (Start->X + Length - 1) / Buff->ScreenBufferSize.X; - if (Buff->ScreenBufferSize.Y <= UpdateRect->Bottom) - { - UpdateRect->Bottom = Buff->ScreenBufferSize.Y - 1; + ConioInitRect(&Region, 0, 0, ActiveBuffer->ViewSize.Y - 1, ActiveBuffer->ViewSize.X - 1); + ConioDrawRegion(Console, &Region); } } -DWORD FASTCALL -ConioEffectiveCursorSize(PCONSOLE Console, DWORD Scale) +VOID FASTCALL +ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer) { - DWORD Size = (Console->ActiveBuffer->CursorInfo.dwSize * Scale + 99) / 100; - /* If line input in progress, perhaps adjust for insert toggle */ - if (Console->LineBuffer && !Console->LineComplete && Console->LineInsertToggle) - return (Size * 2 <= Scale) ? (Size * 2) : (Size / 2); - return Size; -} - -static NTSTATUS -DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage, - IN PCSR_THREAD ClientThread, - IN BOOL CreateWaitBlock OPTIONAL); - -// Wait function CSR_WAIT_FUNCTION -static BOOLEAN -WriteConsoleThread(IN PLIST_ENTRY WaitList, - IN PCSR_THREAD WaitThread, - IN PCSR_API_MESSAGE WaitApiMessage, - IN PVOID WaitContext, - IN PVOID WaitArgument1, - IN PVOID WaitArgument2, - IN ULONG WaitFlags) -{ - NTSTATUS Status; - - DPRINT("WriteConsoleThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags); - - /* - * If we are notified of the process termination via a call - * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or - * CsrDestroyThread, just return. - */ - if (WaitFlags & CsrProcessTerminating) - { - Status = STATUS_THREAD_IS_TERMINATING; - goto Quit; - } - - Status = DoWriteConsole(WaitApiMessage, - WaitThread, - FALSE); - -Quit: - if (Status != STATUS_PENDING) - { - WaitApiMessage->Status = Status; - } - - return (Status == STATUS_PENDING ? FALSE : TRUE); -} - -static NTSTATUS -DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage, - IN PCSR_THREAD ClientThread, - IN BOOL CreateWaitBlock OPTIONAL) -{ - NTSTATUS Status = STATUS_SUCCESS; - PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest; - PCONSOLE Console; - PCONSOLE_SCREEN_BUFFER Buff; - PCHAR Buffer; - DWORD Written = 0; - ULONG Length; - - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(ClientThread->Process), WriteConsoleRequest->OutputHandle, &Buff, GENERIC_WRITE, FALSE); - if (!NT_SUCCESS(Status)) return Status; - - Console = Buff->Header.Console; - - // if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) - if (Console->PauseFlags && Console->UnpauseEvent != NULL) - { - if (CreateWaitBlock) - { - if (!CsrCreateWait(&Console->WriteWaitQueue, - WriteConsoleThread, - ClientThread, - ApiMessage, - NULL, - NULL)) - { - /* Fail */ - ConSrvReleaseScreenBuffer(Buff, FALSE); - return STATUS_NO_MEMORY; - } - } - - /* Wait until we un-pause the console */ - Status = STATUS_PENDING; - } - else - { - if (WriteConsoleRequest->Unicode) - { - Length = WideCharToMultiByte(Console->OutputCodePage, 0, - (PWCHAR)WriteConsoleRequest->Buffer, - WriteConsoleRequest->NrCharactersToWrite, - NULL, 0, NULL, NULL); - Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length); - if (Buffer) - { - WideCharToMultiByte(Console->OutputCodePage, 0, - (PWCHAR)WriteConsoleRequest->Buffer, - WriteConsoleRequest->NrCharactersToWrite, - Buffer, Length, NULL, NULL); - } - else - { - Status = STATUS_NO_MEMORY; - } - } - else - { - Buffer = (PCHAR)WriteConsoleRequest->Buffer; - } - - if (Buffer) - { - if (NT_SUCCESS(Status)) - { - Status = ConioWriteConsole(Console, Buff, Buffer, - WriteConsoleRequest->NrCharactersToWrite, TRUE); - if (NT_SUCCESS(Status)) - { - Written = WriteConsoleRequest->NrCharactersToWrite; - } - } - if (WriteConsoleRequest->Unicode) - { - RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); - } - } - - WriteConsoleRequest->NrCharactersWritten = Written; - } - - ConSrvReleaseScreenBuffer(Buff, FALSE); - return Status; + PCONSOLE Console = Buffer->Header.Console; + Console->ActiveBuffer = Buffer; + ConioResizeTerminal(Console); + // ConioDrawConsole(Console); } /* PUBLIC SERVER APIS *********************************************************/ -CSR_API(SrvReadConsoleOutput) -{ - PCONSOLE_READOUTPUT ReadOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputRequest; - PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); - PCHAR_INFO CharInfo; - PCHAR_INFO CurCharInfo; - PCONSOLE_SCREEN_BUFFER Buff; - SHORT SizeX, SizeY; - NTSTATUS Status; - COORD BufferSize; - COORD BufferCoord; - SMALL_RECT ReadRegion; - SMALL_RECT ScreenRect; - DWORD i; - PBYTE Ptr; - LONG X, Y; - UINT CodePage; - - DPRINT("SrvReadConsoleOutput\n"); - - CharInfo = ReadOutputRequest->CharInfo; - ReadRegion = ReadOutputRequest->ReadRegion; - BufferSize = ReadOutputRequest->BufferSize; - BufferCoord = ReadOutputRequest->BufferCoord; - - if (!CsrValidateMessageBuffer(ApiMessage, - (PVOID*)&ReadOutputRequest->CharInfo, - BufferSize.X * BufferSize.Y, - sizeof(CHAR_INFO))) - { - return STATUS_INVALID_PARAMETER; - } - - Status = ConSrvGetScreenBuffer(ProcessData, ReadOutputRequest->OutputHandle, &Buff, GENERIC_READ, TRUE); - if (!NT_SUCCESS(Status)) return Status; - - /* FIXME: Is this correct? */ - CodePage = ProcessData->Console->OutputCodePage; - - SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&ReadRegion)); - SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&ReadRegion)); - ReadRegion.Bottom = ReadRegion.Top + SizeY; - ReadRegion.Right = ReadRegion.Left + SizeX; - - ConioInitRect(&ScreenRect, 0, 0, Buff->ScreenBufferSize.Y, Buff->ScreenBufferSize.X); - if (!ConioGetIntersection(&ReadRegion, &ScreenRect, &ReadRegion)) - { - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; - } - - for (i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y) - { - CurCharInfo = CharInfo + (i * BufferSize.X); - - Ptr = ConioCoordToPointer(Buff, ReadRegion.Left, Y); - for (X = ReadRegion.Left; X < ReadRegion.Right; ++X) - { - if (ReadOutputRequest->Unicode) - { - // ConsoleAnsiCharToUnicodeChar(ProcessData->Console, (PCHAR)Ptr++, &CurCharInfo->Char.UnicodeChar); - MultiByteToWideChar(CodePage, 0, - (PCHAR)Ptr++, 1, - &CurCharInfo->Char.UnicodeChar, 1); - } - else - { - CurCharInfo->Char.AsciiChar = *Ptr++; - } - CurCharInfo->Attributes = *Ptr++; - ++CurCharInfo; - } - } - - ConSrvReleaseScreenBuffer(Buff, TRUE); - - ReadOutputRequest->ReadRegion.Right = ReadRegion.Left + SizeX - 1; - ReadOutputRequest->ReadRegion.Bottom = ReadRegion.Top + SizeY - 1; - ReadOutputRequest->ReadRegion.Left = ReadRegion.Left; - ReadOutputRequest->ReadRegion.Top = ReadRegion.Top; - - return STATUS_SUCCESS; -} - -CSR_API(SrvWriteConsole) +CSR_API(SrvInvalidateBitMapRect) { NTSTATUS Status; - PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest; - - DPRINT("SrvWriteConsole\n"); - - if (!CsrValidateMessageBuffer(ApiMessage, - (PVOID)&WriteConsoleRequest->Buffer, - WriteConsoleRequest->BufferSize, - sizeof(BYTE))) - { - return STATUS_INVALID_PARAMETER; - } - - Status = DoWriteConsole(ApiMessage, - CsrGetClientThread(), - TRUE); - - if (Status == STATUS_PENDING) - *ReplyCode = CsrReplyPending; - - return Status; -} - -CSR_API(SrvWriteConsoleOutput) -{ - PCONSOLE_WRITEOUTPUT WriteOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputRequest; - PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); - SHORT i, X, Y, SizeX, SizeY; + PCONSOLE_INVALIDATEDIBITS InvalidateDIBitsRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.InvalidateDIBitsRequest; PCONSOLE Console; PCONSOLE_SCREEN_BUFFER Buff; - SMALL_RECT ScreenBuffer; - CHAR_INFO* CurCharInfo; - SMALL_RECT WriteRegion; - CHAR_INFO* CharInfo; - COORD BufferCoord; - COORD BufferSize; - NTSTATUS Status; - PBYTE Ptr; - DPRINT("SrvWriteConsoleOutput\n"); + DPRINT("SrvInvalidateBitMapRect\n"); - BufferSize = WriteOutputRequest->BufferSize; - BufferCoord = WriteOutputRequest->BufferCoord; - CharInfo = WriteOutputRequest->CharInfo; - - if (!CsrValidateMessageBuffer(ApiMessage, - (PVOID*)&WriteOutputRequest->CharInfo, - BufferSize.X * BufferSize.Y, - sizeof(CHAR_INFO))) - { - return STATUS_INVALID_PARAMETER; - } - - Status = ConSrvGetScreenBuffer(ProcessData, - WriteOutputRequest->OutputHandle, - &Buff, - GENERIC_WRITE, - TRUE); + Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), InvalidateDIBitsRequest->OutputHandle, &Buff, GENERIC_READ, TRUE); if (!NT_SUCCESS(Status)) return Status; Console = Buff->Header.Console; - WriteRegion = WriteOutputRequest->WriteRegion; - - SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&WriteRegion)); - SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&WriteRegion)); - WriteRegion.Bottom = WriteRegion.Top + SizeY - 1; - WriteRegion.Right = WriteRegion.Left + SizeX - 1; - - /* Make sure WriteRegion is inside the screen buffer */ - ConioInitRect(&ScreenBuffer, 0, 0, Buff->ScreenBufferSize.Y - 1, Buff->ScreenBufferSize.X - 1); - if (!ConioGetIntersection(&WriteRegion, &ScreenBuffer, &WriteRegion)) - { - ConSrvReleaseScreenBuffer(Buff, TRUE); - - /* It is okay to have a WriteRegion completely outside the screen buffer. - No data is written then. */ - return STATUS_SUCCESS; - } - - for (i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++) - { - CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X; - Ptr = ConioCoordToPointer(Buff, WriteRegion.Left, Y); - for (X = WriteRegion.Left; X <= WriteRegion.Right; X++) - { - CHAR AsciiChar; - if (WriteOutputRequest->Unicode) - { - ConsoleUnicodeCharToAnsiChar(Console, &AsciiChar, &CurCharInfo->Char.UnicodeChar); - } - else - { - AsciiChar = CurCharInfo->Char.AsciiChar; - } - *Ptr++ = AsciiChar; - *Ptr++ = (BYTE)CurCharInfo->Attributes; - CurCharInfo++; - } - } - - ConioDrawRegion(Console, &WriteRegion); - - ConSrvReleaseScreenBuffer(Buff, TRUE); - - WriteOutputRequest->WriteRegion.Right = WriteRegion.Left + SizeX - 1; - WriteOutputRequest->WriteRegion.Bottom = WriteRegion.Top + SizeY - 1; - WriteOutputRequest->WriteRegion.Left = WriteRegion.Left; - WriteOutputRequest->WriteRegion.Top = WriteRegion.Top; - - return STATUS_SUCCESS; -} - -CSR_API(SrvReadConsoleOutputString) -{ - NTSTATUS Status; - PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputCodeRequest; - PCONSOLE Console; - PCONSOLE_SCREEN_BUFFER Buff; - USHORT CodeType; - SHORT Xpos, Ypos; - PVOID ReadBuffer; - DWORD i; - ULONG CodeSize; - BYTE Code; - - DPRINT("SrvReadConsoleOutputString\n"); - - CodeType = ReadOutputCodeRequest->CodeType; - switch (CodeType) - { - case CODE_ASCII: - CodeSize = sizeof(CHAR); - break; - - case CODE_UNICODE: - CodeSize = sizeof(WCHAR); - break; - - case CODE_ATTRIBUTE: - CodeSize = sizeof(WORD); - break; - - default: - return STATUS_INVALID_PARAMETER; - } - - if (!CsrValidateMessageBuffer(ApiMessage, - (PVOID*)&ReadOutputCodeRequest->pCode.pCode, - ReadOutputCodeRequest->NumCodesToRead, - CodeSize)) - { - return STATUS_INVALID_PARAMETER; - } - - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ReadOutputCodeRequest->OutputHandle, &Buff, GENERIC_READ, TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Console = Buff->Header.Console; - - ReadBuffer = ReadOutputCodeRequest->pCode.pCode; - Xpos = ReadOutputCodeRequest->ReadCoord.X; - Ypos = (ReadOutputCodeRequest->ReadCoord.Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y; - - /* - * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) : - * - * If the number of attributes (resp. characters) to be read from extends - * beyond the end of the specified screen buffer row, attributes (resp. - * characters) are read from the next row. If the number of attributes - * (resp. characters) to be read from extends beyond the end of the console - * screen buffer, attributes (resp. characters) up to the end of the console - * screen buffer are read. - * - * TODO: Do NOT loop up to NumCodesToRead, but stop before - * if we are going to overflow... - */ - for (i = 0; i < min(ReadOutputCodeRequest->NumCodesToRead, Buff->ScreenBufferSize.X * Buff->ScreenBufferSize.Y * 2); ++i) - { - Code = Buff->Buffer[2 * (Xpos + Ypos * Buff->ScreenBufferSize.X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)]; - - switch (CodeType) - { - case CODE_UNICODE: - ConsoleAnsiCharToUnicodeChar(Console, (PWCHAR)ReadBuffer, (PCHAR)&Code); - break; - - case CODE_ASCII: - *(PCHAR)ReadBuffer = (CHAR)Code; - break; - - case CODE_ATTRIBUTE: - *(PWORD)ReadBuffer = (WORD)Code; - break; - } - ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize); - - Xpos++; - - if (Xpos == Buff->ScreenBufferSize.X) - { - Xpos = 0; - Ypos++; - - if (Ypos == Buff->ScreenBufferSize.Y) - { - Ypos = 0; - } - } - } - - // switch (CodeType) - // { - // case CODE_UNICODE: - // *(PWCHAR)ReadBuffer = 0; - // break; - - // case CODE_ASCII: - // *(PCHAR)ReadBuffer = 0; - // break; - - // case CODE_ATTRIBUTE: - // *(PWORD)ReadBuffer = 0; - // break; - // } - - ReadOutputCodeRequest->EndCoord.X = Xpos; - ReadOutputCodeRequest->EndCoord.Y = (Ypos - Buff->VirtualY + Buff->ScreenBufferSize.Y) % Buff->ScreenBufferSize.Y; - - ConSrvReleaseScreenBuffer(Buff, TRUE); - - ReadOutputCodeRequest->CodesRead = (DWORD)((ULONG_PTR)ReadBuffer - (ULONG_PTR)ReadOutputCodeRequest->pCode.pCode) / CodeSize; - // <= ReadOutputCodeRequest->NumCodesToRead - - return STATUS_SUCCESS; -} - -CSR_API(SrvWriteConsoleOutputString) -{ - NTSTATUS Status; - PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputCodeRequest; - PCONSOLE Console; - PCONSOLE_SCREEN_BUFFER Buff; - USHORT CodeType; - PBYTE Buffer; // PUCHAR - PCHAR String, tmpString = NULL; - DWORD X, Y, Length; // , Written = 0; - ULONG CodeSize; - SMALL_RECT UpdateRect; - - DPRINT("SrvWriteConsoleOutputString\n"); - - CodeType = WriteOutputCodeRequest->CodeType; - switch (CodeType) - { - case CODE_ASCII: - CodeSize = sizeof(CHAR); - break; - - case CODE_UNICODE: - CodeSize = sizeof(WCHAR); - break; - - case CODE_ATTRIBUTE: - CodeSize = sizeof(WORD); - break; - - default: - return STATUS_INVALID_PARAMETER; - } - - if (!CsrValidateMessageBuffer(ApiMessage, - (PVOID*)&WriteOutputCodeRequest->pCode.pCode, - WriteOutputCodeRequest->Length, - CodeSize)) - { - return STATUS_INVALID_PARAMETER; - } - - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - WriteOutputCodeRequest->OutputHandle, - &Buff, - GENERIC_WRITE, - TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Console = Buff->Header.Console; - - switch (CodeType) - { - case CODE_UNICODE: - { - Length = WideCharToMultiByte(Console->OutputCodePage, 0, - (PWCHAR)WriteOutputCodeRequest->pCode.UnicodeChar, - WriteOutputCodeRequest->Length, - NULL, 0, NULL, NULL); - tmpString = String = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length); - if (String) - { - WideCharToMultiByte(Console->OutputCodePage, 0, - (PWCHAR)WriteOutputCodeRequest->pCode.UnicodeChar, - WriteOutputCodeRequest->Length, - String, Length, NULL, NULL); - } - else - { - Status = STATUS_NO_MEMORY; - } - - break; - } - - case CODE_ASCII: - String = (PCHAR)WriteOutputCodeRequest->pCode.AsciiChar; - break; - - case CODE_ATTRIBUTE: - default: - // *(ReadBuffer++) = Code; - String = (PCHAR)WriteOutputCodeRequest->pCode.Attribute; - break; - } - - if (String && NT_SUCCESS(Status)) - { - X = WriteOutputCodeRequest->Coord.X; - Y = (WriteOutputCodeRequest->Coord.Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y; - Length = WriteOutputCodeRequest->Length; - Buffer = &Buff->Buffer[2 * (Y * Buff->ScreenBufferSize.X + X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)]; - - while (Length--) - { - *Buffer = *String++; - // ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize); - String = (PCHAR)((ULONG_PTR)String + CodeSize); - // Written++; - Buffer += 2; - if (++X == Buff->ScreenBufferSize.X) - { - if (++Y == Buff->ScreenBufferSize.Y) - { - Y = 0; - Buffer = Buff->Buffer + (CodeType == CODE_ATTRIBUTE ? 1 : 0); - } - X = 0; - } - } - - if (Buff == Console->ActiveBuffer) - { - ConioComputeUpdateRect(Buff, &UpdateRect, &WriteOutputCodeRequest->Coord, - WriteOutputCodeRequest->Length); - ConioDrawRegion(Console, &UpdateRect); - } - - // WriteOutputCodeRequest->EndCoord.X = X; - // WriteOutputCodeRequest->EndCoord.Y = (Y + Buff->ScreenBufferSize.Y - Buff->VirtualY) % Buff->ScreenBufferSize.Y; - } - - if (tmpString) - { - RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString); - } - - ConSrvReleaseScreenBuffer(Buff, TRUE); - - // WriteOutputCodeRequest->NrCharactersWritten = Written; - return Status; -} - -CSR_API(SrvFillConsoleOutput) -{ - NTSTATUS Status; - PCONSOLE_FILLOUTPUTCODE FillOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FillOutputRequest; - PCONSOLE Console; - PCONSOLE_SCREEN_BUFFER Buff; - DWORD X, Y, Length; // , Written = 0; - USHORT CodeType; - BYTE Code; - PBYTE Buffer; - SMALL_RECT UpdateRect; - - DPRINT("SrvFillConsoleOutput\n"); - - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), FillOutputRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Console = Buff->Header.Console; - - CodeType = FillOutputRequest->CodeType; - - X = FillOutputRequest->Coord.X; - Y = (FillOutputRequest->Coord.Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y; - Length = FillOutputRequest->Length; - Buffer = &Buff->Buffer[2 * (Y * Buff->ScreenBufferSize.X + X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)]; - - switch (CodeType) - { - case CODE_ASCII: - Code = (BYTE)FillOutputRequest->Code.AsciiChar; - break; - - case CODE_UNICODE: - ConsoleUnicodeCharToAnsiChar(Console, (PCHAR)&Code, &FillOutputRequest->Code.UnicodeChar); - break; - - case CODE_ATTRIBUTE: - Code = (BYTE)FillOutputRequest->Code.Attribute; - break; - - default: - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_INVALID_PARAMETER; - } - - while (Length--) - { - *Buffer = Code; - Buffer += 2; - // Written++; - if (++X == Buff->ScreenBufferSize.X) - { - if (++Y == Buff->ScreenBufferSize.Y) - { - Y = 0; - Buffer = Buff->Buffer + (CodeType == CODE_ATTRIBUTE ? 1 : 0); - } - X = 0; - } - } - + /* If the output buffer is the current one, redraw the correct portion of the screen */ if (Buff == Console->ActiveBuffer) - { - ConioComputeUpdateRect(Buff, &UpdateRect, &FillOutputRequest->Coord, - FillOutputRequest->Length); - ConioDrawRegion(Console, &UpdateRect); - } + ConioDrawRegion(Console, &InvalidateDIBitsRequest->Region); ConSrvReleaseScreenBuffer(Buff, TRUE); -/* - Length = FillOutputRequest->Length; - FillOutputRequest->NrCharactersWritten = Length; -*/ return STATUS_SUCCESS; } @@ -1262,11 +183,11 @@ CSR_API(SrvGetConsoleCursorInfo) DPRINT("SrvGetConsoleCursorInfo\n"); - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), CursorInfoRequest->OutputHandle, &Buff, GENERIC_READ, TRUE); + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), CursorInfoRequest->OutputHandle, &Buff, GENERIC_READ, TRUE); if (!NT_SUCCESS(Status)) return Status; CursorInfoRequest->Info.bVisible = Buff->CursorInfo.bVisible; - CursorInfoRequest->Info.dwSize = Buff->CursorInfo.dwSize; + CursorInfoRequest->Info.dwSize = Buff->CursorInfo.dwSize; ConSrvReleaseScreenBuffer(Buff, TRUE); return STATUS_SUCCESS; @@ -1279,47 +200,37 @@ CSR_API(SrvSetConsoleCursorInfo) PCONSOLE Console; PCONSOLE_SCREEN_BUFFER Buff; DWORD Size; - BOOL Visible; + BOOL Visible, Success = TRUE; DPRINT("SrvSetConsoleCursorInfo\n"); - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), CursorInfoRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE); + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), CursorInfoRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE); if (!NT_SUCCESS(Status)) return Status; Console = Buff->Header.Console; - Size = CursorInfoRequest->Info.dwSize; + Size = CursorInfoRequest->Info.dwSize; Visible = CursorInfoRequest->Info.bVisible; - if (Size < 1) - { - Size = 1; - } - if (100 < Size) - { - Size = 100; - } + if (Size < 1) Size = 1; + if (100 < Size) Size = 100; - if ( (Size != Buff->CursorInfo.dwSize) || - (Visible && ! Buff->CursorInfo.bVisible) || - (! Visible && Buff->CursorInfo.bVisible) ) + if ( (Size != Buff->CursorInfo.dwSize) || + (Visible && !Buff->CursorInfo.bVisible) || + (!Visible && Buff->CursorInfo.bVisible) ) { - Buff->CursorInfo.dwSize = Size; + Buff->CursorInfo.dwSize = Size; Buff->CursorInfo.bVisible = Visible; - if (!ConioSetCursorInfo(Console, Buff)) - { - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_UNSUCCESSFUL; - } + Success = ConioSetCursorInfo(Console, Buff); } ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; + return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); } CSR_API(SrvSetConsoleCursorPosition) { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; PCONSOLE_SETCURSORPOSITION SetCursorPositionRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorPositionRequest; PCONSOLE Console; PCONSOLE_SCREEN_BUFFER Buff; @@ -1328,7 +239,7 @@ CSR_API(SrvSetConsoleCursorPosition) DPRINT("SrvSetConsoleCursorPosition\n"); - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetCursorPositionRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE); + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetCursorPositionRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE); if (!NT_SUCCESS(Status)) return Status; Console = Buff->Header.Console; @@ -1338,8 +249,8 @@ CSR_API(SrvSetConsoleCursorPosition) if ( NewCursorX < 0 || NewCursorX >= Buff->ScreenBufferSize.X || NewCursorY < 0 || NewCursorY >= Buff->ScreenBufferSize.Y ) { - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_INVALID_PARAMETER; + Status = STATUS_INVALID_PARAMETER; + goto Quit; } OldCursorX = Buff->CursorPosition.X; OldCursorY = Buff->CursorPosition.Y; @@ -1349,150 +260,136 @@ CSR_API(SrvSetConsoleCursorPosition) { if (!ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY)) { - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_UNSUCCESSFUL; + Status = STATUS_UNSUCCESSFUL; + goto Quit; } } +Quit: ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; -} - -CSR_API(SrvSetConsoleTextAttribute) -{ - NTSTATUS Status; - PCONSOLE_SETTEXTATTRIB SetTextAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetTextAttribRequest; - PCONSOLE Console; - PCONSOLE_SCREEN_BUFFER Buff; - - DPRINT("SrvSetConsoleTextAttribute\n"); - - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetTextAttribRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Console = Buff->Header.Console; - - Buff->ScreenDefaultAttrib = SetTextAttribRequest->Attrib; - if (Buff == Console->ActiveBuffer) - { - if (!ConioUpdateScreenInfo(Console, Buff)) - { - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_UNSUCCESSFUL; - } - } - - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; + return Status; } CSR_API(SrvCreateConsoleScreenBuffer) { - NTSTATUS Status; + NTSTATUS Status = STATUS_INVALID_PARAMETER; PCONSOLE_CREATESCREENBUFFER CreateScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CreateScreenBufferRequest; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); PCONSOLE Console; PCONSOLE_SCREEN_BUFFER Buff; - COORD ScreenBufferSize = {80, 25}; - USHORT ScreenAttrib = DEFAULT_SCREEN_ATTRIB; - USHORT PopupAttrib = DEFAULT_POPUP_ATTRIB; - ULONG DisplayMode = CONSOLE_WINDOWED_MODE; - BOOLEAN IsCursorVisible = TRUE; - ULONG CursorSize = CSR_DEFAULT_CURSOR_SIZE; + PVOID ScreenBufferInfo = NULL; + TEXTMODE_BUFFER_INFO TextModeInfo = {{80, 25}, + DEFAULT_SCREEN_ATTRIB, + DEFAULT_POPUP_ATTRIB , + TRUE, + CSR_DEFAULT_CURSOR_SIZE}; + GRAPHICS_BUFFER_INFO GraphicsInfo; + GraphicsInfo.Info = CreateScreenBufferRequest->GraphicsBufferInfo; // HACK for MSVC DPRINT("SrvCreateConsoleScreenBuffer\n"); Status = ConSrvGetConsole(ProcessData, &Console, TRUE); if (!NT_SUCCESS(Status)) return Status; - /* - if (Console->ActiveBuffer) + if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_TEXTMODE_BUFFER) { - ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize; - if (ScreenBufferSize.X == 0) ScreenBufferSize.X = 80; - if (ScreenBufferSize.Y == 0) ScreenBufferSize.Y = 25; - - ScreenAttrib = Console->ActiveBuffer->ScreenDefaultAttrib; - PopupAttrib = Console->ActiveBuffer->PopupDefaultAttrib; - - IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible; - CursorSize = Console->ActiveBuffer->CursorInfo.dwSize; - } - */ - - // This is Windows' behaviour - { - ScreenBufferSize = Console->ConsoleSize; // Use the current console size - if (ScreenBufferSize.X == 0) ScreenBufferSize.X = 1; - if (ScreenBufferSize.Y == 0) ScreenBufferSize.Y = 1; + ScreenBufferInfo = &TextModeInfo; + /* if (Console->ActiveBuffer) { - ScreenAttrib = Console->ActiveBuffer->ScreenDefaultAttrib; - PopupAttrib = Console->ActiveBuffer->PopupDefaultAttrib; - DisplayMode = Console->ActiveBuffer->DisplayMode; + TextModeInfo.ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize; + if (TextModeInfo.ScreenBufferSize.X == 0) TextModeInfo.ScreenBufferSize.X = 80; + if (TextModeInfo.ScreenBufferSize.Y == 0) TextModeInfo.ScreenBufferSize.Y = 25; - IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible; - CursorSize = Console->ActiveBuffer->CursorInfo.dwSize; + TextModeInfo.ScreenAttrib = Console->ActiveBuffer->ScreenBuffer.TextBuffer.ScreenDefaultAttrib; + TextModeInfo.PopupAttrib = Console->ActiveBuffer->ScreenBuffer.TextBuffer.PopupDefaultAttrib; + + TextModeInfo.IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible; + TextModeInfo.CursorSize = Console->ActiveBuffer->CursorInfo.dwSize; + } + */ + + /* + * This is Windows' behaviour + */ + + /* Use the current console size. Regularize it if needed. */ + TextModeInfo.ScreenBufferSize = Console->ConsoleSize; + if (TextModeInfo.ScreenBufferSize.X == 0) TextModeInfo.ScreenBufferSize.X = 1; + if (TextModeInfo.ScreenBufferSize.Y == 0) TextModeInfo.ScreenBufferSize.Y = 1; + + /* If we have an active screen buffer, use its attributes as the new ones */ + if (Console->ActiveBuffer && GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER) + { + PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)Console->ActiveBuffer; + + TextModeInfo.ScreenAttrib = Buffer->ScreenDefaultAttrib; + TextModeInfo.PopupAttrib = Buffer->PopupDefaultAttrib; + + TextModeInfo.IsCursorVisible = Buffer->CursorInfo.bVisible; + TextModeInfo.CursorSize = Buffer->CursorInfo.dwSize; } } - - Status = ConSrvCreateScreenBuffer(Console, - &Buff, - ScreenBufferSize, - ScreenAttrib, - PopupAttrib, - DisplayMode, - IsCursorVisible, - CursorSize); - if (NT_SUCCESS(Status)) + else if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_GRAPHICS_BUFFER) { - RtlEnterCriticalSection(&ProcessData->HandleTableLock); + /* Get infos from the graphics buffer information structure */ + if (!CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMapInfo, + 1, + CreateScreenBufferRequest->GraphicsBufferInfo.dwBitMapInfoLength)) + { + Status = STATUS_INVALID_PARAMETER; + goto Quit; + } - /* Insert the new handle inside the process handles table */ - Status = ConSrvInsertObject(ProcessData, - &CreateScreenBufferRequest->OutputHandle, - &Buff->Header, - CreateScreenBufferRequest->Access, - CreateScreenBufferRequest->Inheritable, - CreateScreenBufferRequest->ShareMode); + ScreenBufferInfo = &GraphicsInfo; - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + /* Initialize shared variables */ + CreateScreenBufferRequest->GraphicsBufferInfo.hMutex = GraphicsInfo.Info.hMutex = INVALID_HANDLE_VALUE; + CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMap = GraphicsInfo.Info.lpBitMap = NULL; + + /* A graphics screen buffer is never inheritable */ + CreateScreenBufferRequest->Inheritable = FALSE; } + Status = ConSrvCreateScreenBuffer(&Buff, + Console, + CreateScreenBufferRequest->ScreenBufferType, + ScreenBufferInfo); + if (!NT_SUCCESS(Status)) goto Quit; + + /* Insert the new handle inside the process handles table */ + RtlEnterCriticalSection(&ProcessData->HandleTableLock); + + Status = ConSrvInsertObject(ProcessData, + &CreateScreenBufferRequest->OutputHandle, + &Buff->Header, + CreateScreenBufferRequest->Access, + CreateScreenBufferRequest->Inheritable, + CreateScreenBufferRequest->ShareMode); + + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + + if (!NT_SUCCESS(Status)) goto Quit; + + if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_GRAPHICS_BUFFER) + { + PGRAPHICS_SCREEN_BUFFER Buffer = (PGRAPHICS_SCREEN_BUFFER)Buff; + /* + * Initialize the graphics buffer information structure + * and give it back to the client. + */ + CreateScreenBufferRequest->GraphicsBufferInfo.hMutex = Buffer->ClientMutex; + CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMap = Buffer->ClientBitMap; + } + +Quit: ConSrvReleaseConsole(Console, TRUE); return Status; } -CSR_API(SrvGetConsoleScreenBufferInfo) -{ - NTSTATUS Status; - PCONSOLE_GETSCREENBUFFERINFO ScreenBufferInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScreenBufferInfoRequest; - PCONSOLE Console; - PCONSOLE_SCREEN_BUFFER Buff; - PCONSOLE_SCREEN_BUFFER_INFO pInfo = &ScreenBufferInfoRequest->Info; - - DPRINT("SrvGetConsoleScreenBufferInfo\n"); - - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ScreenBufferInfoRequest->OutputHandle, &Buff, GENERIC_READ, TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Console = Buff->Header.Console; - - pInfo->dwSize = Buff->ScreenBufferSize; - pInfo->dwCursorPosition = Buff->CursorPosition; - pInfo->wAttributes = Buff->ScreenDefaultAttrib; - pInfo->srWindow.Left = Buff->ShowX; - pInfo->srWindow.Right = Buff->ShowX + Console->ConsoleSize.X - 1; - pInfo->srWindow.Top = Buff->ShowY; - pInfo->srWindow.Bottom = Buff->ShowY + Console->ConsoleSize.Y - 1; - pInfo->dwMaximumWindowSize = Buff->ScreenBufferSize; - - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; -} - CSR_API(SrvSetConsoleActiveScreenBuffer) { NTSTATUS Status; @@ -1507,11 +404,7 @@ CSR_API(SrvSetConsoleActiveScreenBuffer) Console = Buff->Header.Console; - if (Buff == Console->ActiveBuffer) - { - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; - } + if (Buff == Console->ActiveBuffer) goto Quit; /* If old buffer has no handles, it's now unreferenced */ if (Console->ActiveBuffer->Header.HandleCount == 0) @@ -1520,119 +413,11 @@ CSR_API(SrvSetConsoleActiveScreenBuffer) } /* Tie console to new buffer */ - Console->ActiveBuffer = Buff; - - /* Redraw the console */ - ConioDrawConsole(Console); + ConioSetActiveScreenBuffer(Buff); +Quit: ConSrvReleaseScreenBuffer(Buff, TRUE); return STATUS_SUCCESS; } -CSR_API(SrvScrollConsoleScreenBuffer) -{ - PCONSOLE_SCROLLSCREENBUFFER ScrollScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScrollScreenBufferRequest; - PCONSOLE Console; - PCONSOLE_SCREEN_BUFFER Buff; - SMALL_RECT ScreenBuffer; - SMALL_RECT SrcRegion; - SMALL_RECT DstRegion; - SMALL_RECT UpdateRegion; - SMALL_RECT ScrollRectangle; - SMALL_RECT ClipRectangle; - NTSTATUS Status; - HANDLE OutputHandle; - BOOLEAN UseClipRectangle; - COORD DestinationOrigin; - CHAR_INFO Fill; - CHAR FillChar; - - DPRINT("SrvScrollConsoleScreenBuffer\n"); - - OutputHandle = ScrollScreenBufferRequest->OutputHandle; - UseClipRectangle = ScrollScreenBufferRequest->UseClipRectangle; - DestinationOrigin = ScrollScreenBufferRequest->DestinationOrigin; - Fill = ScrollScreenBufferRequest->Fill; - - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), OutputHandle, &Buff, GENERIC_WRITE, TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Console = Buff->Header.Console; - - ScrollRectangle = ScrollScreenBufferRequest->ScrollRectangle; - - /* Make sure source rectangle is inside the screen buffer */ - ConioInitRect(&ScreenBuffer, 0, 0, Buff->ScreenBufferSize.Y - 1, Buff->ScreenBufferSize.X - 1); - if (!ConioGetIntersection(&SrcRegion, &ScreenBuffer, &ScrollRectangle)) - { - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; - } - - /* If the source was clipped on the left or top, adjust the destination accordingly */ - if (ScrollRectangle.Left < 0) - { - DestinationOrigin.X -= ScrollRectangle.Left; - } - if (ScrollRectangle.Top < 0) - { - DestinationOrigin.Y -= ScrollRectangle.Top; - } - - if (UseClipRectangle) - { - ClipRectangle = ScrollScreenBufferRequest->ClipRectangle; - if (!ConioGetIntersection(&ClipRectangle, &ClipRectangle, &ScreenBuffer)) - { - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; - } - } - else - { - ClipRectangle = ScreenBuffer; - } - - ConioInitRect(&DstRegion, - DestinationOrigin.Y, - DestinationOrigin.X, - DestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1, - DestinationOrigin.X + ConioRectWidth(&SrcRegion) - 1); - - if (ScrollScreenBufferRequest->Unicode) - ConsoleUnicodeCharToAnsiChar(Console, &FillChar, &Fill.Char.UnicodeChar); - else - FillChar = Fill.Char.AsciiChar; - - ConioMoveRegion(Buff, &SrcRegion, &DstRegion, &ClipRectangle, Fill.Attributes << 8 | (BYTE)FillChar); - - if (Buff == Console->ActiveBuffer) - { - ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion); - if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &ClipRectangle)) - { - /* Draw update region */ - ConioDrawRegion(Console, &UpdateRegion); - } - } - - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; -} - -CSR_API(SrvSetConsoleScreenBufferSize) -{ - NTSTATUS Status; - PCONSOLE_SETSCREENBUFFERSIZE SetScreenBufferSizeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferSizeRequest; - PCONSOLE_SCREEN_BUFFER Buff; - - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetScreenBufferSizeRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Status = ConioResizeBuffer(Buff->Header.Console, Buff, SetScreenBufferSizeRequest->Size); - - ConSrvReleaseScreenBuffer(Buff, TRUE); - return Status; -} - /* EOF */ diff --git a/reactos/win32ss/user/consrv/conoutput.h b/reactos/win32ss/user/consrv/conoutput.h index 6a903d5fa65..f10320b53db 100644 --- a/reactos/win32ss/user/consrv/conoutput.h +++ b/reactos/win32ss/user/consrv/conoutput.h @@ -9,23 +9,35 @@ #pragma once +#define ConSrvGetTextModeBuffer(ProcessData, Handle, Ptr, Access, LockConsole) \ + ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), NULL, \ + (Access), (LockConsole), TEXTMODE_BUFFER) +#define ConSrvGetTextModeBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \ + ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \ + (Access), (LockConsole), TEXTMODE_BUFFER) + +#define ConSrvGetGraphicsBuffer(ProcessData, Handle, Ptr, Access, LockConsole) \ + ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), NULL, \ + (Access), (LockConsole), GRAPHICS_BUFFER) +#define ConSrvGetGraphicsBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \ + ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \ + (Access), (LockConsole), GRAPHICS_BUFFER) + #define ConSrvGetScreenBuffer(ProcessData, Handle, Ptr, Access, LockConsole) \ ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), NULL, \ (Access), (LockConsole), SCREEN_BUFFER) #define ConSrvGetScreenBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \ ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \ (Access), (LockConsole), SCREEN_BUFFER) + #define ConSrvReleaseScreenBuffer(Buff, IsConsoleLocked) \ ConSrvReleaseObject(&(Buff)->Header, (IsConsoleLocked)) -NTSTATUS FASTCALL ConSrvCreateScreenBuffer(IN OUT PCONSOLE Console, - OUT PCONSOLE_SCREEN_BUFFER* Buffer, - IN COORD ScreenBufferSize, - IN USHORT ScreenAttrib, - IN USHORT PopupAttrib, - IN ULONG DisplayMode, - IN BOOLEAN IsCursorVisible, - IN ULONG CursorSize); +NTSTATUS FASTCALL ConSrvCreateScreenBuffer(OUT PCONSOLE_SCREEN_BUFFER* Buffer, + IN OUT PCONSOLE Console, + IN ULONG BufferType, + IN PVOID ScreenBufferInfo); VOID WINAPI ConioDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer); +VOID FASTCALL ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer); /* EOF */ diff --git a/reactos/win32ss/user/consrv/console.c b/reactos/win32ss/user/consrv/console.c index 34ca2d5ad2b..8b0330ac779 100644 --- a/reactos/win32ss/user/consrv/console.c +++ b/reactos/win32ss/user/consrv/console.c @@ -479,9 +479,10 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole, { NTSTATUS Status; SECURITY_ATTRIBUTES SecurityAttributes; - CONSOLE_INFO ConsoleInfo; SIZE_T Length = 0; DWORD ProcessId = HandleToUlong(ConsoleLeaderProcess->ClientId.UniqueProcess); + CONSOLE_INFO ConsoleInfo; + TEXTMODE_BUFFER_INFO ScreenBufferInfo; PCONSOLE Console; PCONSOLE_SCREEN_BUFFER NewBuffer; BOOL GuiMode; @@ -564,14 +565,17 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole, ConsoleInfo.ConsoleSize.X = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cx; ConsoleInfo.ConsoleSize.Y = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cy; } - /* - if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN) - { - ConsoleInfo.FullScreen = TRUE; - } - */ } + /* + * Fix the screen buffer size if needed. The rule is: + * ScreenBufferSize >= ConsoleSize + */ + if (ConsoleInfo.ScreenBufferSize.X < ConsoleInfo.ConsoleSize.X) + ConsoleInfo.ScreenBufferSize.X = ConsoleInfo.ConsoleSize.X; + if (ConsoleInfo.ScreenBufferSize.Y < ConsoleInfo.ConsoleSize.Y) + ConsoleInfo.ScreenBufferSize.Y = ConsoleInfo.ConsoleSize.Y; + /* * Initialize the console */ @@ -583,6 +587,7 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole, memcpy(Console->Colors, ConsoleInfo.Colors, sizeof(ConsoleInfo.Colors)); Console->ConsoleSize = ConsoleInfo.ConsoleSize; + Console->FixedSize = FALSE; // Value by default; is reseted by the front-ends if needed. /* * Initialize the input buffer @@ -618,17 +623,18 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole, Console->CodePage = GetOEMCP(); Console->OutputCodePage = GetOEMCP(); - /* Initialize a new screen buffer with default settings */ + /* Initialize a new text-mode screen buffer with default settings */ + ScreenBufferInfo.ScreenBufferSize = ConsoleInfo.ScreenBufferSize; + ScreenBufferInfo.ScreenAttrib = ConsoleInfo.ScreenAttrib; + ScreenBufferInfo.PopupAttrib = ConsoleInfo.PopupAttrib; + ScreenBufferInfo.IsCursorVisible = TRUE; + ScreenBufferInfo.CursorSize = ConsoleInfo.CursorSize; + InitializeListHead(&Console->BufferList); - Status = ConSrvCreateScreenBuffer(Console, - &NewBuffer, - ConsoleInfo.ScreenBufferSize, - ConsoleInfo.ScreenAttrib, - ConsoleInfo.PopupAttrib, - (ConsoleInfo.FullScreen ? CONSOLE_FULLSCREEN_MODE - : CONSOLE_WINDOWED_MODE), - TRUE, - ConsoleInfo.CursorSize); + Status = ConSrvCreateScreenBuffer(&NewBuffer, + Console, + CONSOLE_TEXTMODE_BUFFER, + &ScreenBufferInfo); if (!NT_SUCCESS(Status)) { DPRINT1("ConSrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status); @@ -642,7 +648,6 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole, InitializeListHead(&Console->WriteWaitQueue); Console->PauseFlags = 0; Console->UnpauseEvent = NULL; - // HardwareState /* * Initialize the alias and history buffers @@ -1043,7 +1048,7 @@ CSR_API(SrvGetConsoleMode) ConsoleModeRequest->ConsoleMode = ConsoleMode; } - else if (SCREEN_BUFFER == Object->Type) + else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type) { PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object; ConsoleModeRequest->ConsoleMode = Buffer->Mode; @@ -1115,7 +1120,7 @@ CSR_API(SrvSetConsoleMode) } InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES); } - else if (SCREEN_BUFFER == Object->Type) + else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type) { PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object; @@ -1242,6 +1247,7 @@ CSR_API(SrvSetConsoleTitle) * ConsoleHwState has the correct size to be compatible * with NT's, but values are not. */ +#if 0 static NTSTATUS FASTCALL SetConsoleHardwareState(PCONSOLE Console, ULONG ConsoleHwState) { @@ -1262,15 +1268,17 @@ SetConsoleHardwareState(PCONSOLE Console, ULONG ConsoleHwState) return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */ } +#endif CSR_API(SrvGetConsoleHardwareState) { +#if 0 NTSTATUS Status; PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest; PCONSOLE_SCREEN_BUFFER Buff; PCONSOLE Console; - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), HardwareStateRequest->OutputHandle, &Buff, GENERIC_READ, @@ -1286,16 +1294,21 @@ CSR_API(SrvGetConsoleHardwareState) ConSrvReleaseScreenBuffer(Buff, TRUE); return Status; +#else + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +#endif } CSR_API(SrvSetConsoleHardwareState) { +#if 0 NTSTATUS Status; PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest; PCONSOLE_SCREEN_BUFFER Buff; PCONSOLE Console; - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), HardwareStateRequest->OutputHandle, &Buff, GENERIC_WRITE, @@ -1312,6 +1325,10 @@ CSR_API(SrvSetConsoleHardwareState) ConSrvReleaseScreenBuffer(Buff, TRUE); return Status; +#else + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +#endif } CSR_API(SrvGetConsoleDisplayMode) @@ -1319,7 +1336,6 @@ CSR_API(SrvGetConsoleDisplayMode) NTSTATUS Status; PCONSOLE_GETDISPLAYMODE GetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetDisplayModeRequest; PCONSOLE Console; - ULONG DisplayMode = 0; Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); @@ -1329,22 +1345,17 @@ CSR_API(SrvGetConsoleDisplayMode) return Status; } - if (Console->ActiveBuffer->DisplayMode & CONSOLE_FULLSCREEN_MODE) - DisplayMode |= CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN - else if (Console->ActiveBuffer->DisplayMode & CONSOLE_WINDOWED_MODE) - DisplayMode |= CONSOLE_WINDOWED; - - GetDisplayModeRequest->DisplayMode = DisplayMode; - Status = STATUS_SUCCESS; + GetDisplayModeRequest->DisplayMode = ConioGetDisplayMode(Console); ConSrvReleaseConsole(Console, TRUE); - return Status; + return STATUS_SUCCESS; } CSR_API(SrvSetConsoleDisplayMode) { NTSTATUS Status; PCONSOLE_SETDISPLAYMODE SetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetDisplayModeRequest; + PCONSOLE Console; PCONSOLE_SCREEN_BUFFER Buff; Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), @@ -1358,17 +1369,16 @@ CSR_API(SrvSetConsoleDisplayMode) return Status; } - if (SetDisplayModeRequest->DisplayMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE)) + Console = Buff->Header.Console; + + if (ConioSetDisplayMode(Console, SetDisplayModeRequest->DisplayMode)) { - Status = STATUS_INVALID_PARAMETER; + SetDisplayModeRequest->NewSBDim = Buff->ScreenBufferSize; + Status = STATUS_SUCCESS; } else { - Buff->DisplayMode = SetDisplayModeRequest->DisplayMode; - // TODO: Change the display mode - SetDisplayModeRequest->NewSBDim = Buff->ScreenBufferSize; - - Status = STATUS_SUCCESS; + Status = STATUS_INVALID_PARAMETER; } ConSrvReleaseScreenBuffer(Buff, TRUE); @@ -1382,7 +1392,7 @@ CSR_API(SrvGetLargestConsoleWindowSize) PCONSOLE_SCREEN_BUFFER Buff; PCONSOLE Console; - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), GetLargestWindowSizeRequest->OutputHandle, &Buff, GENERIC_READ, @@ -1398,62 +1408,50 @@ CSR_API(SrvGetLargestConsoleWindowSize) CSR_API(SrvSetConsoleWindowInfo) { -#if 0 NTSTATUS Status; -#endif PCONSOLE_SETWINDOWINFO SetWindowInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetWindowInfoRequest; -#if 0 PCONSOLE_SCREEN_BUFFER Buff; - PCONSOLE Console; -#endif SMALL_RECT WindowRect = SetWindowInfoRequest->WindowRect; -#if 0 - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - SetWindowInfoRequest->OutputHandle, - &Buff, - GENERIC_READ, - TRUE); - if (!NT_SUCCESS(Status)) return Status; + DPRINT("SrvSetConsoleWindowInfo(0x%08x, %d, {L%d, T%d, R%d, B%d}) called\n", + SetWindowInfoRequest->OutputHandle, SetWindowInfoRequest->Absolute, + WindowRect.Left, WindowRect.Top, WindowRect.Right, WindowRect.Bottom); - Console = Buff->Header.Console; + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + SetWindowInfoRequest->OutputHandle, + &Buff, + GENERIC_READ, + TRUE); + if (!NT_SUCCESS(Status)) return Status; if (SetWindowInfoRequest->Absolute == FALSE) { /* Relative positions given. Transform them to absolute ones */ - WindowRect.Left += Buff->ShowX; - WindowRect.Top += Buff->ShowY; - WindowRect.Right += Buff->ShowX + Console->ConsoleSize.X - 1; - WindowRect.Bottom += Buff->ShowY + Console->ConsoleSize.Y - 1; + WindowRect.Left += Buff->ViewOrigin.X; + WindowRect.Top += Buff->ViewOrigin.Y; + WindowRect.Right += Buff->ViewOrigin.X + Buff->ViewSize.X - 1; + WindowRect.Bottom += Buff->ViewOrigin.Y + Buff->ViewSize.Y - 1; } - if ( (WindowRect.Left < 0) || (WindowRect.Top < 0) || - (WindowRect.Right > ScreenBufferSize.X) || - (WindowRect.Bottom > ScreenBufferSize.Y) || - (WindowRect.Right <= WindowRect.Left) || + /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */ + if ( (WindowRect.Left < 0) || (WindowRect.Top < 0) || + (WindowRect.Right >= Buff->ScreenBufferSize.X) || + (WindowRect.Bottom >= Buff->ScreenBufferSize.Y) || + (WindowRect.Right <= WindowRect.Left) || (WindowRect.Bottom <= WindowRect.Top) ) { ConSrvReleaseScreenBuffer(Buff, TRUE); return STATUS_INVALID_PARAMETER; } - Buff->ShowX = WindowRect.Left; - Buff->ShowY = WindowRect.Top; + Buff->ViewOrigin.X = WindowRect.Left; + Buff->ViewOrigin.Y = WindowRect.Top; - // These two lines are frontend-specific. - Console->ConsoleSize.X = WindowRect.Right - WindowRect.Left + 1; - Console->ConsoleSize.Y = WindowRect.Bottom - WindowRect.Top + 1; - - // ConioGetLargestConsoleWindowSize(Console, &GetLargestWindowSizeRequest->Size); + Buff->ViewSize.X = WindowRect.Right - WindowRect.Left + 1; + Buff->ViewSize.Y = WindowRect.Bottom - WindowRect.Top + 1; ConSrvReleaseScreenBuffer(Buff, TRUE); return STATUS_SUCCESS; -#else - DPRINT1("SrvSetConsoleWindowInfo(0x%08x, %d, {L%d, T%d, R%d, B%d}) UNIMPLEMENTED\n", - SetWindowInfoRequest->OutputHandle, SetWindowInfoRequest->Absolute, - WindowRect.Left, WindowRect.Top, WindowRect.Right, WindowRect.Bottom); - return STATUS_NOT_IMPLEMENTED; -#endif } CSR_API(SrvGetConsoleWindow) diff --git a/reactos/win32ss/user/consrv/consrv.h b/reactos/win32ss/user/consrv/consrv.h index ec9b9aa3fc2..335bdc510fc 100644 --- a/reactos/win32ss/user/consrv/consrv.h +++ b/reactos/win32ss/user/consrv/consrv.h @@ -24,6 +24,7 @@ #include #include #define NTOS_MODE_USER +#include #include #include #include diff --git a/reactos/win32ss/user/consrv/frontends/gui/graphics.c b/reactos/win32ss/user/consrv/frontends/gui/graphics.c new file mode 100644 index 00000000000..43df51cffa1 --- /dev/null +++ b/reactos/win32ss/user/consrv/frontends/gui/graphics.c @@ -0,0 +1,81 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Console Server DLL + * FILE: win32ss/user/consrv/frontends/gui/graphics.c + * PURPOSE: GUI Terminal Front-End - Support for graphics-mode screen-buffers + * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr) + */ + +/* INCLUDES *******************************************************************/ + +#include "consrv.h" +#include "include/conio.h" +#include "include/settings.h" +#include "guisettings.h" + +#define NDEBUG +#include + + +/* FUNCTIONS ******************************************************************/ + +VOID +GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer) +{ + /* + * This function supposes that the system clipboard was opened. + */ + + // PCONSOLE Console = Buffer->Header.Console; + + UNIMPLEMENTED; +} + +VOID +GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer) +{ + /* + * This function supposes that the system clipboard was opened. + */ + + // PCONSOLE Console = Buffer->Header.Console; + + UNIMPLEMENTED; +} + +VOID +GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer, + PGUI_CONSOLE_DATA GuiData, + HDC hDC, + PRECT rc) +{ + if (Buffer->BitMap == NULL) return; + + /* Grab the mutex */ + NtWaitForSingleObject(Buffer->Mutex, FALSE, NULL); + + /* + * The seventh parameter (YSrc) of SetDIBitsToDevice always designates + * the Y-coordinate of the "lower-left corner" of the image, be the DIB + * in bottom-up or top-down mode. + */ + SetDIBitsToDevice(hDC, + /* Coordinates / size of the repainted rectangle, in the view's frame */ + rc->left, + rc->top, + rc->right - rc->left, + rc->bottom - rc->top, + /* Coordinates / size of the corresponding image portion, in the graphics screen-buffer's frame */ + Buffer->ViewOrigin.X + rc->left, + Buffer->ViewOrigin.Y + rc->top, + 0, + Buffer->ScreenBufferSize.Y, // == Buffer->BitMapInfo->bmiHeader.biHeight + Buffer->BitMap, + Buffer->BitMapInfo, + Buffer->BitMapUsage); + + /* Release the mutex */ + NtReleaseMutant(Buffer->Mutex, NULL); +} + +/* EOF */ diff --git a/reactos/win32ss/user/consrv/frontends/gui/guisettings.c b/reactos/win32ss/user/consrv/frontends/gui/guisettings.c index 8a143d2e334..7b9a72b17a1 100644 --- a/reactos/win32ss/user/consrv/frontends/gui/guisettings.c +++ b/reactos/win32ss/user/consrv/frontends/gui/guisettings.c @@ -106,6 +106,11 @@ GuiConsoleReadUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo, TermInfo->FontWeight = Value; RetVal = TRUE; } + else if (!wcscmp(szValueName, L"FullScreen")) + { + TermInfo->FullScreen = Value; + RetVal = TRUE; + } else if (!wcscmp(szValueName, L"WindowPosition")) { TermInfo->AutoPosition = FALSE; @@ -157,6 +162,9 @@ do { SetConsoleSetting(L"FontSize", REG_DWORD, sizeof(DWORD), &TermInfo->FontSize, 0); SetConsoleSetting(L"FontWeight", REG_DWORD, sizeof(DWORD), &TermInfo->FontWeight, FW_DONTCARE); + Storage = TermInfo->FullScreen; + SetConsoleSetting(L"FullScreen", REG_DWORD, sizeof(DWORD), &Storage, FALSE); + if (TermInfo->AutoPosition == FALSE) { Storage = MAKELONG(TermInfo->WindowOrigin.x, TermInfo->WindowOrigin.y); @@ -192,10 +200,11 @@ GuiConsoleGetDefaultSettings(IN OUT PGUI_CONSOLE_INFO TermInfo, wcsncpy(TermInfo->FaceName, L"Fixedsys", LF_FACESIZE); // HACK: !! // TermInfo->FaceName[0] = L'\0'; TermInfo->FontFamily = FF_DONTCARE; - TermInfo->FontSize = 0; + TermInfo->FontSize = 0; TermInfo->FontWeight = FW_DONTCARE; TermInfo->UseRasterFonts = TRUE; + TermInfo->FullScreen = FALSE; TermInfo->ShowWindow = SW_SHOWNORMAL; TermInfo->AutoPosition = TRUE; TermInfo->WindowOrigin.x = 0; @@ -218,6 +227,7 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData, { NTSTATUS Status; PCONSOLE Console = GuiData->Console; + PCONSOLE_SCREEN_BUFFER ActiveBuffer = Console->ActiveBuffer; PCONSOLE_PROCESS_DATA ProcessData; HANDLE hSection = NULL, hClientSection = NULL; LARGE_INTEGER SectionSize; @@ -282,17 +292,30 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData, pSharedInfo->ci.HistoryBufferSize = Console->HistoryBufferSize; pSharedInfo->ci.NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers; pSharedInfo->ci.HistoryNoDup = Console->HistoryNoDup; - pSharedInfo->ci.FullScreen = !!(Console->ActiveBuffer->DisplayMode & CONSOLE_FULLSCREEN_MODE); pSharedInfo->ci.QuickEdit = Console->QuickEdit; pSharedInfo->ci.InsertMode = Console->InsertMode; pSharedInfo->ci.InputBufferSize = 0; - pSharedInfo->ci.ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize; - pSharedInfo->ci.ConsoleSize = Console->ConsoleSize; + pSharedInfo->ci.ScreenBufferSize = ActiveBuffer->ScreenBufferSize; + pSharedInfo->ci.ConsoleSize = ActiveBuffer->ViewSize; pSharedInfo->ci.CursorBlinkOn; pSharedInfo->ci.ForceCursorOff; - pSharedInfo->ci.CursorSize = Console->ActiveBuffer->CursorInfo.dwSize; - pSharedInfo->ci.ScreenAttrib = Console->ActiveBuffer->ScreenDefaultAttrib; - pSharedInfo->ci.PopupAttrib = Console->ActiveBuffer->PopupDefaultAttrib; + pSharedInfo->ci.CursorSize = ActiveBuffer->CursorInfo.dwSize; + if (GetType(ActiveBuffer) == TEXTMODE_BUFFER) + { + PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)ActiveBuffer; + + pSharedInfo->ci.ScreenAttrib = Buffer->ScreenDefaultAttrib; + pSharedInfo->ci.PopupAttrib = Buffer->PopupDefaultAttrib; + } + else // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) + { + // PGRAPHICS_SCREEN_BUFFER Buffer = (PGRAPHICS_SCREEN_BUFFER)ActiveBuffer; + DPRINT1("GuiConsoleShowConsoleProperties - Graphics buffer\n"); + + // FIXME: Gather defaults from the registry ? + pSharedInfo->ci.ScreenAttrib = DEFAULT_SCREEN_ATTRIB; + pSharedInfo->ci.PopupAttrib = DEFAULT_POPUP_ATTRIB ; + } pSharedInfo->ci.CodePage; /* GUI Information */ @@ -302,9 +325,10 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData, wcsncpy(GuiInfo->FaceName, GuiData->GuiInfo.FaceName, LF_FACESIZE); GuiInfo->FaceName[Length] = L'\0'; GuiInfo->FontFamily = GuiData->GuiInfo.FontFamily; - GuiInfo->FontSize = GuiData->GuiInfo.FontSize; + GuiInfo->FontSize = GuiData->GuiInfo.FontSize; GuiInfo->FontWeight = GuiData->GuiInfo.FontWeight; GuiInfo->UseRasterFonts = GuiData->GuiInfo.UseRasterFonts; + GuiInfo->FullScreen = GuiData->GuiInfo.FullScreen; /// GuiInfo->WindowPosition = GuiData->GuiInfo.WindowPosition; GuiInfo->AutoPosition = GuiData->GuiInfo.AutoPosition; GuiInfo->WindowOrigin = GuiData->GuiInfo.WindowOrigin; @@ -322,6 +346,7 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData, else { Length = 0; + // FIXME: Load the default parameters from the registry. } /* Null-terminate the title */ @@ -478,6 +503,12 @@ GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData, GuiConsoleMoveWindow(GuiData); InvalidateRect(GuiData->hWindow, NULL, TRUE); + + /* + * Apply full-screen mode. + */ + GuiData->GuiInfo.FullScreen = GuiInfo->FullScreen; + // TODO: Apply it really } /* diff --git a/reactos/win32ss/user/consrv/frontends/gui/guisettings.h b/reactos/win32ss/user/consrv/frontends/gui/guisettings.h index 1ec60bae819..dd1930b178e 100644 --- a/reactos/win32ss/user/consrv/frontends/gui/guisettings.h +++ b/reactos/win32ss/user/consrv/frontends/gui/guisettings.h @@ -27,6 +27,9 @@ typedef struct _GUI_CONSOLE_INFO DWORD FontWeight; BOOL UseRasterFonts; + BOOL FullScreen; /* Whether the console is displayed in full-screen or windowed mode */ +// ULONG HardwareState; /* _GDI_MANAGED, _DIRECT */ + WORD ShowWindow; BOOL AutoPosition; POINT WindowOrigin; @@ -44,9 +47,10 @@ typedef struct _GUI_CONSOLE_DATA HWND hWindow; /* Handle to the console's window */ HICON hIcon; /* Handle to the console's icon (big) */ HICON hIconSm; /* Handle to the console's icon (small) */ - // COLORREF Colors[16]; + BOOL IgnoreNextMouseSignal; /* Used in cases where we don't want to treat a mouse signal */ +// COLORREF Colors[16]; - // PVOID ScreenBuffer; /* Hardware screen buffer */ +// PVOID ScreenBuffer; /* Hardware screen buffer */ HFONT Font; UINT CharWidth; diff --git a/reactos/win32ss/user/consrv/frontends/gui/guiterm.c b/reactos/win32ss/user/consrv/frontends/gui/guiterm.c index 9b3c2a24ee6..61583d1db78 100644 --- a/reactos/win32ss/user/consrv/frontends/gui/guiterm.c +++ b/reactos/win32ss/user/consrv/frontends/gui/guiterm.c @@ -32,8 +32,9 @@ #endif #define PM_CREATE_CONSOLE (WM_APP + 1) #define PM_DESTROY_CONSOLE (WM_APP + 2) -#define PM_CONSOLE_BEEP (WM_APP + 3) -#define PM_CONSOLE_SET_TITLE (WM_APP + 4) +#define PM_RESIZE_TERMINAL (WM_APP + 3) +#define PM_CONSOLE_BEEP (WM_APP + 4) +#define PM_CONSOLE_SET_TITLE (WM_APP + 5) /* Not defined in any header file */ @@ -212,12 +213,14 @@ GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM { LRESULT Ret = TRUE; PCONSOLE Console = GuiData->Console; + PCONSOLE_SCREEN_BUFFER ActiveBuffer; if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) { Ret = FALSE; goto Quit; } + ActiveBuffer = Console->ActiveBuffer; switch (wParam) { @@ -254,8 +257,8 @@ GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM { Console->Selection.dwSelectionAnchor.X = 0; Console->Selection.dwSelectionAnchor.Y = 0; - Console->dwSelectionCursor.X = Console->ConsoleSize.X - 1; - Console->dwSelectionCursor.Y = Console->ConsoleSize.Y - 1; + Console->dwSelectionCursor.X = ActiveBuffer->ViewSize.X - 1; + Console->dwSelectionCursor.Y = ActiveBuffer->ViewSize.Y - 1; GuiConsoleUpdateSelection(Console, &Console->dwSelectionCursor); break; } @@ -318,22 +321,37 @@ static VOID GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData) { PCONSOLE Console = GuiData->Console; + PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer; SCROLLINFO sInfo; - DWORD Width = Console->ConsoleSize.X * GuiData->CharWidth + - 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)); - DWORD Height = Console->ConsoleSize.Y * GuiData->CharHeight + - 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION); + DWORD Width, Height; + UINT WidthUnit, HeightUnit; + + if (GetType(Buff) == TEXTMODE_BUFFER) + { + WidthUnit = GuiData->CharWidth ; + HeightUnit = GuiData->CharHeight; + } + else /* if (GetType(Buff) == GRAPHICS_BUFFER) */ + { + WidthUnit = 1; + HeightUnit = 1; + } + + Width = Buff->ViewSize.X * WidthUnit + + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)); + Height = Buff->ViewSize.Y * HeightUnit + + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION); /* Set scrollbar sizes */ sInfo.cbSize = sizeof(SCROLLINFO); sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; sInfo.nMin = 0; - if (Console->ActiveBuffer->ScreenBufferSize.Y > Console->ConsoleSize.Y) + if (Buff->ScreenBufferSize.Y > Buff->ViewSize.Y) { - sInfo.nMax = Console->ActiveBuffer->ScreenBufferSize.Y - 1; - sInfo.nPage = Console->ConsoleSize.Y; - sInfo.nPos = Console->ActiveBuffer->ShowY; + sInfo.nMax = Buff->ScreenBufferSize.Y - 1; + sInfo.nPage = Buff->ViewSize.Y; + sInfo.nPos = Buff->ViewOrigin.Y; SetScrollInfo(GuiData->hWindow, SB_VERT, &sInfo, TRUE); Width += GetSystemMetrics(SM_CXVSCROLL); ShowScrollBar(GuiData->hWindow, SB_VERT, TRUE); @@ -343,11 +361,11 @@ GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData) ShowScrollBar(GuiData->hWindow, SB_VERT, FALSE); } - if (Console->ActiveBuffer->ScreenBufferSize.X > Console->ConsoleSize.X) + if (Buff->ScreenBufferSize.X > Buff->ViewSize.X) { - sInfo.nMax = Console->ActiveBuffer->ScreenBufferSize.X - 1; - sInfo.nPage = Console->ConsoleSize.X; - sInfo.nPos = Console->ActiveBuffer->ShowX; + sInfo.nMax = Buff->ScreenBufferSize.X - 1; + sInfo.nPage = Buff->ViewSize.X; + sInfo.nPos = Buff->ViewOrigin.X; SetScrollInfo(GuiData->hWindow, SB_HORZ, &sInfo, TRUE); Height += GetSystemMetrics(SM_CYHSCROLL); ShowScrollBar(GuiData->hWindow, SB_HORZ, TRUE); @@ -359,7 +377,49 @@ GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData) /* Resize the window */ SetWindowPos(GuiData->hWindow, NULL, 0, 0, Width, Height, - SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS); + // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call + // to: InvalidateRect(GuiData->hWindow, NULL, TRUE); +} + +static VOID +GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData) +{ + PCONSOLE Console = GuiData->Console; + // DEVMODE dmScreenSettings; + + if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; + + /* Switch to full-screen or to windowed mode */ + GuiData->GuiInfo.FullScreen = !GuiData->GuiInfo.FullScreen; + DPRINT1("GuiConsoleSwitchFullScreen - Switch to %s ...\n", + (GuiData->GuiInfo.FullScreen ? "full-screen" : "windowed mode")); + + // TODO: Change window appearance. + // See: + // http://stackoverflow.com/questions/2382464/win32-full-screen-and-hiding-taskbar + // http://stackoverflow.com/questions/3549148/fullscreen-management-with-winapi + // http://blogs.msdn.com/b/oldnewthing/archive/2010/04/12/9994016.aspx + // http://stackoverflow.com/questions/1400654/how-do-i-put-my-opengl-app-into-fullscreen-mode + // http://nehe.gamedev.net/tutorial/creating_an_opengl_window_win32/13001/ +#if 0 + if (GuiData->GuiInfo.FullScreen) + { + memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); + dmScreenSettings.dmSize = sizeof(dmScreenSettings); + dmScreenSettings.dmDisplayFixedOutput = DMDFO_CENTER; // DMDFO_STRETCH // DMDFO_DEFAULT + dmScreenSettings.dmPelsWidth = 640; // Console->ActiveBuffer->ViewSize.X * GuiData->CharWidth; + dmScreenSettings.dmPelsHeight = 480; // Console->ActiveBuffer->ViewSize.Y * GuiData->CharHeight; + dmScreenSettings.dmBitsPerPel = 32; + dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN); + } + else + { + } +#endif + + LeaveCriticalSection(&Console->Lock); } static BOOL @@ -467,11 +527,23 @@ SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect) { PCONSOLE Console = GuiData->Console; PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer; + UINT WidthUnit, HeightUnit; - Rect->left = (SmallRect->Left - Buffer->ShowX) * GuiData->CharWidth; - Rect->top = (SmallRect->Top - Buffer->ShowY) * GuiData->CharHeight; - Rect->right = (SmallRect->Right + 1 - Buffer->ShowX) * GuiData->CharWidth; - Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ShowY) * GuiData->CharHeight; + if (GetType(Buffer) == TEXTMODE_BUFFER) + { + WidthUnit = GuiData->CharWidth ; + HeightUnit = GuiData->CharHeight; + } + else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */ + { + WidthUnit = 1; + HeightUnit = 1; + } + + Rect->left = (SmallRect->Left - Buffer->ViewOrigin.X) * WidthUnit ; + Rect->top = (SmallRect->Top - Buffer->ViewOrigin.Y) * HeightUnit; + Rect->right = (SmallRect->Right + 1 - Buffer->ViewOrigin.X) * WidthUnit ; + Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ViewOrigin.Y) * HeightUnit; } static VOID @@ -535,119 +607,24 @@ GuiConsoleUpdateSelection(PCONSOLE Console, PCOORD coord) } } -static VOID -GuiConsolePaint(PCONSOLE Console, - PGUI_CONSOLE_DATA GuiData, - HDC hDC, - PRECT rc) -{ - PCONSOLE_SCREEN_BUFFER Buff; - ULONG TopLine, BottomLine, LeftChar, RightChar; - ULONG Line, Char, Start; - PBYTE From; - PWCHAR To; - BYTE LastAttribute, Attribute; - ULONG CursorX, CursorY, CursorHeight; - HBRUSH CursorBrush, OldBrush; - HFONT OldFont; - Buff = Console->ActiveBuffer; - - TopLine = rc->top / GuiData->CharHeight + Buff->ShowY; - BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1 + Buff->ShowY; - LeftChar = rc->left / GuiData->CharWidth + Buff->ShowX; - RightChar = (rc->right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1 + Buff->ShowX; - LastAttribute = ConioCoordToPointer(Buff, LeftChar, TopLine)[1]; - - SetTextColor(hDC, RGBFromAttrib(Console, TextAttribFromAttrib(LastAttribute))); - SetBkColor(hDC, RGBFromAttrib(Console, BkgdAttribFromAttrib(LastAttribute))); - - if (BottomLine >= Buff->ScreenBufferSize.Y) BottomLine = Buff->ScreenBufferSize.Y - 1; - if (RightChar >= Buff->ScreenBufferSize.X) RightChar = Buff->ScreenBufferSize.X - 1; - - OldFont = SelectObject(hDC, GuiData->Font); - - for (Line = TopLine; Line <= BottomLine; Line++) - { - WCHAR LineBuffer[80]; - From = ConioCoordToPointer(Buff, LeftChar, Line); - Start = LeftChar; - To = LineBuffer; - - for (Char = LeftChar; Char <= RightChar; Char++) - { - if (*(From + 1) != LastAttribute || (Char - Start == sizeof(LineBuffer) / sizeof(WCHAR))) - { - TextOutW(hDC, - (Start - Buff->ShowX) * GuiData->CharWidth, - (Line - Buff->ShowY) * GuiData->CharHeight, - LineBuffer, - Char - Start); - Start = Char; - To = LineBuffer; - Attribute = *(From + 1); - if (Attribute != LastAttribute) - { - SetTextColor(hDC, RGBFromAttrib(Console, TextAttribFromAttrib(Attribute))); - SetBkColor(hDC, RGBFromAttrib(Console, BkgdAttribFromAttrib(Attribute))); - LastAttribute = Attribute; - } - } - - MultiByteToWideChar(Console->OutputCodePage, - 0, (PCHAR)From, 1, To, 1); - To++; - From += 2; - } - - TextOutW(hDC, - (Start - Buff->ShowX) * GuiData->CharWidth, - (Line - Buff->ShowY) * GuiData->CharHeight, - LineBuffer, - RightChar - Start + 1); - } - - if (Buff->CursorInfo.bVisible && - Buff->CursorBlinkOn && - !Buff->ForceCursorOff) - { - CursorX = Buff->CursorPosition.X; - CursorY = Buff->CursorPosition.Y; - if (LeftChar <= CursorX && CursorX <= RightChar && - TopLine <= CursorY && CursorY <= BottomLine) - { - CursorHeight = ConioEffectiveCursorSize(Console, GuiData->CharHeight); - From = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y) + 1; - - if (*From != DEFAULT_SCREEN_ATTRIB) - { - CursorBrush = CreateSolidBrush(RGBFromAttrib(Console, *From)); - } - else - { - CursorBrush = CreateSolidBrush(RGBFromAttrib(Console, Buff->ScreenDefaultAttrib)); - } - - OldBrush = SelectObject(hDC, CursorBrush); - PatBlt(hDC, - (CursorX - Buff->ShowX) * GuiData->CharWidth, - (CursorY - Buff->ShowY) * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight), - GuiData->CharWidth, - CursorHeight, - PATCOPY); - SelectObject(hDC, OldBrush); - DeleteObject(CursorBrush); - } - } - - SelectObject(hDC, OldFont); -} +VOID +GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer, + PGUI_CONSOLE_DATA GuiData, + HDC hDC, + PRECT rc); +VOID +GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer, + PGUI_CONSOLE_DATA GuiData, + HDC hDC, + PRECT rc); static VOID GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData) { BOOL Success = TRUE; PCONSOLE Console = GuiData->Console; + PCONSOLE_SCREEN_BUFFER ActiveBuffer; HDC hDC; PAINTSTRUCT ps; @@ -656,24 +633,25 @@ GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData) Success = FALSE; goto Quit; } - - if (Console->ActiveBuffer == NULL || - Console->ActiveBuffer->Buffer == NULL) - { - goto Quit; - } + ActiveBuffer = Console->ActiveBuffer; hDC = BeginPaint(GuiData->hWindow, &ps); if (hDC != NULL && - ps.rcPaint.left < ps.rcPaint.right && - ps.rcPaint.top < ps.rcPaint.bottom) + ps.rcPaint.left < ps.rcPaint.right && + ps.rcPaint.top < ps.rcPaint.bottom) { EnterCriticalSection(&GuiData->Lock); - GuiConsolePaint(Console, - GuiData, - hDC, - &ps.rcPaint); + if (GetType(ActiveBuffer) == TEXTMODE_BUFFER) + { + GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)ActiveBuffer, + GuiData, hDC, &ps.rcPaint); + } + else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */ + { + GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)ActiveBuffer, + GuiData, hDC, &ps.rcPaint); + } if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) { @@ -681,9 +659,7 @@ GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData) SmallRectToRect(GuiData, &rc, &Console->Selection.srSelection); /* invert the selection */ - if (IntersectRect(&rc, - &ps.rcPaint, - &rc)) + if (IntersectRect(&rc, &ps.rcPaint, &rc)) { PatBlt(hDC, rc.left, @@ -711,13 +687,15 @@ static VOID GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam) { PCONSOLE Console = GuiData->Console; + PCONSOLE_SCREEN_BUFFER ActiveBuffer; MSG Message; if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; + ActiveBuffer = Console->ActiveBuffer; + if ( (Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) && - ((Console->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) == 0) && - (Console->ActiveBuffer) ) + ((Console->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) == 0) ) { BOOL Interpreted = FALSE; @@ -740,7 +718,7 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l case VK_RIGHT: { Interpreted = TRUE; - if (Console->dwSelectionCursor.X < Console->ActiveBuffer->ScreenBufferSize.X - 1) + if (Console->dwSelectionCursor.X < ActiveBuffer->ScreenBufferSize.X - 1) Console->dwSelectionCursor.X++; break; @@ -758,7 +736,7 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l case VK_DOWN: { Interpreted = TRUE; - if (Console->dwSelectionCursor.Y < Console->ActiveBuffer->ScreenBufferSize.Y - 1) + if (Console->dwSelectionCursor.Y < ActiveBuffer->ScreenBufferSize.Y - 1) Console->dwSelectionCursor.Y++; break; @@ -775,14 +753,14 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l case VK_END: { Interpreted = TRUE; - Console->dwSelectionCursor.Y = Console->ActiveBuffer->ScreenBufferSize.Y - 1; + Console->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1; break; } case VK_PRIOR: { Interpreted = TRUE; - Console->dwSelectionCursor.Y -= Console->ConsoleSize.Y; + Console->dwSelectionCursor.Y -= ActiveBuffer->ViewSize.Y; if (Console->dwSelectionCursor.Y < 0) Console->dwSelectionCursor.Y = 0; @@ -792,9 +770,9 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l case VK_NEXT: { Interpreted = TRUE; - Console->dwSelectionCursor.Y += Console->ConsoleSize.Y; - if (Console->dwSelectionCursor.Y >= Console->ActiveBuffer->ScreenBufferSize.Y) - Console->dwSelectionCursor.Y = Console->ActiveBuffer->ScreenBufferSize.Y - 1; + Console->dwSelectionCursor.Y += ActiveBuffer->ViewSize.Y; + if (Console->dwSelectionCursor.Y >= ActiveBuffer->ScreenBufferSize.Y) + Console->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1; break; } @@ -850,80 +828,87 @@ GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData) if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; Buff = Console->ActiveBuffer; - GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y); - Buff->CursorBlinkOn = !Buff->CursorBlinkOn; - if ((GuiData->OldCursor.x != Buff->CursorPosition.X) || (GuiData->OldCursor.y != Buff->CursorPosition.Y)) + if (GetType(Buff) == TEXTMODE_BUFFER) { - SCROLLINFO xScroll; - int OldScrollX = -1, OldScrollY = -1; - int NewScrollX = -1, NewScrollY = -1; + GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y); + Buff->CursorBlinkOn = !Buff->CursorBlinkOn; - xScroll.cbSize = sizeof(SCROLLINFO); - xScroll.fMask = SIF_POS; - // Capture the original position of the scroll bars and save them. - if (GetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll))OldScrollX = xScroll.nPos; - if (GetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll))OldScrollY = xScroll.nPos; - - // If we successfully got the info for the horizontal scrollbar - if (OldScrollX >= 0) + if ((GuiData->OldCursor.x != Buff->CursorPosition.X) || (GuiData->OldCursor.y != Buff->CursorPosition.Y)) { - if ((Buff->CursorPosition.X < Buff->ShowX)||(Buff->CursorPosition.X >= (Buff->ShowX + Console->ConsoleSize.X))) + SCROLLINFO xScroll; + int OldScrollX = -1, OldScrollY = -1; + int NewScrollX = -1, NewScrollY = -1; + + xScroll.cbSize = sizeof(SCROLLINFO); + xScroll.fMask = SIF_POS; + // Capture the original position of the scroll bars and save them. + if (GetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll)) OldScrollX = xScroll.nPos; + if (GetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll)) OldScrollY = xScroll.nPos; + + // If we successfully got the info for the horizontal scrollbar + if (OldScrollX >= 0) { - // Handle the horizontal scroll bar - if (Buff->CursorPosition.X >= Console->ConsoleSize.X) NewScrollX = Buff->CursorPosition.X - Console->ConsoleSize.X + 1; - else NewScrollX = 0; + if ((Buff->CursorPosition.X < Buff->ViewOrigin.X) || (Buff->CursorPosition.X >= (Buff->ViewOrigin.X + Buff->ViewSize.X))) + { + // Handle the horizontal scroll bar + if (Buff->CursorPosition.X >= Buff->ViewSize.X) NewScrollX = Buff->CursorPosition.X - Buff->ViewSize.X + 1; + else NewScrollX = 0; + } + else + { + NewScrollX = OldScrollX; + } } - else + // If we successfully got the info for the vertical scrollbar + if (OldScrollY >= 0) { - NewScrollX = OldScrollX; + if ((Buff->CursorPosition.Y < Buff->ViewOrigin.Y) || (Buff->CursorPosition.Y >= (Buff->ViewOrigin.Y + Buff->ViewSize.Y))) + { + // Handle the vertical scroll bar + if (Buff->CursorPosition.Y >= Buff->ViewSize.Y) NewScrollY = Buff->CursorPosition.Y - Buff->ViewSize.Y + 1; + else NewScrollY = 0; + } + else + { + NewScrollY = OldScrollY; + } + } + + // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area + // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar + // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling) + // and their associated scrollbar is left alone. + if ((OldScrollX != NewScrollX) || (OldScrollY != NewScrollY)) + { + Buff->ViewOrigin.X = NewScrollX; + Buff->ViewOrigin.Y = NewScrollY; + ScrollWindowEx(GuiData->hWindow, + (OldScrollX - NewScrollX) * GuiData->CharWidth, + (OldScrollY - NewScrollY) * GuiData->CharHeight, + NULL, + NULL, + NULL, + NULL, + SW_INVALIDATE); + if (NewScrollX >= 0) + { + xScroll.nPos = NewScrollX; + SetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll, TRUE); + } + if (NewScrollY >= 0) + { + xScroll.nPos = NewScrollY; + SetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll, TRUE); + } + UpdateWindow(GuiData->hWindow); + GuiData->OldCursor.x = Buff->CursorPosition.X; + GuiData->OldCursor.y = Buff->CursorPosition.Y; } } - // If we successfully got the info for the vertical scrollbar - if (OldScrollY >= 0) - { - if ((Buff->CursorPosition.Y < Buff->ShowY) || (Buff->CursorPosition.Y >= (Buff->ShowY + Console->ConsoleSize.Y))) - { - // Handle the vertical scroll bar - if (Buff->CursorPosition.Y >= Console->ConsoleSize.Y) NewScrollY = Buff->CursorPosition.Y - Console->ConsoleSize.Y + 1; - else NewScrollY = 0; - } - else - { - NewScrollY = OldScrollY; - } - } - - // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area - // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar - // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling) - // and their associated scrollbar is left alone. - if ((OldScrollX != NewScrollX) || (OldScrollY != NewScrollY)) - { - Buff->ShowX = NewScrollX; - Buff->ShowY = NewScrollY; - ScrollWindowEx(GuiData->hWindow, - (OldScrollX - NewScrollX) * GuiData->CharWidth, - (OldScrollY - NewScrollY) * GuiData->CharHeight, - NULL, - NULL, - NULL, - NULL, - SW_INVALIDATE); - if (NewScrollX >= 0) - { - xScroll.nPos = NewScrollX; - SetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll, TRUE); - } - if (NewScrollY >= 0) - { - xScroll.nPos = NewScrollY; - SetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll, TRUE); - } - UpdateWindow(GuiData->hWindow); - GuiData->OldCursor.x = Buff->CursorPosition.X; - GuiData->OldCursor.y = Buff->CursorPosition.Y; - } + } + else /* if (GetType(Buff) == GRAPHICS_BUFFER) */ + { } LeaveCriticalSection(&Console->Lock); @@ -967,9 +952,21 @@ PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam) PCONSOLE Console = GuiData->Console; PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer; COORD Coord; + UINT WidthUnit, HeightUnit; - Coord.X = Buffer->ShowX + ((SHORT)LOWORD(lParam) / (int)GuiData->CharWidth); - Coord.Y = Buffer->ShowY + ((SHORT)HIWORD(lParam) / (int)GuiData->CharHeight); + if (GetType(Buffer) == TEXTMODE_BUFFER) + { + WidthUnit = GuiData->CharWidth ; + HeightUnit = GuiData->CharHeight; + } + else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */ + { + WidthUnit = 1; + HeightUnit = 1; + } + + Coord.X = Buffer->ViewOrigin.X + ((SHORT)LOWORD(lParam) / (int)WidthUnit ); + Coord.Y = Buffer->ViewOrigin.Y + ((SHORT)HIWORD(lParam) / (int)HeightUnit); /* Clip coordinate to ensure it's inside buffer */ if (Coord.X < 0) @@ -991,6 +988,29 @@ GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM BOOL Err = FALSE; PCONSOLE Console = GuiData->Console; + if (GuiData->IgnoreNextMouseSignal) + { + if (msg != WM_LBUTTONDOWN && + msg != WM_MBUTTONDOWN && + msg != WM_RBUTTONDOWN) + { + /* + * If this mouse signal is not a button-down action, + * then it is the last signal being ignored. + */ + GuiData->IgnoreNextMouseSignal = FALSE; + } + else + { + /* + * This mouse signal is a button-down action. + * Ignore it and perform default action. + */ + Err = TRUE; + } + goto Quit; + } + if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) { Err = TRUE; @@ -1036,7 +1056,14 @@ GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM break; } + case WM_LBUTTONDBLCLK: + { + DPRINT1("Handle left-double-click for selecting a word\n"); + break; + } + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: { if (!(Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)) { @@ -1051,6 +1078,7 @@ GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM SetWindowText(GuiData->hWindow, Console->Title.Buffer); } + GuiData->IgnoreNextMouseSignal = TRUE; break; } @@ -1205,110 +1233,50 @@ Quit: return 0; } +VOID GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer); +VOID GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer); + static VOID GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData) { - PCONSOLE Console = GuiData->Console; - if (OpenClipboard(GuiData->hWindow) == TRUE) { - HANDLE hData; - PBYTE ptr; - LPSTR data, dstPos; - ULONG selWidth, selHeight; - ULONG xPos, yPos, size; + PCONSOLE Console = GuiData->Console; + PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer; - selWidth = Console->Selection.srSelection.Right - Console->Selection.srSelection.Left + 1; - selHeight = Console->Selection.srSelection.Bottom - Console->Selection.srSelection.Top + 1; - DPRINT("Selection is (%d|%d) to (%d|%d)\n", - Console->Selection.srSelection.Left, - Console->Selection.srSelection.Top, - Console->Selection.srSelection.Right, - Console->Selection.srSelection.Bottom); - - /* Basic size for one line and termination */ - size = selWidth + 1; - if (selHeight > 0) + if (GetType(Buffer) == TEXTMODE_BUFFER) { - /* Multiple line selections have to get \r\n appended */ - size += ((selWidth + 2) * (selHeight - 1)); + GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer); + } + else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */ + { + GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer); } - /* Allocate memory, it will be passed to the system and may not be freed here */ - hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size); - if (hData == NULL) - { - CloseClipboard(); - return; - } - data = GlobalLock(hData); - if (data == NULL) - { - CloseClipboard(); - return; - } - - DPRINT("Copying %dx%d selection\n", selWidth, selHeight); - dstPos = data; - - for (yPos = 0; yPos < selHeight; yPos++) - { - ptr = ConioCoordToPointer(Console->ActiveBuffer, - Console->Selection.srSelection.Left, - yPos + Console->Selection.srSelection.Top); - /* Copy only the characters, leave attributes alone */ - for (xPos = 0; xPos < selWidth; xPos++) - { - dstPos[xPos] = ptr[xPos * 2]; - } - dstPos += selWidth; - if (yPos != (selHeight - 1)) - { - strcat(data, "\r\n"); - dstPos += 2; - } - } - - DPRINT("Setting data <%s> to clipboard\n", data); - GlobalUnlock(hData); - - EmptyClipboard(); - SetClipboardData(CF_TEXT, hData); CloseClipboard(); } } +VOID GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer); +VOID GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer); + static VOID GuiConsolePaste(PGUI_CONSOLE_DATA GuiData) { - PCONSOLE Console = GuiData->Console; - if (OpenClipboard(GuiData->hWindow) == TRUE) { - HANDLE hData; - LPSTR str; - size_t len; + PCONSOLE Console = GuiData->Console; + PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer; - hData = GetClipboardData(CF_TEXT); - if (hData == NULL) + if (GetType(Buffer) == TEXTMODE_BUFFER) { - CloseClipboard(); - return; + GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer); + } + else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */ + { + GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer); } - str = GlobalLock(hData); - if (str == NULL) - { - CloseClipboard(); - return; - } - DPRINT("Got data <%s> from clipboard\n", str); - len = strlen(str); - - // TODO: Push the text into the input buffer. - ConioWriteConsole(Console, Console->ActiveBuffer, str, len, TRUE); - - GlobalUnlock(hData); CloseClipboard(); } } @@ -1317,21 +1285,36 @@ static VOID GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo) { PCONSOLE Console = GuiData->Console; + PCONSOLE_SCREEN_BUFFER ActiveBuffer; DWORD windx, windy; + UINT WidthUnit, HeightUnit; if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; - windx = CONGUI_MIN_WIDTH * GuiData->CharWidth + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)); - windy = CONGUI_MIN_HEIGHT * GuiData->CharHeight + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION); + ActiveBuffer = Console->ActiveBuffer; + + if (GetType(ActiveBuffer) == TEXTMODE_BUFFER) + { + WidthUnit = GuiData->CharWidth ; + HeightUnit = GuiData->CharHeight; + } + else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */ + { + WidthUnit = 1; + HeightUnit = 1; + } + + windx = CONGUI_MIN_WIDTH * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)); + windy = CONGUI_MIN_HEIGHT * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION); minMaxInfo->ptMinTrackSize.x = windx; minMaxInfo->ptMinTrackSize.y = windy; - windx = (Console->ActiveBuffer->ScreenBufferSize.X) * GuiData->CharWidth + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)); - windy = (Console->ActiveBuffer->ScreenBufferSize.Y) * GuiData->CharHeight + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION); + windx = (ActiveBuffer->ScreenBufferSize.X) * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)); + windy = (ActiveBuffer->ScreenBufferSize.Y) * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION); - if (Console->ConsoleSize.X < Console->ActiveBuffer->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar - if (Console->ConsoleSize.Y < Console->ActiveBuffer->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar + if (ActiveBuffer->ViewSize.X < ActiveBuffer->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar + if (ActiveBuffer->ViewSize.Y < ActiveBuffer->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar minMaxInfo->ptMaxTrackSize.x = windx; minMaxInfo->ptMaxTrackSize.y = windy; @@ -1351,6 +1334,18 @@ GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam) { PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer; DWORD windx, windy, charx, chary; + UINT WidthUnit, HeightUnit; + + if (GetType(Buff) == TEXTMODE_BUFFER) + { + WidthUnit = GuiData->CharWidth ; + HeightUnit = GuiData->CharHeight; + } + else /* if (GetType(Buff) == GRAPHICS_BUFFER) */ + { + WidthUnit = 1; + HeightUnit = 1; + } GuiData->WindowSizeLock = TRUE; @@ -1358,39 +1353,39 @@ GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam) windy = HIWORD(lParam); // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar) - if (Console->ConsoleSize.X < Buff->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar - if (Console->ConsoleSize.Y < Buff->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar + if (Buff->ViewSize.X < Buff->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar + if (Buff->ViewSize.Y < Buff->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar - charx = windx / GuiData->CharWidth; - chary = windy / GuiData->CharHeight; + charx = windx / (int)WidthUnit ; + chary = windy / (int)HeightUnit; // Character alignment (round size up or down) - if ((windx % GuiData->CharWidth) >= (GuiData->CharWidth / 2)) ++charx; - if ((windy % GuiData->CharHeight) >= (GuiData->CharHeight / 2)) ++chary; + if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx; + if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary; // Compensate for added scroll bars in new window - if (charx < Buff->ScreenBufferSize.X)windy -= GetSystemMetrics(SM_CYHSCROLL); // new window will have a horizontal scroll bar - if (chary < Buff->ScreenBufferSize.Y)windx -= GetSystemMetrics(SM_CXVSCROLL); // new window will have a vertical scroll bar + if (charx < Buff->ScreenBufferSize.X) windy -= GetSystemMetrics(SM_CYHSCROLL); // new window will have a horizontal scroll bar + if (chary < Buff->ScreenBufferSize.Y) windx -= GetSystemMetrics(SM_CXVSCROLL); // new window will have a vertical scroll bar - charx = windx / GuiData->CharWidth; - chary = windy / GuiData->CharHeight; + charx = windx / (int)WidthUnit ; + chary = windy / (int)HeightUnit; // Character alignment (round size up or down) - if ((windx % GuiData->CharWidth) >= (GuiData->CharWidth / 2)) ++charx; - if ((windy % GuiData->CharHeight) >= (GuiData->CharHeight / 2)) ++chary; + if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx; + if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary; // Resize window - if ((charx != Console->ConsoleSize.X) || (chary != Console->ConsoleSize.Y)) + if ((charx != Buff->ViewSize.X) || (chary != Buff->ViewSize.Y)) { - Console->ConsoleSize.X = (charx <= Buff->ScreenBufferSize.X) ? charx : Buff->ScreenBufferSize.X; - Console->ConsoleSize.Y = (chary <= Buff->ScreenBufferSize.Y) ? chary : Buff->ScreenBufferSize.Y; + Buff->ViewSize.X = (charx <= Buff->ScreenBufferSize.X) ? charx : Buff->ScreenBufferSize.X; + Buff->ViewSize.Y = (chary <= Buff->ScreenBufferSize.Y) ? chary : Buff->ScreenBufferSize.Y; } GuiConsoleResizeWindow(GuiData); // Adjust the start of the visible area if we are attempting to show nonexistent areas - if ((Buff->ScreenBufferSize.X - Buff->ShowX) < Console->ConsoleSize.X) Buff->ShowX = Buff->ScreenBufferSize.X - Console->ConsoleSize.X; - if ((Buff->ScreenBufferSize.Y - Buff->ShowY) < Console->ConsoleSize.Y) Buff->ShowY = Buff->ScreenBufferSize.Y - Console->ConsoleSize.Y; + if ((Buff->ScreenBufferSize.X - Buff->ViewOrigin.X) < Buff->ViewSize.X) Buff->ViewOrigin.X = Buff->ScreenBufferSize.X - Buff->ViewSize.X; + if ((Buff->ScreenBufferSize.Y - Buff->ViewOrigin.Y) < Buff->ViewSize.Y) Buff->ViewOrigin.Y = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y; InvalidateRect(GuiData->hWindow, NULL, TRUE); GuiData->WindowSizeLock = FALSE; @@ -1436,7 +1431,7 @@ GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam) SCROLLINFO sInfo; int fnBar; int old_pos, Maximum; - PUSHORT pShowXY; + PSHORT pShowXY; if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return 0; @@ -1445,14 +1440,14 @@ GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam) if (uMsg == WM_HSCROLL) { fnBar = SB_HORZ; - Maximum = Buff->ScreenBufferSize.X - Console->ConsoleSize.X; - pShowXY = &Buff->ShowX; + Maximum = Buff->ScreenBufferSize.X - Buff->ViewSize.X; + pShowXY = &Buff->ViewOrigin.X; } else { fnBar = SB_VERT; - Maximum = Buff->ScreenBufferSize.Y - Console->ConsoleSize.Y; - pShowXY = &Buff->ShowY; + Maximum = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y; + pShowXY = &Buff->ViewOrigin.Y; } /* set scrollbar sizes */ @@ -1507,13 +1502,26 @@ GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam) if (old_pos != sInfo.nPos) { - USHORT OldX = Buff->ShowX; - USHORT OldY = Buff->ShowY; + USHORT OldX = Buff->ViewOrigin.X; + USHORT OldY = Buff->ViewOrigin.Y; + UINT WidthUnit, HeightUnit; + *pShowXY = sInfo.nPos; + if (GetType(Buff) == TEXTMODE_BUFFER) + { + WidthUnit = GuiData->CharWidth ; + HeightUnit = GuiData->CharHeight; + } + else /* if (GetType(Buff) == GRAPHICS_BUFFER) */ + { + WidthUnit = 1; + HeightUnit = 1; + } + ScrollWindowEx(GuiData->hWindow, - (OldX - Buff->ShowX) * GuiData->CharWidth, - (OldY - Buff->ShowY) * GuiData->CharHeight, + (OldX - Buff->ViewOrigin.X) * WidthUnit , + (OldY - Buff->ViewOrigin.Y) * HeightUnit, NULL, NULL, NULL, @@ -1569,6 +1577,12 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) /* We have a console, start message dispatching */ switch (msg) { + case WM_ACTIVATE: + { + if (LOWORD(wParam) == WA_CLICKACTIVE) GuiData->IgnoreNextMouseSignal = TRUE; + break; + } + case WM_CLOSE: GuiConsoleHandleClose(GuiData); break; @@ -1583,6 +1597,14 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_SYSKEYUP: case WM_CHAR: { + /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */ + if (msg == WM_SYSKEYDOWN && (HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_RETURN) + { + /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */ + if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT) GuiConsoleSwitchFullScreen(GuiData); + break; + } + GuiConsoleHandleKey(GuiData, msg, wParam, lParam); break; } @@ -1608,9 +1630,16 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) break; } + case WM_HSCROLL: + case WM_VSCROLL: + { + Result = GuiConsoleHandleScroll(GuiData, msg, wParam); + break; + } + case WM_NCRBUTTONDOWN: { - DPRINT("WM_NCRBUTTONDOWN\n"); + DPRINT1("WM_NCRBUTTONDOWN\n"); /* * HACK: !! Because, when we deal with WM_RBUTTON* and we do not * call after that DefWindowProc, on ReactOS, right-clicks on the @@ -1620,9 +1649,11 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) * and line 1135 too. */ if (DefWindowProcW(hWnd, WM_NCHITTEST, 0, lParam) == HTCAPTION) - return DefWindowProcW(hWnd, WM_CONTEXTMENU, wParam, lParam); - else - goto Default; + { + /* Call DefWindowProcW with the WM_CONTEXTMENU message */ + msg = WM_CONTEXTMENU; + } + goto Default; } // case WM_NCRBUTTONUP: // DPRINT1("WM_NCRBUTTONUP\n"); @@ -1659,13 +1690,6 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) break; } - case WM_HSCROLL: - case WM_VSCROLL: - { - Result = GuiConsoleHandleScroll(GuiData, msg, wParam); - break; - } - case WM_SETFOCUS: case WM_KILLFOCUS: { @@ -1677,6 +1701,11 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) er.Event.FocusEvent.bSetFocus = (msg == WM_SETFOCUS); ConioProcessInputEvent(Console, &er); + if (msg == WM_SETFOCUS) + DPRINT1("TODO: Create console caret\n"); + else // if (msg == WM_KILLFOCUS) + DPRINT1("TODO: Destroy console caret\n"); + LeaveCriticalSection(&Console->Lock); } break; @@ -1690,6 +1719,15 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) GuiConsoleResize(GuiData, wParam, lParam); break; + case PM_RESIZE_TERMINAL: + { + /* Resize the window to the user's values */ + GuiData->WindowSizeLock = TRUE; + GuiConsoleResizeWindow(GuiData); + GuiData->WindowSizeLock = FALSE; + break; + } + case PM_APPLY_CONSOLE_INFO: { Console = GuiData->Console; // Not NULL because checked in GuiGetGuiData. @@ -1932,7 +1970,7 @@ GuiInit(VOID) wc.hIcon = ghDefaultIcon; wc.hIconSm = ghDefaultIconSm; wc.hCursor = ghDefaultCursor; - wc.hbrBackground = CreateSolidBrush(RGB(0,0,0)); // FIXME: Use defaults from registry. + wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // The color of a terminal when it is switch off. wc.lpszMenuName = NULL; wc.cbClsExtra = 0; wc.cbWndExtra = GWLP_CONSOLEWND_ALLOC; @@ -2025,6 +2063,17 @@ GuiCleanupConsole(PCONSOLE Console) DPRINT("Quit GuiCleanupConsole\n"); } +static VOID WINAPI +GuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region) +{ + PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + RECT RegionRect; + + SmallRectToRect(GuiData, &RegionRect, Region); + /* Do not erase the background: it speeds up redrawing and reduce flickering */ + InvalidateRect(GuiData->hWindow, &RegionRect, FALSE); +} + static VOID WINAPI GuiWriteStream(PCONSOLE Console, SMALL_RECT* Region, SHORT CursorStartX, SHORT CursorStartY, UINT ScrolledLines, CHAR *Buffer, UINT Length) @@ -2034,16 +2083,14 @@ GuiWriteStream(PCONSOLE Console, SMALL_RECT* Region, SHORT CursorStartX, SHORT C SHORT CursorEndX, CursorEndY; RECT ScrollRect; - if (NULL == GuiData || NULL == GuiData->hWindow) - { - return; - } + if (NULL == GuiData || NULL == GuiData->hWindow) return; + if (GetType(Buff) != TEXTMODE_BUFFER) return; if (0 != ScrolledLines) { ScrollRect.left = 0; ScrollRect.top = 0; - ScrollRect.right = Console->ConsoleSize.X * GuiData->CharWidth; + ScrollRect.right = Buff->ViewSize.X * GuiData->CharWidth; ScrollRect.bottom = Region->Top * GuiData->CharHeight; ScrollWindowEx(GuiData->hWindow, @@ -2079,16 +2126,6 @@ GuiWriteStream(PCONSOLE Console, SMALL_RECT* Region, SHORT CursorStartX, SHORT C SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL); } -static VOID WINAPI -GuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region) -{ - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; - RECT RegionRect; - - SmallRectToRect(GuiData, &RegionRect, Region); - InvalidateRect(GuiData->hWindow, &RegionRect, FALSE); -} - static BOOL WINAPI GuiSetCursorInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff) { @@ -2105,36 +2142,27 @@ GuiSetScreenInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff, SHORT OldCursorX { if (Console->ActiveBuffer == Buff) { - /* Redraw char at old position (removes cursor) */ + /* Redraw char at old position (remove cursor) */ GuiInvalidateCell(Console, OldCursorX, OldCursorY); - /* Redraw char at new position (shows cursor) */ + /* Redraw char at new position (show cursor) */ GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y); } return TRUE; } -static BOOL WINAPI -GuiUpdateScreenInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff) -{ - return TRUE; -} - -static BOOL WINAPI -GuiIsBufferResizeSupported(PCONSOLE Console) -{ - return TRUE; -} - static VOID WINAPI GuiResizeTerminal(PCONSOLE Console) { PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; /* Resize the window to the user's values */ - GuiData->WindowSizeLock = TRUE; - GuiConsoleResizeWindow(GuiData); - GuiData->WindowSizeLock = FALSE; + // GuiData->WindowSizeLock = TRUE; + // GuiConsoleResizeWindow(GuiData); + // GuiData->WindowSizeLock = FALSE; + // NOTE: This code ^^ causes deadlocks... + + PostMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0); } static BOOL WINAPI @@ -2222,24 +2250,40 @@ static VOID WINAPI GuiGetLargestConsoleWindowSize(PCONSOLE Console, PCOORD pSize) { PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; - HWND hDesktop; - RECT desktop; + RECT WorkArea; LONG width, height; + UINT WidthUnit, HeightUnit; if (!pSize) return; - /* - * This is one solution. Surely better solutions exist : - * http://stackoverflow.com/questions/4631292/how-detect-current-screen-resolution - * http://www.clearevo.com/blog/programming/2011/08/30/windows_c_c++_-_get_monitor_display_screen_size_in_pixels.html - */ - hDesktop = GetDesktopWindow(); - if (!hDesktop) return; + if (!SystemParametersInfoW(SPI_GETWORKAREA, 0, &WorkArea, 0)) + { + DPRINT1("SystemParametersInfoW failed - What to do ??\n"); + return; + } - GetWindowRect(hDesktop, &desktop); + if (Console->ActiveBuffer) + { + if (GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER) + { + WidthUnit = GuiData->CharWidth ; + HeightUnit = GuiData->CharHeight; + } + else /* if (GetType(Console->ActiveBuffer) == GRAPHICS_BUFFER) */ + { + WidthUnit = 1; + HeightUnit = 1; + } + } + else + { + /* Default: text mode */ + WidthUnit = GuiData->CharWidth ; + HeightUnit = GuiData->CharHeight; + } - width = desktop.right; - height = desktop.bottom; + width = WorkArea.right; + height = WorkArea.bottom; width -= (2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE))); height -= (2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION)); @@ -2247,26 +2291,53 @@ GuiGetLargestConsoleWindowSize(PCONSOLE Console, PCOORD pSize) if (width < 0) width = 0; if (height < 0) height = 0; - pSize->X = (SHORT)(width / GuiData->CharWidth ); - pSize->Y = (SHORT)(height / GuiData->CharHeight); + pSize->X = (SHORT)(width / (int)WidthUnit ) /* HACK */ + 2; + pSize->Y = (SHORT)(height / (int)HeightUnit) /* HACK */ + 1; +} + +static ULONG WINAPI +GuiGetDisplayMode(PCONSOLE Console) +{ + PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + ULONG DisplayMode = 0; + + if (GuiData->GuiInfo.FullScreen) + DisplayMode |= CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN + else + DisplayMode |= CONSOLE_WINDOWED; + + return DisplayMode; +} + +static BOOL WINAPI +GuiSetDisplayMode(PCONSOLE Console, ULONG NewMode) +{ + PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + + if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE)) + return FALSE; + + GuiData->GuiInfo.FullScreen = (NewMode & CONSOLE_FULLSCREEN_MODE); + // TODO: Change the display mode + return TRUE; } static FRONTEND_VTBL GuiVtbl = { GuiCleanupConsole, - GuiWriteStream, GuiDrawRegion, + GuiWriteStream, GuiSetCursorInfo, GuiSetScreenInfo, - GuiUpdateScreenInfo, - GuiIsBufferResizeSupported, GuiResizeTerminal, GuiProcessKeyCallback, GuiRefreshInternalInfo, GuiChangeTitle, GuiChangeIcon, GuiGetConsoleWindowHandle, - GuiGetLargestConsoleWindowSize + GuiGetLargestConsoleWindowSize, + GuiGetDisplayMode, + GuiSetDisplayMode, }; NTSTATUS FASTCALL @@ -2300,6 +2371,9 @@ GuiInitConsole(PCONSOLE Console, GuiData->Console = Console; GuiData->hWindow = NULL; + /* The console can be resized */ + Console->FixedSize = FALSE; + InitializeCriticalSection(&GuiData->Lock); @@ -2335,12 +2409,10 @@ GuiInitConsole(PCONSOLE Console, TermInfo.AutoPosition = FALSE; TermInfo.WindowOrigin = ConsoleStartInfo->ConsoleWindowOrigin; } - /* if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN) { - ConsoleInfo.FullScreen = TRUE; + TermInfo.FullScreen = TRUE; } - */ } @@ -2355,6 +2427,7 @@ GuiInitConsole(PCONSOLE Console, GuiData->GuiInfo.FontSize = TermInfo.FontSize; GuiData->GuiInfo.FontWeight = TermInfo.FontWeight; GuiData->GuiInfo.UseRasterFonts = TermInfo.UseRasterFonts; + GuiData->GuiInfo.FullScreen = TermInfo.FullScreen; GuiData->GuiInfo.ShowWindow = TermInfo.ShowWindow; GuiData->GuiInfo.AutoPosition = TermInfo.AutoPosition; GuiData->GuiInfo.WindowOrigin = TermInfo.WindowOrigin; diff --git a/reactos/win32ss/user/consrv/frontends/gui/text.c b/reactos/win32ss/user/consrv/frontends/gui/text.c new file mode 100644 index 00000000000..cdfedf41b14 --- /dev/null +++ b/reactos/win32ss/user/consrv/frontends/gui/text.c @@ -0,0 +1,281 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Console Server DLL + * FILE: win32ss/user/consrv/frontends/gui/text.c + * PURPOSE: GUI Terminal Front-End - Support for text-mode screen-buffers + * PROGRAMMERS: Gé van Geldorp + * Johannes Anderwald + * Jeffrey Morlan + * Hermes Belusca-Maito (hermes.belusca@sfr.fr) + */ + +/* INCLUDES *******************************************************************/ + +#include "consrv.h" +#include "include/conio.h" +#include "include/settings.h" +#include "guisettings.h" + +#define NDEBUG +#include + + +/* GLOBALS ********************************************************************/ + +/* Copied from consrv/text.c */ +#define ConsoleAnsiCharToUnicodeChar(Console, dWChar, sChar) \ + MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1) + + +/* FUNCTIONS ******************************************************************/ + +VOID +GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer) +{ + /* + * This function supposes that the system clipboard was opened. + */ + + PCONSOLE Console = Buffer->Header.Console; + + HANDLE hData; + PBYTE ptr; + LPWSTR data, dstPos; + ULONG selWidth, selHeight; + ULONG xPos, yPos, size; + + selWidth = Console->Selection.srSelection.Right - Console->Selection.srSelection.Left + 1; + selHeight = Console->Selection.srSelection.Bottom - Console->Selection.srSelection.Top + 1; + DPRINT("Selection is (%d|%d) to (%d|%d)\n", + Console->Selection.srSelection.Left, + Console->Selection.srSelection.Top, + Console->Selection.srSelection.Right, + Console->Selection.srSelection.Bottom); + + /* Basic size for one line and termination */ + size = selWidth + 1; + if (selHeight > 0) + { + /* Multiple line selections have to get \r\n appended */ + size += ((selWidth + 2) * (selHeight - 1)); + } + size *= sizeof(WCHAR); + + /* Allocate memory, it will be passed to the system and may not be freed here */ + hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size); + if (hData == NULL) return; + + data = GlobalLock(hData); + if (data == NULL) return; + + DPRINT("Copying %dx%d selection\n", selWidth, selHeight); + dstPos = data; + + for (yPos = 0; yPos < selHeight; yPos++) + { + ptr = ConioCoordToPointer(Buffer, + Console->Selection.srSelection.Left, + yPos + Console->Selection.srSelection.Top); + /* Copy only the characters, leave attributes alone */ + for (xPos = 0; xPos < selWidth; xPos++) + { + ConsoleAnsiCharToUnicodeChar(Console, &dstPos[xPos], (LPCSTR)&ptr[xPos * 2]); + } + dstPos += selWidth; + if (yPos != (selHeight - 1)) + { + wcscat(data, L"\r\n"); + dstPos += 2; + } + } + + DPRINT("Setting data <%S> to clipboard\n", data); + GlobalUnlock(hData); + + EmptyClipboard(); + SetClipboardData(CF_UNICODETEXT, hData); +} + +VOID +GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer) +{ + /* + * This function supposes that the system clipboard was opened. + */ + + PCONSOLE Console = Buffer->Header.Console; + + HANDLE hData; + LPWSTR str; + WCHAR CurChar = 0; + + SHORT VkKey; // MAKEWORD(low = vkey_code, high = shift_state); + INPUT_RECORD er; + + hData = GetClipboardData(CF_UNICODETEXT); + if (hData == NULL) return; + + str = GlobalLock(hData); + if (str == NULL) return; + + DPRINT("Got data <%S> from clipboard\n", str); + + er.EventType = KEY_EVENT; + er.Event.KeyEvent.wRepeatCount = 1; + while (*str) + { + /* \r or \n characters. Go to the line only if we get "\r\n" sequence. */ + if (CurChar == L'\r' && *str == L'\n') + { + str++; + continue; + } + CurChar = *str++; + + /* Get the key code (+ shift state) corresponding to the character */ + VkKey = VkKeyScanW(CurChar); + if (VkKey == 0xFFFF) + { + DPRINT1("VkKeyScanW failed - Should simulate the key...\n"); + continue; + } + + /* Pressing some control keys */ + + /* Pressing the character key, with the control keys maintained pressed */ + er.Event.KeyEvent.bKeyDown = TRUE; + er.Event.KeyEvent.wVirtualKeyCode = LOBYTE(VkKey); + er.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(LOBYTE(VkKey), MAPVK_VK_TO_CHAR); + er.Event.KeyEvent.uChar.UnicodeChar = CurChar; + er.Event.KeyEvent.dwControlKeyState = 0; + if (HIBYTE(VkKey) & 1) + er.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; + if (HIBYTE(VkKey) & 2) + er.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; // RIGHT_CTRL_PRESSED; + if (HIBYTE(VkKey) & 4) + er.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; // RIGHT_ALT_PRESSED; + + ConioProcessInputEvent(Console, &er); + + /* Up all the character and control keys */ + er.Event.KeyEvent.bKeyDown = FALSE; + ConioProcessInputEvent(Console, &er); + } + + GlobalUnlock(hData); +} + +VOID +GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer, + PGUI_CONSOLE_DATA GuiData, + HDC hDC, + PRECT rc) +{ + PCONSOLE Console = Buffer->Header.Console; + // ASSERT(Console == GuiData->Console); + + ULONG TopLine, BottomLine, LeftChar, RightChar; + ULONG Line, Char, Start; + PBYTE From; + PWCHAR To; + BYTE LastAttribute, Attribute; + ULONG CursorX, CursorY, CursorHeight; + HBRUSH CursorBrush, OldBrush; + HFONT OldFont; + + if (Buffer->Buffer == NULL) return; + + TopLine = rc->top / GuiData->CharHeight + Buffer->ViewOrigin.Y; + BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1 + Buffer->ViewOrigin.Y; + LeftChar = rc->left / GuiData->CharWidth + Buffer->ViewOrigin.X; + RightChar = (rc->right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1 + Buffer->ViewOrigin.X; + LastAttribute = ConioCoordToPointer(Buffer, LeftChar, TopLine)[1]; + + SetTextColor(hDC, RGBFromAttrib(Console, TextAttribFromAttrib(LastAttribute))); + SetBkColor(hDC, RGBFromAttrib(Console, BkgdAttribFromAttrib(LastAttribute))); + + if (BottomLine >= Buffer->ScreenBufferSize.Y) BottomLine = Buffer->ScreenBufferSize.Y - 1; + if (RightChar >= Buffer->ScreenBufferSize.X) RightChar = Buffer->ScreenBufferSize.X - 1; + + OldFont = SelectObject(hDC, GuiData->Font); + + for (Line = TopLine; Line <= BottomLine; Line++) + { + WCHAR LineBuffer[80]; + From = ConioCoordToPointer(Buffer, LeftChar, Line); + Start = LeftChar; + To = LineBuffer; + + for (Char = LeftChar; Char <= RightChar; Char++) + { + if (*(From + 1) != LastAttribute || (Char - Start == sizeof(LineBuffer) / sizeof(WCHAR))) + { + TextOutW(hDC, + (Start - Buffer->ViewOrigin.X) * GuiData->CharWidth, + (Line - Buffer->ViewOrigin.Y) * GuiData->CharHeight, + LineBuffer, + Char - Start); + Start = Char; + To = LineBuffer; + Attribute = *(From + 1); + if (Attribute != LastAttribute) + { + SetTextColor(hDC, RGBFromAttrib(Console, TextAttribFromAttrib(Attribute))); + SetBkColor(hDC, RGBFromAttrib(Console, BkgdAttribFromAttrib(Attribute))); + LastAttribute = Attribute; + } + } + + MultiByteToWideChar(Console->OutputCodePage, + 0, (PCHAR)From, 1, To, 1); + To++; + From += 2; + } + + TextOutW(hDC, + (Start - Buffer->ViewOrigin.X) * GuiData->CharWidth, + (Line - Buffer->ViewOrigin.Y) * GuiData->CharHeight, + LineBuffer, + RightChar - Start + 1); + } + + /* + * Draw the caret + */ + if (Buffer->CursorInfo.bVisible && + Buffer->CursorBlinkOn && + !Buffer->ForceCursorOff) + { + CursorX = Buffer->CursorPosition.X; + CursorY = Buffer->CursorPosition.Y; + if (LeftChar <= CursorX && CursorX <= RightChar && + TopLine <= CursorY && CursorY <= BottomLine) + { + CursorHeight = ConioEffectiveCursorSize(Console, GuiData->CharHeight); + From = ConioCoordToPointer(Buffer, Buffer->CursorPosition.X, Buffer->CursorPosition.Y) + 1; + + if (*From != DEFAULT_SCREEN_ATTRIB) + { + CursorBrush = CreateSolidBrush(RGBFromAttrib(Console, *From)); + } + else + { + CursorBrush = CreateSolidBrush(RGBFromAttrib(Console, Buffer->ScreenDefaultAttrib)); + } + + OldBrush = SelectObject(hDC, CursorBrush); + PatBlt(hDC, + (CursorX - Buffer->ViewOrigin.X) * GuiData->CharWidth, + (CursorY - Buffer->ViewOrigin.Y) * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight), + GuiData->CharWidth, + CursorHeight, + PATCOPY); + SelectObject(hDC, OldBrush); + DeleteObject(CursorBrush); + } + } + + SelectObject(hDC, OldFont); +} + +/* EOF */ diff --git a/reactos/win32ss/user/consrv/frontends/tui/tuiterm.c b/reactos/win32ss/user/consrv/frontends/tui/tuiterm.c index b68133ac998..aa56b69c595 100644 --- a/reactos/win32ss/user/consrv/frontends/tui/tuiterm.c +++ b/reactos/win32ss/user/consrv/frontends/tui/tuiterm.c @@ -230,7 +230,7 @@ TuiSwapConsole(INT Next) } static VOID FASTCALL -TuiCopyRect(char *Dest, PCONSOLE_SCREEN_BUFFER Buff, SMALL_RECT* Region) +TuiCopyRect(char *Dest, PTEXTMODE_SCREEN_BUFFER Buff, SMALL_RECT* Region) { UINT SrcDelta, DestDelta; LONG i; @@ -476,21 +476,6 @@ TuiCleanupConsole(PCONSOLE Console) ConsoleFreeHeap(TuiData); } -static VOID WINAPI -TuiWriteStream(PCONSOLE Console, SMALL_RECT* Region, SHORT CursorStartX, SHORT CursorStartY, - UINT ScrolledLines, CHAR *Buffer, UINT Length) -{ - DWORD BytesWritten; - PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer; - - if (ActiveConsole->Console->ActiveBuffer != Buff) return; - - if (!WriteFile(ConsoleDeviceHandle, Buffer, Length, &BytesWritten, NULL)) - { - DPRINT1("Error writing to BlueScreen\n"); - } -} - static VOID WINAPI TuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region) { @@ -499,7 +484,7 @@ TuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region) PCONSOLE_DRAW ConsoleDraw; UINT ConsoleDrawSize; - if (ActiveConsole->Console != Console) return; + if (ActiveConsole->Console != Console || GetType(Buff) != TEXTMODE_BUFFER) return; ConsoleDrawSize = sizeof(CONSOLE_DRAW) + (ConioRectWidth(Region) * ConioRectHeight(Region)) * 2; @@ -516,7 +501,7 @@ TuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region) ConsoleDraw->CursorX = Buff->CursorPosition.X; ConsoleDraw->CursorY = Buff->CursorPosition.Y; - TuiCopyRect((char *) (ConsoleDraw + 1), Buff, Region); + TuiCopyRect((char*)(ConsoleDraw + 1), (PTEXTMODE_SCREEN_BUFFER)Buff, Region); if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW, NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL)) @@ -529,6 +514,21 @@ TuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region) ConsoleFreeHeap(ConsoleDraw); } +static VOID WINAPI +TuiWriteStream(PCONSOLE Console, SMALL_RECT* Region, SHORT CursorStartX, SHORT CursorStartY, + UINT ScrolledLines, CHAR *Buffer, UINT Length) +{ + DWORD BytesWritten; + PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer; + + if (ActiveConsole->Console->ActiveBuffer != Buff) return; + + if (!WriteFile(ConsoleDeviceHandle, Buffer, Length, &BytesWritten, NULL)) + { + DPRINT1("Error writing to BlueScreen\n"); + } +} + static BOOL WINAPI TuiSetCursorInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff) { @@ -557,9 +557,10 @@ TuiSetScreenInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff, SHORT OldCursorX DWORD BytesReturned; if (ActiveConsole->Console->ActiveBuffer != Buff) return TRUE; + if (GetType(Buff) != TEXTMODE_BUFFER) return FALSE; Info.dwCursorPosition = Buff->CursorPosition; - Info.wAttributes = Buff->ScreenDefaultAttrib; + Info.wAttributes = ((PTEXTMODE_SCREEN_BUFFER)Buff)->ScreenDefaultAttrib; if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &Info, sizeof(CONSOLE_SCREEN_BUFFER_INFO), NULL, 0, @@ -572,18 +573,6 @@ TuiSetScreenInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff, SHORT OldCursorX return TRUE; } -static BOOL WINAPI -TuiUpdateScreenInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff) -{ - return TRUE; -} - -static BOOL WINAPI -TuiIsBufferResizeSupported(PCONSOLE Console) -{ - return (Console && Console->State == CONSOLE_INITIALIZING ? TRUE : FALSE); -} - static VOID WINAPI TuiResizeTerminal(PCONSOLE Console) { @@ -640,22 +629,36 @@ TuiGetLargestConsoleWindowSize(PCONSOLE Console, PCOORD pSize) *pSize = PhysicalConsoleSize; } +static ULONG WINAPI +TuiGetDisplayMode(PCONSOLE Console) +{ + return CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN; +} + +static BOOL WINAPI +TuiSetDisplayMode(PCONSOLE Console, ULONG NewMode) +{ + // if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE)) + // return FALSE; + return TRUE; +} + static FRONTEND_VTBL TuiVtbl = { TuiCleanupConsole, - TuiWriteStream, TuiDrawRegion, + TuiWriteStream, TuiSetCursorInfo, TuiSetScreenInfo, - TuiUpdateScreenInfo, - TuiIsBufferResizeSupported, TuiResizeTerminal, TuiProcessKeyCallback, TuiRefreshInternalInfo, TuiChangeTitle, TuiChangeIcon, TuiGetConsoleWindowHandle, - TuiGetLargestConsoleWindowSize + TuiGetLargestConsoleWindowSize, + TuiGetDisplayMode, + TuiSetDisplayMode, }; NTSTATUS FASTCALL @@ -670,6 +673,9 @@ TuiInitConsole(PCONSOLE Console, if (Console == NULL || ConsoleInfo == NULL) return STATUS_INVALID_PARAMETER; + if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) + return STATUS_INVALID_PARAMETER; + /* Initialize the TUI terminal emulator */ if (!TuiInit(Console->CodePage)) return STATUS_UNSUCCESSFUL; @@ -693,8 +699,10 @@ TuiInitConsole(PCONSOLE Console, * the console size when we display it with the hardware. */ Console->ConsoleSize = PhysicalConsoleSize; - ConioResizeBuffer(Console, Console->ActiveBuffer, PhysicalConsoleSize); - Console->ActiveBuffer->DisplayMode |= CONSOLE_FULLSCREEN_MODE; + ConioResizeBuffer(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), PhysicalConsoleSize); + + /* The console cannot be resized anymore */ + Console->FixedSize = TRUE; // MUST be placed AFTER the call to ConioResizeBuffer !! // ConioResizeTerminal(Console); /* diff --git a/reactos/win32ss/user/consrv/graphics.c b/reactos/win32ss/user/consrv/graphics.c new file mode 100644 index 00000000000..51b6e79b599 --- /dev/null +++ b/reactos/win32ss/user/consrv/graphics.c @@ -0,0 +1,274 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Console Server DLL + * FILE: win32ss/user/consrv/graphics.c + * PURPOSE: Console Output Functions for graphics-mode screen-buffers + * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr) + * + * NOTE: See http://blog.airesoft.co.uk/2012/10/things-ms-can-do-that-they-dont-tell-you-about-console-graphics/ + * for more information. + */ + +/* INCLUDES *******************************************************************/ + +#include "consrv.h" +#include "include/conio.h" +#include "conio.h" +#include "conoutput.h" +#include "handle.h" + +#define NDEBUG +#include + + +/* PRIVATE FUNCTIONS **********************************************************/ + +CONSOLE_IO_OBJECT_TYPE +GRAPHICS_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This) +{ + // return This->Header.Type; + return GRAPHICS_BUFFER; +} + +static CONSOLE_SCREEN_BUFFER_VTBL GraphicsVtbl = +{ + GRAPHICS_BUFFER_GetType, +}; + + +NTSTATUS +CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer, + IN OUT PCONSOLE Console, + IN SIZE_T Size); +VOID +CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer); + + +NTSTATUS +GRAPHICS_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer, + IN OUT PCONSOLE Console, + IN PGRAPHICS_BUFFER_INFO GraphicsInfo) +{ + NTSTATUS Status = STATUS_SUCCESS; + PGRAPHICS_SCREEN_BUFFER NewBuffer = NULL; + + LARGE_INTEGER SectionSize; + ULONG ViewSize = 0; + HANDLE ProcessHandle; + + if (Buffer == NULL || Console == NULL || GraphicsInfo == NULL) + return STATUS_INVALID_PARAMETER; + + *Buffer = NULL; + + Status = CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER*)&NewBuffer, + Console, + sizeof(GRAPHICS_SCREEN_BUFFER)); + if (!NT_SUCCESS(Status)) return Status; + NewBuffer->Header.Type = GRAPHICS_BUFFER; + NewBuffer->Vtbl = &GraphicsVtbl; + + /* + * Remember the handle to the process so that we can close or unmap + * correctly the allocated resources when the client releases the + * screen buffer. + */ + ProcessHandle = CsrGetClientThread()->Process->ProcessHandle; + NewBuffer->ClientProcess = ProcessHandle; + + /* Get infos from the graphics buffer information structure */ + NewBuffer->BitMapInfoLength = GraphicsInfo->Info.dwBitMapInfoLength; + + NewBuffer->BitMapInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, NewBuffer->BitMapInfoLength); + if (NewBuffer->BitMapInfo == NULL) + { + CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Adjust the bitmap height if needed (bottom-top vs. top-bottom). Use always bottom-up. */ + if (GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight > 0) + GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight = -GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight; + + /* We do not use anything else than uncompressed bitmaps */ + if (GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biCompression != BI_RGB) + { + DPRINT1("biCompression == %d != BI_RGB, correct that!\n", GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biCompression); + GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biCompression = BI_RGB; + } + + RtlCopyMemory(NewBuffer->BitMapInfo, + GraphicsInfo->Info.lpBitMapInfo, + GraphicsInfo->Info.dwBitMapInfoLength); + + NewBuffer->BitMapUsage = GraphicsInfo->Info.dwUsage; + + /* Set the screen buffer size. Fight against overflows. */ + if ( GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biWidth <= 0xFFFF && + -GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight <= 0xFFFF ) + { + /* Be careful about the sign of biHeight */ + NewBuffer->ScreenBufferSize.X = (SHORT)GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biWidth ; + NewBuffer->ScreenBufferSize.Y = (SHORT)-GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight; + + NewBuffer->OldViewSize = NewBuffer->ViewSize = + NewBuffer->OldScreenBufferSize = NewBuffer->ScreenBufferSize; + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + ConsoleFreeHeap(NewBuffer->BitMapInfo); + CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); + goto Quit; + } + + /* + * Create a mutex to synchronize bitmap memory access + * between ourselves and the client. + */ + Status = NtCreateMutant(&NewBuffer->Mutex, MUTANT_ALL_ACCESS, NULL, FALSE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtCreateMutant() failed: %lu\n", Status); + ConsoleFreeHeap(NewBuffer->BitMapInfo); + CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); + goto Quit; + } + + /* + * Duplicate the Mutex for the client. We must keep a trace of it + * so that we can close it when the client releases the screen buffer. + */ + Status = NtDuplicateObject(NtCurrentProcess(), + NewBuffer->Mutex, + ProcessHandle, + &NewBuffer->ClientMutex, + 0, 0, DUPLICATE_SAME_ACCESS); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtDuplicateObject() failed: %lu\n", Status); + NtClose(NewBuffer->Mutex); + ConsoleFreeHeap(NewBuffer->BitMapInfo); + CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); + goto Quit; + } + + /* + * Create a memory section for the bitmap area, to share with the client. + */ + SectionSize.QuadPart = NewBuffer->BitMapInfo->bmiHeader.biSizeImage; + Status = NtCreateSection(&NewBuffer->hSection, + SECTION_ALL_ACCESS, + NULL, + &SectionSize, + PAGE_READWRITE, + SEC_COMMIT, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Error: Impossible to create a shared section ; Status = %lu\n", Status); + NtClose(NewBuffer->ClientMutex); + NtClose(NewBuffer->Mutex); + ConsoleFreeHeap(NewBuffer->BitMapInfo); + CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); + goto Quit; + } + + /* + * Create a view for our needs. + */ + ViewSize = 0; + NewBuffer->BitMap = NULL; + Status = NtMapViewOfSection(NewBuffer->hSection, + NtCurrentProcess(), + (PVOID*)&NewBuffer->BitMap, + 0, + 0, + NULL, + &ViewSize, + ViewUnmap, + 0, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status); + NtClose(NewBuffer->hSection); + NtClose(NewBuffer->ClientMutex); + NtClose(NewBuffer->Mutex); + ConsoleFreeHeap(NewBuffer->BitMapInfo); + CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); + goto Quit; + } + + /* + * Create a view for the client. We must keep a trace of it so that + * we can unmap it when the client releases the screen buffer. + */ + ViewSize = 0; + NewBuffer->ClientBitMap = NULL; + Status = NtMapViewOfSection(NewBuffer->hSection, + ProcessHandle, + (PVOID*)&NewBuffer->ClientBitMap, + 0, + 0, + NULL, + &ViewSize, + ViewUnmap, + 0, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status); + NtUnmapViewOfSection(NtCurrentProcess(), NewBuffer->BitMap); + NtClose(NewBuffer->hSection); + NtClose(NewBuffer->ClientMutex); + NtClose(NewBuffer->Mutex); + ConsoleFreeHeap(NewBuffer->BitMapInfo); + CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); + goto Quit; + } + + NewBuffer->ViewOrigin.X = NewBuffer->ViewOrigin.Y = 0; + NewBuffer->VirtualY = 0; + + NewBuffer->CursorBlinkOn = FALSE; + NewBuffer->ForceCursorOff = TRUE; + NewBuffer->CursorInfo.bVisible = FALSE; + NewBuffer->CursorInfo.dwSize = 0; + NewBuffer->CursorPosition.X = NewBuffer->CursorPosition.Y = 0; + + NewBuffer->Mode = 0; + + *Buffer = (PCONSOLE_SCREEN_BUFFER)NewBuffer; + Status = STATUS_SUCCESS; + +Quit: + return Status; +} + +VOID +GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer) +{ + PGRAPHICS_SCREEN_BUFFER Buff = (PGRAPHICS_SCREEN_BUFFER)Buffer; + + /* + * IMPORTANT !! Reinitialize the type so that we don't enter a recursive + * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy. + */ + Buffer->Header.Type = SCREEN_BUFFER; + + /* + * Uninitialize the graphics screen buffer + * in the reverse way we initialized it. + */ + NtUnmapViewOfSection(Buff->ClientProcess, Buff->ClientBitMap); + NtUnmapViewOfSection(NtCurrentProcess(), Buff->BitMap); + NtClose(Buff->hSection); + NtClose(Buff->ClientMutex); + NtClose(Buff->Mutex); + ConsoleFreeHeap(Buff->BitMapInfo); + + CONSOLE_SCREEN_BUFFER_Destroy(Buffer); +} + +/* EOF */ diff --git a/reactos/win32ss/user/consrv/handle.c b/reactos/win32ss/user/consrv/handle.c index 6f5f9b38416..37c68685554 100644 --- a/reactos/win32ss/user/consrv/handle.c +++ b/reactos/win32ss/user/consrv/handle.c @@ -101,7 +101,7 @@ ConSrvCloseHandleEntry(PCONSOLE_IO_HANDLE Entry) /* If the last handle to a screen buffer is closed, delete it... */ if (AdjustHandleCounts(Entry, -1) == 0) { - if (Object->Type == SCREEN_BUFFER) + if (Object->Type == TEXTMODE_BUFFER || Object->Type == GRAPHICS_BUFFER) { PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object; /* ...unless it's the only buffer left. Windows allows deletion @@ -114,6 +114,10 @@ ConSrvCloseHandleEntry(PCONSOLE_IO_HANDLE Entry) { DPRINT("Closing the input buffer\n"); } + else + { + DPRINT1("Invalid object type %d\n", Object->Type); + } } /// LOCK /// LeaveCriticalSection(&Console->Lock); @@ -429,9 +433,10 @@ ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData, if ( HandleEntry == NULL || ObjectEntry == NULL || (HandleEntry->Access & Access) == 0 || - (Type != 0 && ObjectEntry->Type != Type) ) + /*(Type != 0 && ObjectEntry->Type != Type)*/ + (Type != 0 && (ObjectEntry->Type & Type) == 0) ) { - DPRINT1("ConSrvGetObject returning invalid handle (%x) of type %lu with access %lu\n", Handle, Type, Access); + DPRINT1("ConSrvGetObject returning invalid handle (%x) of type %lu with access %lu ; wanted type %lu with access %lu\n", Handle, ObjectEntry->Type, HandleEntry->Access, Type, Access); RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_INVALID_HANDLE; } diff --git a/reactos/win32ss/user/consrv/include/conio.h b/reactos/win32ss/user/consrv/include/conio.h index 96b1350d3fd..dc56a26361e 100644 --- a/reactos/win32ss/user/consrv/include/conio.h +++ b/reactos/win32ss/user/consrv/include/conio.h @@ -20,8 +20,11 @@ /* Object type magic numbers */ typedef enum _CONSOLE_IO_OBJECT_TYPE { - INPUT_BUFFER = 0x01, // --> Input-type handles - SCREEN_BUFFER = 0x02 // --> Output-type handles +// ANY_TYPE_BUFFER = 0x00, // --> Match any types of IO handles + TEXTMODE_BUFFER = 0x01, // --> Output-type handles for text SBs + GRAPHICS_BUFFER = 0x02, // --> Output-type handles for graphics SBs + SCREEN_BUFFER = 0x03, // --> Any SB type + INPUT_BUFFER = 0x04 // --> Input-type handles } CONSOLE_IO_OBJECT_TYPE; typedef struct _CONSOLE_IO_OBJECT @@ -33,6 +36,69 @@ typedef struct _CONSOLE_IO_OBJECT LONG HandleCount; } CONSOLE_IO_OBJECT, *PCONSOLE_IO_OBJECT; + +/******************************************************************************\ +|* *| +|* Abstract "class" for screen-buffers, be they text-mode or graphics *| +|* *| +\******************************************************************************/ + +/* + * See conoutput.c for the implementation + */ + +typedef struct _CONSOLE_SCREEN_BUFFER CONSOLE_SCREEN_BUFFER, + *PCONSOLE_SCREEN_BUFFER; + +typedef struct _CONSOLE_SCREEN_BUFFER_VTBL +{ + CONSOLE_IO_OBJECT_TYPE (*GetType)(PCONSOLE_SCREEN_BUFFER This); +} CONSOLE_SCREEN_BUFFER_VTBL, *PCONSOLE_SCREEN_BUFFER_VTBL; + +#define GetType(This) (This)->Vtbl->GetType(This) + +struct _CONSOLE_SCREEN_BUFFER +{ + CONSOLE_IO_OBJECT Header; /* Object header - MUST BE IN FIRST PLACE */ + PCONSOLE_SCREEN_BUFFER_VTBL Vtbl; /* Virtual table */ + + LIST_ENTRY ListEntry; /* Entry in console's list of buffers */ + + COORD ScreenBufferSize; /* Size of this screen buffer. (Rows, Columns) for text-mode and (Width, Height) for graphics */ + COORD ViewSize; /* Associated "view" (i.e. console) size */ + + COORD OldScreenBufferSize; /* Old size of this screen buffer */ + COORD OldViewSize; /* Old associated view size */ + + COORD ViewOrigin; /* Beginning offset for the actual display area */ + +/***** Put that VV in TEXTMODE_SCREEN_BUFFER ?? *****/ + USHORT VirtualY; /* Top row of buffer being displayed, reported to callers */ + + COORD CursorPosition; /* Current cursor position */ + BOOLEAN CursorBlinkOn; + BOOLEAN ForceCursorOff; +// ULONG CursorSize; + CONSOLE_CURSOR_INFO CursorInfo; // FIXME: Keep this member or not ?? +/*********************************************/ + +// WORD ScreenDefaultAttrib; /* Default screen char attribute */ +// WORD PopupDefaultAttrib; /* Default popup char attribute */ + USHORT Mode; /* Output buffer modes */ +}; + + + +/******************************************************************************\ +|* *| +|* Text-mode and graphics-mode screen-buffer "classes" *| +|* *| +\******************************************************************************/ + +/* + * See text.c for the implementation + */ + /************************************************************************ * Screen buffer structure represents the win32 screen buffer object. * * Internally, the portion of the buffer being shown CAN loop past the * @@ -49,40 +115,62 @@ typedef struct _CONSOLE_IO_OBJECT * internally, I just wrap back to the top of the buffer. * ************************************************************************/ -typedef struct _CONSOLE_SCREEN_BUFFER +typedef struct _TEXTMODE_BUFFER_INFO { - CONSOLE_IO_OBJECT Header; /* Object header */ - LIST_ENTRY ListEntry; /* Entry in console's list of buffers */ + COORD ScreenBufferSize; + USHORT ScreenAttrib; + USHORT PopupAttrib; + BOOLEAN IsCursorVisible; + ULONG CursorSize; +} TEXTMODE_BUFFER_INFO, *PTEXTMODE_BUFFER_INFO; + +typedef struct _TEXTMODE_SCREEN_BUFFER +{ + CONSOLE_SCREEN_BUFFER; /* Screen buffer base class - MUST BE IN FIRST PLACE */ BYTE *Buffer; /* CHAR_INFO */ /* Pointer to screen buffer */ - COORD ScreenBufferSize; /* Size of this screen buffer */ - COORD CursorPosition; /* Current cursor position */ - - USHORT ShowX, ShowY; /* Beginning offset for the actual display area */ - USHORT VirtualY; /* Top row of buffer being displayed, reported to callers */ - - BOOLEAN CursorBlinkOn; - BOOLEAN ForceCursorOff; - // ULONG CursorSize; - CONSOLE_CURSOR_INFO CursorInfo; // FIXME: Keep this member or not ?? - WORD ScreenDefaultAttrib; /* Default screen char attribute */ WORD PopupDefaultAttrib; /* Default popup char attribute */ - USHORT Mode; - ULONG DisplayMode; -} CONSOLE_SCREEN_BUFFER, *PCONSOLE_SCREEN_BUFFER; +} TEXTMODE_SCREEN_BUFFER, *PTEXTMODE_SCREEN_BUFFER; + + +/* + * See graphics.c for the implementation + */ + +typedef struct _GRAPHICS_BUFFER_INFO +{ + CONSOLE_GRAPHICS_BUFFER_INFO Info; +} GRAPHICS_BUFFER_INFO, *PGRAPHICS_BUFFER_INFO; + +typedef struct _GRAPHICS_SCREEN_BUFFER +{ + CONSOLE_SCREEN_BUFFER; /* Screen buffer base class - MUST BE IN FIRST PLACE */ + + ULONG BitMapInfoLength; /* Real size of the structure pointed by BitMapInfo */ + LPBITMAPINFO BitMapInfo; /* Information on the bitmap buffer */ + ULONG BitMapUsage; /* See the uUsage parameter of GetDIBits */ + HANDLE hSection; /* Handle to the memory shared section for the bitmap buffer */ + PVOID BitMap; /* Our bitmap buffer */ + PVOID ClientBitMap; /* A copy of the client view of our bitmap buffer */ + HANDLE Mutex; /* Our mutex, used to synchronize read / writes to the bitmap buffer */ + HANDLE ClientMutex; /* A copy of the client handle to our mutex */ + HANDLE ClientProcess; /* Handle to the client process who opened the buffer, to unmap the view */ +} GRAPHICS_SCREEN_BUFFER, *PGRAPHICS_SCREEN_BUFFER; + + typedef struct _CONSOLE_INPUT_BUFFER { - CONSOLE_IO_OBJECT Header; /* Object header */ + CONSOLE_IO_OBJECT Header; /* Object header - MUST BE IN FIRST PLACE */ - ULONG InputBufferSize; /* Size of this input buffer */ - LIST_ENTRY InputEvents; /* List head for input event queue */ - HANDLE ActiveEvent; /* Event set when an input event is added in its queue */ - LIST_ENTRY ReadWaitQueue; /* List head for the queue of read wait blocks */ + ULONG InputBufferSize; /* Size of this input buffer */ + LIST_ENTRY InputEvents; /* List head for input event queue */ + HANDLE ActiveEvent; /* Event set when an input event is added in its queue */ + LIST_ENTRY ReadWaitQueue; /* List head for the queue of read wait blocks */ - USHORT Mode; /* Console Input Buffer mode flags */ + USHORT Mode; /* Input buffer modes */ } CONSOLE_INPUT_BUFFER, *PCONSOLE_INPUT_BUFFER; typedef struct _FRONTEND_VTBL @@ -90,7 +178,12 @@ typedef struct _FRONTEND_VTBL /* * Internal interface (functions called by the console server only) */ + // BOOL (WINAPI *Init)(); VOID (WINAPI *CleanupConsole)(struct _CONSOLE* Console); + /* Interface used for both text-mode and graphics screen buffers */ + VOID (WINAPI *DrawRegion)(struct _CONSOLE* Console, + SMALL_RECT* Region); + /* Interface used only for text-mode screen buffers */ VOID (WINAPI *WriteStream)(struct _CONSOLE* Console, SMALL_RECT* Block, SHORT CursorStartX, @@ -98,17 +191,12 @@ typedef struct _FRONTEND_VTBL UINT ScrolledLines, CHAR *Buffer, UINT Length); - VOID (WINAPI *DrawRegion)(struct _CONSOLE* Console, - SMALL_RECT* Region); BOOL (WINAPI *SetCursorInfo)(struct _CONSOLE* Console, PCONSOLE_SCREEN_BUFFER ScreenBuffer); BOOL (WINAPI *SetScreenInfo)(struct _CONSOLE* Console, PCONSOLE_SCREEN_BUFFER ScreenBuffer, SHORT OldCursorX, SHORT OldCursorY); - BOOL (WINAPI *UpdateScreenInfo)(struct _CONSOLE* Console, - PCONSOLE_SCREEN_BUFFER ScreenBuffer); - BOOL (WINAPI *IsBufferResizeSupported)(struct _CONSOLE* Console); VOID (WINAPI *ResizeTerminal)(struct _CONSOLE* Console); BOOL (WINAPI *ProcessKeyCallback)(struct _CONSOLE* Console, MSG* msg, @@ -127,7 +215,20 @@ typedef struct _FRONTEND_VTBL HWND (WINAPI *GetConsoleWindowHandle)(struct _CONSOLE* Console); VOID (WINAPI *GetLargestConsoleWindowSize)(struct _CONSOLE* Console, PCOORD pSize); + ULONG (WINAPI *GetDisplayMode)(struct _CONSOLE* Console); + BOOL (WINAPI *SetDisplayMode)(struct _CONSOLE* Console, + ULONG NewMode); +#if 0 // Possible future front-end interface + BOOL (WINAPI *GetFrontEndProperty)(struct _CONSOLE* Console, + ULONG Flag, + PVOID Info, + ULONG Size); + BOOL (WINAPI *SetFrontEndProperty)(struct _CONSOLE* Console, + ULONG Flag, + PVOID Info /*, + ULONG Size */); +#endif } FRONTEND_VTBL, *PFRONTEND_VTBL; typedef struct _FRONTEND_IFACE @@ -160,8 +261,9 @@ typedef struct _CONSOLE FRONTEND_IFACE TermIFace; /* Frontend-specific interface */ /**************************** Input buffer and data ***************************/ - CONSOLE_INPUT_BUFFER InputBuffer; /* Input buffer of the console */ + CONSOLE_INPUT_BUFFER InputBuffer; /* Input buffer of the console */ + /** Put those things in TEXTMODE_SCREEN_BUFFER ?? **/ PWCHAR LineBuffer; /* Current line being input, in line buffered mode */ WORD LineMaxSize; /* Maximum size of line in characters (including CR+LF) */ WORD LineSize; /* Current size of line */ @@ -170,6 +272,7 @@ typedef struct _CONSOLE BOOLEAN LineUpPressed; BOOLEAN LineInsertToggle; /* Replace character over cursor instead of inserting */ ULONG LineWakeupMask; /* Bitmap of which control characters will end line input */ + /***************************************************/ BOOLEAN QuickEdit; BOOLEAN InsertMode; @@ -186,8 +289,6 @@ typedef struct _CONSOLE HANDLE UnpauseEvent; LIST_ENTRY WriteWaitQueue; /* List head for the queue of write wait blocks */ - ULONG HardwareState; /* _GDI_MANAGED, _DIRECT */ - /**************************** Aliases and Histories ***************************/ struct _ALIAS_HEADER *Aliases; LIST_ENTRY HistoryBuffers; @@ -196,10 +297,12 @@ typedef struct _CONSOLE BOOLEAN HistoryNoDup; /* Remove old duplicate history entries */ /****************************** Other properties ******************************/ - UNICODE_STRING OriginalTitle; /* Original title of console, the one when the console leader is launched. Always NULL-terminated */ + UNICODE_STRING OriginalTitle; /* Original title of console, the one defined when the console leader is launched; it never changes. Always NULL-terminated */ UNICODE_STRING Title; /* Title of console. Always NULL-terminated */ -/* SIZE */ COORD ConsoleSize; /* The size of the console */ + COORD ConsoleSize; /* The current size of the console, for text-mode only */ + BOOLEAN FixedSize; /* TRUE if the console is of fixed size */ + COLORREF Colors[16]; /* Colour palette */ } CONSOLE, *PCONSOLE; @@ -222,23 +325,30 @@ NTSTATUS FASTCALL ConioProcessInputEvent(PCONSOLE Console, PINPUT_RECORD InputEvent); /* conoutput.c */ +#define ConioInitRect(Rect, top, left, bottom, right) \ +do { \ + ((Rect)->Top) = top; \ + ((Rect)->Left) = left; \ + ((Rect)->Bottom) = bottom; \ + ((Rect)->Right) = right; \ +} while (0) +#define ConioIsRectEmpty(Rect) \ + (((Rect)->Left > (Rect)->Right) || ((Rect)->Top > (Rect)->Bottom)) #define ConioRectHeight(Rect) \ (((Rect)->Top) > ((Rect)->Bottom) ? 0 : ((Rect)->Bottom) - ((Rect)->Top) + 1) #define ConioRectWidth(Rect) \ (((Rect)->Left) > ((Rect)->Right) ? 0 : ((Rect)->Right) - ((Rect)->Left) + 1) -PBYTE FASTCALL ConioCoordToPointer(PCONSOLE_SCREEN_BUFFER Buf, - ULONG X, - ULONG Y); +PBYTE ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff, ULONG X, ULONG Y); VOID FASTCALL ConioDrawConsole(PCONSOLE Console); -NTSTATUS FASTCALL ConioResizeBuffer(PCONSOLE Console, - PCONSOLE_SCREEN_BUFFER ScreenBuffer, - COORD Size); -NTSTATUS FASTCALL ConioWriteConsole(PCONSOLE Console, - PCONSOLE_SCREEN_BUFFER Buff, - CHAR *Buffer, - DWORD Length, - BOOL Attrib); +NTSTATUS ConioResizeBuffer(PCONSOLE Console, + PTEXTMODE_SCREEN_BUFFER ScreenBuffer, + COORD Size); +NTSTATUS ConioWriteConsole(PCONSOLE Console, + PTEXTMODE_SCREEN_BUFFER Buff, + CHAR *Buffer, + DWORD Length, + BOOL Attrib); DWORD FASTCALL ConioEffectiveCursorSize(PCONSOLE Console, DWORD Scale); diff --git a/reactos/win32ss/user/consrv/include/settings.h b/reactos/win32ss/user/consrv/include/settings.h index fa324a2eb74..551ccdca64f 100644 --- a/reactos/win32ss/user/consrv/include/settings.h +++ b/reactos/win32ss/user/consrv/include/settings.h @@ -29,12 +29,11 @@ typedef struct _CONSOLE_INFO ULONG NumberOfHistoryBuffers; BOOLEAN HistoryNoDup; -/* BOOLEAN */ ULONG FullScreen; /* Give the type of console: GUI (windowed) or TUI (fullscreen) */ BOOLEAN QuickEdit; BOOLEAN InsertMode; - ULONG InputBufferSize; - COORD ScreenBufferSize; -/* SIZE */ COORD ConsoleSize; /* The size of the console */ + ULONG InputBufferSize; + COORD ScreenBufferSize; + COORD ConsoleSize; /* The size of the console */ BOOLEAN CursorBlinkOn; BOOLEAN ForceCursorOff; @@ -66,7 +65,7 @@ typedef struct _CONSOLE_PROPS BOOLEAN AppliedConfig; DWORD ActiveStaticControl; - CONSOLE_INFO ci; /* Console-specific informations */ + CONSOLE_INFO ci; /* Console-specific informations */ TERMINAL_INFO TerminalInfo; /* Frontend-specific parameters */ } CONSOLE_PROPS, *PCONSOLE_PROPS; diff --git a/reactos/win32ss/user/consrv/init.c b/reactos/win32ss/user/consrv/init.c index 4512dad7ff8..028627e7b81 100644 --- a/reactos/win32ss/user/consrv/init.c +++ b/reactos/win32ss/user/consrv/init.c @@ -70,7 +70,7 @@ PCSR_API_ROUTINE ConsoleServerApiDispatchTable[ConsolepMaxApiNumber - CONSRV_FIR SrvGetConsoleTitle, SrvSetConsoleTitle, SrvCreateConsoleScreenBuffer, - // SrvInvalidateBitMapRect, + SrvInvalidateBitMapRect, // SrvVDMConsoleOperation, // SrvSetConsoleCursor, // SrvShowConsoleCursor, @@ -161,7 +161,7 @@ BOOLEAN ConsoleServerApiServerValidTable[ConsolepMaxApiNumber - CONSRV_FIRST_API FALSE, // SrvGetConsoleTitle, FALSE, // SrvSetConsoleTitle, FALSE, // SrvCreateConsoleScreenBuffer, - // FALSE, // SrvInvalidateBitMapRect, + FALSE, // SrvInvalidateBitMapRect, // FALSE, // SrvVDMConsoleOperation, // FALSE, // SrvSetConsoleCursor, // FALSE, // SrvShowConsoleCursor, @@ -252,7 +252,7 @@ PCHAR ConsoleServerApiNameTable[ConsolepMaxApiNumber - CONSRV_FIRST_API_NUMBER] "GetConsoleTitle", "SetConsoleTitle", "CreateConsoleScreenBuffer", - // "InvalidateBitMapRect", + "InvalidateBitMapRect", // "VDMConsoleOperation", // "SetConsoleCursor", // "ShowConsoleCursor", diff --git a/reactos/win32ss/user/consrv/lineinput.c b/reactos/win32ss/user/consrv/lineinput.c index 224d6781ceb..3e090a9265a 100644 --- a/reactos/win32ss/user/consrv/lineinput.c +++ b/reactos/win32ss/user/consrv/lineinput.c @@ -46,8 +46,7 @@ HistoryCurrentBuffer(PCONSOLE Console) /* Couldn't find the buffer, create a new one */ Hist = ConsoleAllocHeap(0, sizeof(HISTORY_BUFFER) + ExeName.Length); - if (!Hist) - return NULL; + if (!Hist) return NULL; Hist->MaxEntries = Console->HistoryBufferSize; Hist->NumEntries = 0; Hist->Entries = ConsoleAllocHeap(0, Hist->MaxEntries * sizeof(UNICODE_STRING)); @@ -194,10 +193,14 @@ LineInputSetPos(PCONSOLE Console, UINT Pos) static VOID LineInputEdit(PCONSOLE Console, UINT NumToDelete, UINT NumToInsert, WCHAR *Insertion) { + PTEXTMODE_SCREEN_BUFFER ActiveBuffer; UINT Pos = Console->LinePos; UINT NewSize = Console->LineSize - NumToDelete + NumToInsert; UINT i; + if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) return; + ActiveBuffer = (PTEXTMODE_SCREEN_BUFFER)Console->ActiveBuffer; + /* Make sure there's always enough room for ending \r\n */ if (NewSize + 2 > Console->LineMaxSize) return; @@ -215,11 +218,11 @@ LineInputEdit(PCONSOLE Console, UINT NumToDelete, UINT NumToInsert, WCHAR *Inser WideCharToMultiByte(Console->OutputCodePage, 0, &Console->LineBuffer[i], 1, &AsciiChar, 1, NULL, NULL); - ConioWriteConsole(Console, Console->ActiveBuffer, &AsciiChar, 1, TRUE); + ConioWriteConsole(Console, ActiveBuffer, &AsciiChar, 1, TRUE); } for (; i < Console->LineSize; i++) { - ConioWriteConsole(Console, Console->ActiveBuffer, " ", 1, TRUE); + ConioWriteConsole(Console, ActiveBuffer, " ", 1, TRUE); } Console->LinePos = i; } @@ -407,7 +410,12 @@ LineInputKeyDown(PCONSOLE Console, KEY_EVENT_RECORD *KeyEvent) LineInputSetPos(Console, Console->LineSize); Console->LineBuffer[Console->LineSize++] = L'\r'; if (Console->InputBuffer.Mode & ENABLE_ECHO_INPUT) - ConioWriteConsole(Console, Console->ActiveBuffer, "\r", 1, TRUE); + { + if (GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER) + { + ConioWriteConsole(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), "\r", 1, TRUE); + } + } /* Add \n if processed input. There should usually be room for it, * but an exception to the rule exists: the buffer could have been @@ -417,7 +425,12 @@ LineInputKeyDown(PCONSOLE Console, KEY_EVENT_RECORD *KeyEvent) { Console->LineBuffer[Console->LineSize++] = L'\n'; if (Console->InputBuffer.Mode & ENABLE_ECHO_INPUT) - ConioWriteConsole(Console, Console->ActiveBuffer, "\n", 1, TRUE); + { + if (GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER) + { + ConioWriteConsole(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), "\n", 1, TRUE); + } + } } Console->LineComplete = TRUE; Console->LinePos = 0; diff --git a/reactos/win32ss/user/consrv/settings.c b/reactos/win32ss/user/consrv/settings.c index cb0079508b6..468eebe1da2 100644 --- a/reactos/win32ss/user/consrv/settings.c +++ b/reactos/win32ss/user/consrv/settings.c @@ -274,11 +274,6 @@ ConSrvReadUserSettings(IN OUT PCONSOLE_INFO ConsoleInfo, ConsoleInfo->HistoryNoDup = (BOOLEAN)Value; RetVal = TRUE; } - else if (!wcscmp(szValueName, L"FullScreen")) - { - ConsoleInfo->FullScreen = Value; - RetVal = TRUE; - } else if (!wcscmp(szValueName, L"QuickEdit")) { ConsoleInfo->QuickEdit = (BOOLEAN)Value; @@ -370,9 +365,6 @@ do { Storage = ConsoleInfo->HistoryNoDup; SetConsoleSetting(L"HistoryNoDup", REG_DWORD, sizeof(DWORD), &Storage, FALSE); - Storage = ConsoleInfo->FullScreen; - SetConsoleSetting(L"FullScreen", REG_DWORD, sizeof(DWORD), &Storage, FALSE); - Storage = ConsoleInfo->QuickEdit; SetConsoleSetting(L"QuickEdit", REG_DWORD, sizeof(DWORD), &Storage, FALSE); @@ -414,10 +406,11 @@ ConSrvGetDefaultSettings(IN OUT PCONSOLE_INFO ConsoleInfo, ConsoleInfo->NumberOfHistoryBuffers = 4; ConsoleInfo->HistoryNoDup = FALSE; - ConsoleInfo->FullScreen = FALSE; ConsoleInfo->QuickEdit = FALSE; ConsoleInfo->InsertMode = TRUE; // ConsoleInfo->InputBufferSize; + + // Rule: ScreenBufferSize >= ConsoleSize ConsoleInfo->ScreenBufferSize.X = 80; ConsoleInfo->ScreenBufferSize.Y = 300; ConsoleInfo->ConsoleSize.X = 80; @@ -452,17 +445,6 @@ ConSrvApplyUserSettings(IN PCONSOLE Console, IN PCONSOLE_INFO ConsoleInfo) { PCONSOLE_SCREEN_BUFFER ActiveBuffer = Console->ActiveBuffer; - COORD BufSize; - BOOL SizeChanged = FALSE; - - /* - * Apply full-screen mode. - */ - if (ConsoleInfo->FullScreen) - Console->ActiveBuffer->DisplayMode |= CONSOLE_FULLSCREEN_MODE; - else - Console->ActiveBuffer->DisplayMode &= ~CONSOLE_FULLSCREEN_MODE; - // TODO: Apply it really /* * Apply terminal-edition settings: @@ -476,9 +458,19 @@ ConSrvApplyUserSettings(IN PCONSOLE Console, * Apply foreground and background colors for both screen and popup * and copy the new palette. */ - ActiveBuffer->ScreenDefaultAttrib = ConsoleInfo->ScreenAttrib; - ActiveBuffer->PopupDefaultAttrib = ConsoleInfo->PopupAttrib; - memcpy(Console->Colors, ConsoleInfo->Colors, sizeof(s_Colors)); // FIXME: Possible buffer overflow if s_colors is bigger than pConInfo->Colors. + if (GetType(ActiveBuffer) == TEXTMODE_BUFFER) + { + PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)ActiveBuffer; + + Buffer->ScreenDefaultAttrib = ConsoleInfo->ScreenAttrib; + Buffer->PopupDefaultAttrib = ConsoleInfo->PopupAttrib; + } + else // if (Console->ActiveBuffer->Header.Type == GRAPHICS_BUFFER) + { + } + + // FIXME: Possible buffer overflow if s_colors is bigger than pConInfo->Colors. + memcpy(Console->Colors, ConsoleInfo->Colors, sizeof(s_Colors)); // TODO: Really update the screen attributes as FillConsoleOutputAttribute does. @@ -486,24 +478,99 @@ ConSrvApplyUserSettings(IN PCONSOLE Console, ActiveBuffer->CursorInfo.bVisible = (ConsoleInfo->CursorSize != 0); ActiveBuffer->CursorInfo.dwSize = min(max(ConsoleInfo->CursorSize, 0), 100); - /* Resize the console */ - if (ConsoleInfo->ConsoleSize.X != Console->ConsoleSize.X || - ConsoleInfo->ConsoleSize.Y != Console->ConsoleSize.Y) + if (GetType(ActiveBuffer) == TEXTMODE_BUFFER) { - Console->ConsoleSize = ConsoleInfo->ConsoleSize; - SizeChanged = TRUE; - } + PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)ActiveBuffer; + COORD BufSize; - /* Resize its active screen-buffer */ - BufSize = ConsoleInfo->ScreenBufferSize; - if (BufSize.X != ActiveBuffer->ScreenBufferSize.X || - BufSize.Y != ActiveBuffer->ScreenBufferSize.Y) + /* Resize its active screen-buffer */ + BufSize = ConsoleInfo->ScreenBufferSize; + + if (Console->FixedSize) + { + /* + * The console is in fixed-size mode, so we cannot resize anything + * at the moment. However, keep those settings somewhere so that + * we can try to set them up when we will be allowed to do so. + */ + if (ConsoleInfo->ConsoleSize.X != Buffer->OldViewSize.X || + ConsoleInfo->ConsoleSize.Y != Buffer->OldViewSize.Y) + { + Buffer->OldViewSize = ConsoleInfo->ConsoleSize; + } + + /* Buffer size is not allowed to be smaller than the view size */ + if (BufSize.X >= Buffer->OldViewSize.X && BufSize.Y >= Buffer->OldViewSize.Y) + { + if (BufSize.X != Buffer->OldScreenBufferSize.X || + BufSize.Y != Buffer->OldScreenBufferSize.Y) + { + /* + * The console is in fixed-size mode, so we cannot resize anything + * at the moment. However, keep those settings somewhere so that + * we can try to set them up when we will be allowed to do so. + */ + Buffer->OldScreenBufferSize = BufSize; + } + } + } + else + { + BOOL SizeChanged = FALSE; + + /* Resize the console */ + if (ConsoleInfo->ConsoleSize.X != Buffer->ViewSize.X || + ConsoleInfo->ConsoleSize.Y != Buffer->ViewSize.Y) + { + Buffer->ViewSize = ConsoleInfo->ConsoleSize; + SizeChanged = TRUE; + } + + /* Resize the screen-buffer */ + if (BufSize.X != Buffer->ScreenBufferSize.X || + BufSize.Y != Buffer->ScreenBufferSize.Y) + { + if (NT_SUCCESS(ConioResizeBuffer(Console, Buffer, BufSize))) + SizeChanged = TRUE; + } + + if (SizeChanged) ConioResizeTerminal(Console); + } + } + else // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) { - if (NT_SUCCESS(ConioResizeBuffer(Console, ActiveBuffer, BufSize))) - SizeChanged = TRUE; - } + PGRAPHICS_SCREEN_BUFFER Buffer = (PGRAPHICS_SCREEN_BUFFER)ActiveBuffer; - if (SizeChanged) ConioResizeTerminal(Console); + /* + * In any case we do NOT modify the size of the graphics screen-buffer. + * We just allow resizing the view only if the new size is smaller + * than the older one. + */ + + if (Console->FixedSize) + { + /* + * The console is in fixed-size mode, so we cannot resize anything + * at the moment. However, keep those settings somewhere so that + * we can try to set them up when we will be allowed to do so. + */ + if (ConsoleInfo->ConsoleSize.X <= Buffer->ViewSize.X || + ConsoleInfo->ConsoleSize.Y <= Buffer->ViewSize.Y) + { + Buffer->OldViewSize = ConsoleInfo->ConsoleSize; + } + } + else + { + /* Resize the view if its size is bigger than the specified size */ + if (ConsoleInfo->ConsoleSize.X <= Buffer->ViewSize.X || + ConsoleInfo->ConsoleSize.Y <= Buffer->ViewSize.Y) + { + Buffer->ViewSize = ConsoleInfo->ConsoleSize; + // SizeChanged = TRUE; + } + } + } } /* EOF */ diff --git a/reactos/win32ss/user/consrv/text.c b/reactos/win32ss/user/consrv/text.c new file mode 100644 index 00000000000..4712e6bb764 --- /dev/null +++ b/reactos/win32ss/user/consrv/text.c @@ -0,0 +1,1420 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Console Server DLL + * FILE: win32ss/user/consrv/text.c + * PURPOSE: Console Output Functions for text-mode screen-buffers + * PROGRAMMERS: Jeffrey Morlan + * Hermes Belusca-Maito (hermes.belusca@sfr.fr) + */ + +/* INCLUDES *******************************************************************/ + +#include "consrv.h" +#include "include/conio.h" +#include "conio.h" +#include "conoutput.h" +#include "handle.h" + +#define NDEBUG +#include + +/* +// Define wmemset(...) +#include +#define HAVE_WMEMSET +*/ + + +/* GLOBALS ********************************************************************/ + +#define TAB_WIDTH 8 + +#define ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \ + WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL) + +#define ConsoleAnsiCharToUnicodeChar(Console, dWChar, sChar) \ + MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1) + + +/* PRIVATE FUNCTIONS **********************************************************/ + +CONSOLE_IO_OBJECT_TYPE +TEXTMODE_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This) +{ + // return This->Header.Type; + return TEXTMODE_BUFFER; +} + +static CONSOLE_SCREEN_BUFFER_VTBL TextVtbl = +{ + TEXTMODE_BUFFER_GetType, +}; + + +static VOID FASTCALL +ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff); + + +NTSTATUS +CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer, + IN OUT PCONSOLE Console, + IN SIZE_T Size); +VOID +CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer); + + +NTSTATUS +TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer, + IN OUT PCONSOLE Console, + IN PTEXTMODE_BUFFER_INFO TextModeInfo) +{ + NTSTATUS Status = STATUS_SUCCESS; + PTEXTMODE_SCREEN_BUFFER NewBuffer = NULL; + + if (Console == NULL || Buffer == NULL || TextModeInfo == NULL) + return STATUS_INVALID_PARAMETER; + + *Buffer = NULL; + + Status = CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER*)&NewBuffer, + Console, + sizeof(TEXTMODE_SCREEN_BUFFER)); + if (!NT_SUCCESS(Status)) return Status; + NewBuffer->Header.Type = TEXTMODE_BUFFER; + NewBuffer->Vtbl = &TextVtbl; + + NewBuffer->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, + 2 * TextModeInfo->ScreenBufferSize.X + * TextModeInfo->ScreenBufferSize.Y); + if (NewBuffer->Buffer == NULL) + { + CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer); + return STATUS_INSUFFICIENT_RESOURCES; + } + + NewBuffer->ScreenBufferSize = NewBuffer->OldScreenBufferSize + = TextModeInfo->ScreenBufferSize; + NewBuffer->ViewSize = NewBuffer->OldViewSize + = Console->ConsoleSize; + + NewBuffer->ViewOrigin.X = NewBuffer->ViewOrigin.Y = 0; + NewBuffer->VirtualY = 0; + + NewBuffer->CursorBlinkOn = NewBuffer->ForceCursorOff = FALSE; + NewBuffer->CursorInfo.bVisible = (TextModeInfo->IsCursorVisible && (TextModeInfo->CursorSize != 0)); + NewBuffer->CursorInfo.dwSize = min(max(TextModeInfo->CursorSize, 0), 100); + + NewBuffer->ScreenDefaultAttrib = TextModeInfo->ScreenAttrib; + NewBuffer->PopupDefaultAttrib = TextModeInfo->PopupAttrib; + + /* Initialize buffer to be empty with default attributes */ + for (NewBuffer->CursorPosition.Y = 0 ; NewBuffer->CursorPosition.Y < NewBuffer->ScreenBufferSize.Y; NewBuffer->CursorPosition.Y++) + { + ClearLineBuffer(NewBuffer); + } + NewBuffer->CursorPosition.X = NewBuffer->CursorPosition.Y = 0; + + NewBuffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT; + + *Buffer = (PCONSOLE_SCREEN_BUFFER)NewBuffer; + return STATUS_SUCCESS; +} + +VOID +TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer) +{ + PTEXTMODE_SCREEN_BUFFER Buff = (PTEXTMODE_SCREEN_BUFFER)Buffer; + + /* + * IMPORTANT !! Reinitialize the type so that we don't enter a recursive + * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy. + */ + Buffer->Header.Type = SCREEN_BUFFER; + + ConsoleFreeHeap(Buff->Buffer); + + CONSOLE_SCREEN_BUFFER_Destroy(Buffer); +} + + +PBYTE +ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff, ULONG X, ULONG Y) +{ + return &Buff->Buffer[2 * (((Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y) * Buff->ScreenBufferSize.X + X)]; +} + +static VOID FASTCALL +ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff) +{ + PBYTE Ptr = ConioCoordToPointer(Buff, 0, Buff->CursorPosition.Y); + SHORT Pos; + + for (Pos = 0; Pos < Buff->ScreenBufferSize.X; Pos++) + { + /* Fill the cell */ + *Ptr++ = ' '; + *Ptr++ = (BYTE)Buff->ScreenDefaultAttrib; + } +} + +static __inline BOOLEAN ConioGetIntersection( + SMALL_RECT* Intersection, + SMALL_RECT* Rect1, + SMALL_RECT* Rect2) +{ + if ( ConioIsRectEmpty(Rect1) || + ConioIsRectEmpty(Rect2) || + (Rect1->Top > Rect2->Bottom) || + (Rect1->Left > Rect2->Right) || + (Rect1->Bottom < Rect2->Top) || + (Rect1->Right < Rect2->Left) ) + { + /* The rectangles do not intersect */ + ConioInitRect(Intersection, 0, -1, 0, -1); + return FALSE; + } + + ConioInitRect(Intersection, + max(Rect1->Top, Rect2->Top), + max(Rect1->Left, Rect2->Left), + min(Rect1->Bottom, Rect2->Bottom), + min(Rect1->Right, Rect2->Right)); + + return TRUE; +} + +static __inline BOOLEAN ConioGetUnion( + SMALL_RECT* Union, + SMALL_RECT* Rect1, + SMALL_RECT* Rect2) +{ + if (ConioIsRectEmpty(Rect1)) + { + if (ConioIsRectEmpty(Rect2)) + { + ConioInitRect(Union, 0, -1, 0, -1); + return FALSE; + } + else + { + *Union = *Rect2; + } + } + else if (ConioIsRectEmpty(Rect2)) + { + *Union = *Rect1; + } + else + { + ConioInitRect(Union, + min(Rect1->Top, Rect2->Top), + min(Rect1->Left, Rect2->Left), + max(Rect1->Bottom, Rect2->Bottom), + max(Rect1->Right, Rect2->Right)); + } + + return TRUE; +} + +static VOID FASTCALL +ConioComputeUpdateRect(PTEXTMODE_SCREEN_BUFFER Buff, SMALL_RECT* UpdateRect, PCOORD Start, UINT Length) +{ + if (Buff->ScreenBufferSize.X <= Start->X + Length) + { + UpdateRect->Left = 0; + } + else + { + UpdateRect->Left = Start->X; + } + if (Buff->ScreenBufferSize.X <= Start->X + Length) + { + UpdateRect->Right = Buff->ScreenBufferSize.X - 1; + } + else + { + UpdateRect->Right = Start->X + Length - 1; + } + UpdateRect->Top = Start->Y; + UpdateRect->Bottom = Start->Y + (Start->X + Length - 1) / Buff->ScreenBufferSize.X; + if (Buff->ScreenBufferSize.Y <= UpdateRect->Bottom) + { + UpdateRect->Bottom = Buff->ScreenBufferSize.Y - 1; + } +} + +/* + * Move from one rectangle to another. We must be careful about the order that + * this is done, to avoid overwriting parts of the source before they are moved. + */ +static VOID FASTCALL +ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer, + SMALL_RECT* SrcRegion, + SMALL_RECT* DstRegion, + SMALL_RECT* ClipRegion, + WORD Fill) +{ + int Width = ConioRectWidth(SrcRegion); + int Height = ConioRectHeight(SrcRegion); + int SX, SY; + int DX, DY; + int XDelta, YDelta; + int i, j; + + SY = SrcRegion->Top; + DY = DstRegion->Top; + YDelta = 1; + if (SY < DY) + { + /* Moving down: work from bottom up */ + SY = SrcRegion->Bottom; + DY = DstRegion->Bottom; + YDelta = -1; + } + for (i = 0; i < Height; i++) + { + PWORD SRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, SY); + PWORD DRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, DY); + + SX = SrcRegion->Left; + DX = DstRegion->Left; + XDelta = 1; + if (SX < DX) + { + /* Moving right: work from right to left */ + SX = SrcRegion->Right; + DX = DstRegion->Right; + XDelta = -1; + } + for (j = 0; j < Width; j++) + { + WORD Cell = SRow[SX]; + if (SX >= ClipRegion->Left && SX <= ClipRegion->Right + && SY >= ClipRegion->Top && SY <= ClipRegion->Bottom) + { + SRow[SX] = Fill; + } + if (DX >= ClipRegion->Left && DX <= ClipRegion->Right + && DY >= ClipRegion->Top && DY <= ClipRegion->Bottom) + { + DRow[DX] = Cell; + } + SX += XDelta; + DX += XDelta; + } + SY += YDelta; + DY += YDelta; + } +} + +DWORD FASTCALL +ConioEffectiveCursorSize(PCONSOLE Console, DWORD Scale) +{ + DWORD Size = (Console->ActiveBuffer->CursorInfo.dwSize * Scale + 99) / 100; + /* If line input in progress, perhaps adjust for insert toggle */ + if (Console->LineBuffer && !Console->LineComplete && Console->LineInsertToggle) + return (Size * 2 <= Scale) ? (Size * 2) : (Size / 2); + return Size; +} + +NTSTATUS +ConioResizeBuffer(PCONSOLE Console, + PTEXTMODE_SCREEN_BUFFER ScreenBuffer, + COORD Size) +{ + BYTE * Buffer; + DWORD Offset = 0; + BYTE * OldPtr; + USHORT CurrentY; + BYTE * OldBuffer; +#ifdef HAVE_WMEMSET + USHORT value = MAKEWORD(' ', ScreenBuffer->ScreenDefaultAttrib); +#else + DWORD i; +#endif + DWORD diff; + + /* Buffer size is not allowed to be smaller than the view size */ + if (Size.X < ScreenBuffer->ViewSize.X || Size.Y < ScreenBuffer->ViewSize.Y) + return STATUS_INVALID_PARAMETER; + + if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y) + { + // FIXME: Trigger a buffer resize event ?? + return STATUS_SUCCESS; + } + + if (Console->FixedSize) + { + /* + * The console is in fixed-size mode, so we cannot resize anything + * at the moment. However, keep those settings somewhere so that + * we can try to set them up when we will be allowed to do so. + */ + ScreenBuffer->OldScreenBufferSize = Size; + return STATUS_NOT_SUPPORTED; // STATUS_SUCCESS + } + + Buffer = ConsoleAllocHeap(0, Size.X * Size.Y * 2); + if (!Buffer) return STATUS_NO_MEMORY; + + DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y); + OldBuffer = ScreenBuffer->Buffer; + + for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++) + { + OldPtr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY); + if (Size.X <= ScreenBuffer->ScreenBufferSize.X) + { + /* reduce size */ + RtlCopyMemory(&Buffer[Offset], OldPtr, Size.X * 2); + Offset += (Size.X * 2); + } + else + { + /* enlarge size */ + RtlCopyMemory(&Buffer[Offset], OldPtr, ScreenBuffer->ScreenBufferSize.X * 2); + Offset += (ScreenBuffer->ScreenBufferSize.X * 2); + + diff = Size.X - ScreenBuffer->ScreenBufferSize.X; + /* zero new part of it */ +#ifdef HAVE_WMEMSET + wmemset((PWCHAR)&Buffer[Offset], value, diff); +#else + for (i = 0; i < diff; i++) + { + Buffer[Offset++] = ' '; + Buffer[Offset++] = (BYTE)ScreenBuffer->ScreenDefaultAttrib; + } +#endif + } + } + + if (Size.Y > ScreenBuffer->ScreenBufferSize.Y) + { + diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y); +#ifdef HAVE_WMEMSET + wmemset((PWCHAR)&Buffer[Offset], value, diff); +#else + for (i = 0; i < diff; i++) + { + Buffer[Offset++] = ' '; + Buffer[Offset++] = (BYTE)ScreenBuffer->ScreenDefaultAttrib; + } +#endif + } + + (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer); + ConsoleFreeHeap(OldBuffer); + ScreenBuffer->ScreenBufferSize = ScreenBuffer->OldScreenBufferSize = Size; + ScreenBuffer->VirtualY = 0; + + /* Ensure cursor and window are within buffer */ + if (ScreenBuffer->CursorPosition.X >= Size.X) + ScreenBuffer->CursorPosition.X = Size.X - 1; + if (ScreenBuffer->CursorPosition.Y >= Size.Y) + ScreenBuffer->CursorPosition.Y = Size.Y - 1; + if (ScreenBuffer->ViewOrigin.X > Size.X - ScreenBuffer->ViewSize.X) + ScreenBuffer->ViewOrigin.X = Size.X - ScreenBuffer->ViewSize.X; + if (ScreenBuffer->ViewOrigin.Y > Size.Y - ScreenBuffer->ViewSize.Y) + ScreenBuffer->ViewOrigin.Y = Size.Y - ScreenBuffer->ViewSize.Y; + + /* + * Trigger a buffer resize event + */ + if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT) + { + INPUT_RECORD er; + + er.EventType = WINDOW_BUFFER_SIZE_EVENT; + er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize; + + ConioProcessInputEvent(Console, &er); + } + + return STATUS_SUCCESS; +} + +static VOID FASTCALL +ConioNextLine(PTEXTMODE_SCREEN_BUFFER Buff, SMALL_RECT* UpdateRect, UINT *ScrolledLines) +{ + /* If we hit bottom, slide the viewable screen */ + if (++Buff->CursorPosition.Y == Buff->ScreenBufferSize.Y) + { + Buff->CursorPosition.Y--; + if (++Buff->VirtualY == Buff->ScreenBufferSize.Y) + { + Buff->VirtualY = 0; + } + (*ScrolledLines)++; + ClearLineBuffer(Buff); + if (UpdateRect->Top != 0) + { + UpdateRect->Top--; + } + } + UpdateRect->Left = 0; + UpdateRect->Right = Buff->ScreenBufferSize.X - 1; + UpdateRect->Bottom = Buff->CursorPosition.Y; +} + +NTSTATUS +ConioWriteConsole(PCONSOLE Console, + PTEXTMODE_SCREEN_BUFFER Buff, + CHAR *Buffer, + DWORD Length, + BOOL Attrib) +{ + UINT i; + PBYTE Ptr; + SMALL_RECT UpdateRect; + SHORT CursorStartX, CursorStartY; + UINT ScrolledLines; + + CursorStartX = Buff->CursorPosition.X; + CursorStartY = Buff->CursorPosition.Y; + UpdateRect.Left = Buff->ScreenBufferSize.X; + UpdateRect.Top = Buff->CursorPosition.Y; + UpdateRect.Right = -1; + UpdateRect.Bottom = Buff->CursorPosition.Y; + ScrolledLines = 0; + + for (i = 0; i < Length; i++) + { + /* + * If we are in processed mode, interpret special characters and + * display them correctly. Otherwise, just put them into the buffer. + */ + if (Buff->Mode & ENABLE_PROCESSED_OUTPUT) + { + /* --- CR --- */ + if (Buffer[i] == '\r') + { + Buff->CursorPosition.X = 0; + UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); + UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); + continue; + } + /* --- LF --- */ + else if (Buffer[i] == '\n') + { + Buff->CursorPosition.X = 0; + ConioNextLine(Buff, &UpdateRect, &ScrolledLines); + continue; + } + /* --- BS --- */ + else if (Buffer[i] == '\b') + { + /* Only handle BS if we're not on the first pos of the first line */ + if (0 != Buff->CursorPosition.X || 0 != Buff->CursorPosition.Y) + { + if (0 == Buff->CursorPosition.X) + { + /* slide virtual position up */ + Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1; + Buff->CursorPosition.Y--; + UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y); + } + else + { + Buff->CursorPosition.X--; + } + Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); + Ptr[0] = ' '; + Ptr[1] = (BYTE)Buff->ScreenDefaultAttrib; + UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); + UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); + } + continue; + } + /* --- TAB --- */ + else if (Buffer[i] == '\t') + { + UINT EndX; + + UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); + EndX = (Buff->CursorPosition.X + TAB_WIDTH) & ~(TAB_WIDTH - 1); + EndX = min(EndX, (UINT)Buff->ScreenBufferSize.X); + Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); + while (Buff->CursorPosition.X < EndX) + { + *Ptr++ = ' '; + *Ptr++ = (BYTE)Buff->ScreenDefaultAttrib; + Buff->CursorPosition.X++; + } + UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X - 1); + if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X) + { + if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT) + { + Buff->CursorPosition.X = 0; + ConioNextLine(Buff, &UpdateRect, &ScrolledLines); + } + else + { + Buff->CursorPosition.X--; + } + } + continue; + } + // /* --- BEL ---*/ + // else if (Buffer[i] == '\a') + // { + // // FIXME: This MUST BE moved to the terminal emulator frontend!! + // DPRINT1("Bell\n"); + // // SendNotifyMessage(Console->hWindow, PM_CONSOLE_BEEP, 0, 0); + // continue; + // } + } + UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); + UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); + Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); + Ptr[0] = Buffer[i]; + if (Attrib) + { + Ptr[1] = (BYTE)Buff->ScreenDefaultAttrib; + } + Buff->CursorPosition.X++; + if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X) + { + if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT) + { + Buff->CursorPosition.X = 0; + ConioNextLine(Buff, &UpdateRect, &ScrolledLines); + } + else + { + Buff->CursorPosition.X = CursorStartX; + } + } + } + + if (!ConioIsRectEmpty(&UpdateRect) && (PCONSOLE_SCREEN_BUFFER)Buff == Console->ActiveBuffer) + { + ConioWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY, + ScrolledLines, Buffer, Length); + } + + return STATUS_SUCCESS; +} + +static NTSTATUS +DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage, + IN PCSR_THREAD ClientThread, + IN BOOL CreateWaitBlock OPTIONAL); + +// Wait function CSR_WAIT_FUNCTION +static BOOLEAN +WriteConsoleThread(IN PLIST_ENTRY WaitList, + IN PCSR_THREAD WaitThread, + IN PCSR_API_MESSAGE WaitApiMessage, + IN PVOID WaitContext, + IN PVOID WaitArgument1, + IN PVOID WaitArgument2, + IN ULONG WaitFlags) +{ + NTSTATUS Status; + + DPRINT("WriteConsoleThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags); + + /* + * If we are notified of the process termination via a call + * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or + * CsrDestroyThread, just return. + */ + if (WaitFlags & CsrProcessTerminating) + { + Status = STATUS_THREAD_IS_TERMINATING; + goto Quit; + } + + Status = DoWriteConsole(WaitApiMessage, + WaitThread, + FALSE); + +Quit: + if (Status != STATUS_PENDING) + { + WaitApiMessage->Status = Status; + } + + return (Status == STATUS_PENDING ? FALSE : TRUE); +} + +static NTSTATUS +DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage, + IN PCSR_THREAD ClientThread, + IN BOOL CreateWaitBlock OPTIONAL) +{ + NTSTATUS Status = STATUS_SUCCESS; + PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest; + PCONSOLE Console; + PTEXTMODE_SCREEN_BUFFER Buff; + PCHAR Buffer; + DWORD Written = 0; + ULONG Length; + + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(ClientThread->Process), WriteConsoleRequest->OutputHandle, &Buff, GENERIC_WRITE, FALSE); + if (!NT_SUCCESS(Status)) return Status; + + Console = Buff->Header.Console; + + // if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) + if (Console->PauseFlags && Console->UnpauseEvent != NULL) + { + if (CreateWaitBlock) + { + if (!CsrCreateWait(&Console->WriteWaitQueue, + WriteConsoleThread, + ClientThread, + ApiMessage, + NULL, + NULL)) + { + /* Fail */ + ConSrvReleaseScreenBuffer(Buff, FALSE); + return STATUS_NO_MEMORY; + } + } + + /* Wait until we un-pause the console */ + Status = STATUS_PENDING; + } + else + { + if (WriteConsoleRequest->Unicode) + { + Length = WideCharToMultiByte(Console->OutputCodePage, 0, + (PWCHAR)WriteConsoleRequest->Buffer, + WriteConsoleRequest->NrCharactersToWrite, + NULL, 0, NULL, NULL); + Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length); + if (Buffer) + { + WideCharToMultiByte(Console->OutputCodePage, 0, + (PWCHAR)WriteConsoleRequest->Buffer, + WriteConsoleRequest->NrCharactersToWrite, + Buffer, Length, NULL, NULL); + } + else + { + Status = STATUS_NO_MEMORY; + } + } + else + { + Buffer = (PCHAR)WriteConsoleRequest->Buffer; + } + + if (Buffer) + { + if (NT_SUCCESS(Status)) + { + Status = ConioWriteConsole(Console, Buff, Buffer, + WriteConsoleRequest->NrCharactersToWrite, TRUE); + if (NT_SUCCESS(Status)) + { + Written = WriteConsoleRequest->NrCharactersToWrite; + } + } + + if (WriteConsoleRequest->Unicode) + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + } + + WriteConsoleRequest->NrCharactersWritten = Written; + } + + ConSrvReleaseScreenBuffer(Buff, FALSE); + return Status; +} + + +/* PUBLIC SERVER APIS *********************************************************/ + +CSR_API(SrvReadConsoleOutput) +{ + PCONSOLE_READOUTPUT ReadOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputRequest; + PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); + PCHAR_INFO CharInfo; + PCHAR_INFO CurCharInfo; + PTEXTMODE_SCREEN_BUFFER Buff; + SHORT SizeX, SizeY; + NTSTATUS Status; + COORD BufferSize; + COORD BufferCoord; + SMALL_RECT ReadRegion; + SMALL_RECT ScreenRect; + DWORD i; + PBYTE Ptr; + LONG X, Y; + UINT CodePage; + + DPRINT("SrvReadConsoleOutput\n"); + + CharInfo = ReadOutputRequest->CharInfo; + ReadRegion = ReadOutputRequest->ReadRegion; + BufferSize = ReadOutputRequest->BufferSize; + BufferCoord = ReadOutputRequest->BufferCoord; + + if (!CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&ReadOutputRequest->CharInfo, + BufferSize.X * BufferSize.Y, + sizeof(CHAR_INFO))) + { + return STATUS_INVALID_PARAMETER; + } + + Status = ConSrvGetTextModeBuffer(ProcessData, ReadOutputRequest->OutputHandle, &Buff, GENERIC_READ, TRUE); + if (!NT_SUCCESS(Status)) return Status; + + /* FIXME: Is this correct? */ + CodePage = ProcessData->Console->OutputCodePage; + + SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&ReadRegion)); + SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&ReadRegion)); + ReadRegion.Bottom = ReadRegion.Top + SizeY; + ReadRegion.Right = ReadRegion.Left + SizeX; + + ConioInitRect(&ScreenRect, 0, 0, Buff->ScreenBufferSize.Y, Buff->ScreenBufferSize.X); + if (!ConioGetIntersection(&ReadRegion, &ScreenRect, &ReadRegion)) + { + ConSrvReleaseScreenBuffer(Buff, TRUE); + return STATUS_SUCCESS; + } + + for (i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y) + { + CurCharInfo = CharInfo + (i * BufferSize.X); + + Ptr = ConioCoordToPointer(Buff, ReadRegion.Left, Y); + for (X = ReadRegion.Left; X < ReadRegion.Right; ++X) + { + if (ReadOutputRequest->Unicode) + { + // ConsoleAnsiCharToUnicodeChar(ProcessData->Console, (PCHAR)Ptr++, &CurCharInfo->Char.UnicodeChar); + MultiByteToWideChar(CodePage, 0, + (PCHAR)Ptr++, 1, + &CurCharInfo->Char.UnicodeChar, 1); + } + else + { + CurCharInfo->Char.AsciiChar = *Ptr++; + } + CurCharInfo->Attributes = *Ptr++; + ++CurCharInfo; + } + } + + ConSrvReleaseScreenBuffer(Buff, TRUE); + + ReadOutputRequest->ReadRegion.Right = ReadRegion.Left + SizeX - 1; + ReadOutputRequest->ReadRegion.Bottom = ReadRegion.Top + SizeY - 1; + ReadOutputRequest->ReadRegion.Left = ReadRegion.Left; + ReadOutputRequest->ReadRegion.Top = ReadRegion.Top; + + return STATUS_SUCCESS; +} + +CSR_API(SrvWriteConsoleOutput) +{ + PCONSOLE_WRITEOUTPUT WriteOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputRequest; + PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); + SHORT i, X, Y, SizeX, SizeY; + PCONSOLE Console; + PTEXTMODE_SCREEN_BUFFER Buff; + SMALL_RECT ScreenBuffer; + CHAR_INFO* CurCharInfo; + SMALL_RECT WriteRegion; + CHAR_INFO* CharInfo; + COORD BufferCoord; + COORD BufferSize; + NTSTATUS Status; + PBYTE Ptr; + + DPRINT("SrvWriteConsoleOutput\n"); + + BufferSize = WriteOutputRequest->BufferSize; + BufferCoord = WriteOutputRequest->BufferCoord; + CharInfo = WriteOutputRequest->CharInfo; + + if (!CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&WriteOutputRequest->CharInfo, + BufferSize.X * BufferSize.Y, + sizeof(CHAR_INFO))) + { + return STATUS_INVALID_PARAMETER; + } + + Status = ConSrvGetTextModeBuffer(ProcessData, + WriteOutputRequest->OutputHandle, + &Buff, + GENERIC_WRITE, + TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Console = Buff->Header.Console; + + WriteRegion = WriteOutputRequest->WriteRegion; + + SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&WriteRegion)); + SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&WriteRegion)); + WriteRegion.Bottom = WriteRegion.Top + SizeY - 1; + WriteRegion.Right = WriteRegion.Left + SizeX - 1; + + /* Make sure WriteRegion is inside the screen buffer */ + ConioInitRect(&ScreenBuffer, 0, 0, Buff->ScreenBufferSize.Y - 1, Buff->ScreenBufferSize.X - 1); + if (!ConioGetIntersection(&WriteRegion, &ScreenBuffer, &WriteRegion)) + { + ConSrvReleaseScreenBuffer(Buff, TRUE); + + /* It is okay to have a WriteRegion completely outside the screen buffer. + No data is written then. */ + return STATUS_SUCCESS; + } + + for (i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++) + { + CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X; + Ptr = ConioCoordToPointer(Buff, WriteRegion.Left, Y); + for (X = WriteRegion.Left; X <= WriteRegion.Right; X++) + { + CHAR AsciiChar; + if (WriteOutputRequest->Unicode) + { + ConsoleUnicodeCharToAnsiChar(Console, &AsciiChar, &CurCharInfo->Char.UnicodeChar); + } + else + { + AsciiChar = CurCharInfo->Char.AsciiChar; + } + *Ptr++ = AsciiChar; + *Ptr++ = (BYTE)CurCharInfo->Attributes; + CurCharInfo++; + } + } + + ConioDrawRegion(Console, &WriteRegion); + + ConSrvReleaseScreenBuffer(Buff, TRUE); + + WriteOutputRequest->WriteRegion.Right = WriteRegion.Left + SizeX - 1; + WriteOutputRequest->WriteRegion.Bottom = WriteRegion.Top + SizeY - 1; + WriteOutputRequest->WriteRegion.Left = WriteRegion.Left; + WriteOutputRequest->WriteRegion.Top = WriteRegion.Top; + + return STATUS_SUCCESS; +} + +CSR_API(SrvWriteConsole) +{ + NTSTATUS Status; + PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest; + + DPRINT("SrvWriteConsole\n"); + + if (!CsrValidateMessageBuffer(ApiMessage, + (PVOID)&WriteConsoleRequest->Buffer, + WriteConsoleRequest->BufferSize, + sizeof(BYTE))) + { + return STATUS_INVALID_PARAMETER; + } + + Status = DoWriteConsole(ApiMessage, + CsrGetClientThread(), + TRUE); + + if (Status == STATUS_PENDING) + *ReplyCode = CsrReplyPending; + + return Status; +} + +CSR_API(SrvReadConsoleOutputString) +{ + NTSTATUS Status; + PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputCodeRequest; + PCONSOLE Console; + PTEXTMODE_SCREEN_BUFFER Buff; + USHORT CodeType; + SHORT Xpos, Ypos; + PVOID ReadBuffer; + DWORD i; + ULONG CodeSize; + BYTE Code; + + DPRINT("SrvReadConsoleOutputString\n"); + + CodeType = ReadOutputCodeRequest->CodeType; + switch (CodeType) + { + case CODE_ASCII: + CodeSize = sizeof(CHAR); + break; + + case CODE_UNICODE: + CodeSize = sizeof(WCHAR); + break; + + case CODE_ATTRIBUTE: + CodeSize = sizeof(WORD); + break; + + default: + return STATUS_INVALID_PARAMETER; + } + + if (!CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&ReadOutputCodeRequest->pCode.pCode, + ReadOutputCodeRequest->NumCodesToRead, + CodeSize)) + { + return STATUS_INVALID_PARAMETER; + } + + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ReadOutputCodeRequest->OutputHandle, &Buff, GENERIC_READ, TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Console = Buff->Header.Console; + + ReadBuffer = ReadOutputCodeRequest->pCode.pCode; + Xpos = ReadOutputCodeRequest->ReadCoord.X; + Ypos = (ReadOutputCodeRequest->ReadCoord.Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y; + + /* + * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) : + * + * If the number of attributes (resp. characters) to be read from extends + * beyond the end of the specified screen buffer row, attributes (resp. + * characters) are read from the next row. If the number of attributes + * (resp. characters) to be read from extends beyond the end of the console + * screen buffer, attributes (resp. characters) up to the end of the console + * screen buffer are read. + * + * TODO: Do NOT loop up to NumCodesToRead, but stop before + * if we are going to overflow... + */ + for (i = 0; i < min(ReadOutputCodeRequest->NumCodesToRead, Buff->ScreenBufferSize.X * Buff->ScreenBufferSize.Y * 2); ++i) + { + Code = Buff->Buffer[2 * (Xpos + Ypos * Buff->ScreenBufferSize.X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)]; + + switch (CodeType) + { + case CODE_UNICODE: + ConsoleAnsiCharToUnicodeChar(Console, (PWCHAR)ReadBuffer, (PCHAR)&Code); + break; + + case CODE_ASCII: + *(PCHAR)ReadBuffer = (CHAR)Code; + break; + + case CODE_ATTRIBUTE: + *(PWORD)ReadBuffer = (WORD)Code; + break; + } + ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize); + + Xpos++; + + if (Xpos == Buff->ScreenBufferSize.X) + { + Xpos = 0; + Ypos++; + + if (Ypos == Buff->ScreenBufferSize.Y) + { + Ypos = 0; + } + } + } + + // switch (CodeType) + // { + // case CODE_UNICODE: + // *(PWCHAR)ReadBuffer = 0; + // break; + + // case CODE_ASCII: + // *(PCHAR)ReadBuffer = 0; + // break; + + // case CODE_ATTRIBUTE: + // *(PWORD)ReadBuffer = 0; + // break; + // } + + ReadOutputCodeRequest->EndCoord.X = Xpos; + ReadOutputCodeRequest->EndCoord.Y = (Ypos - Buff->VirtualY + Buff->ScreenBufferSize.Y) % Buff->ScreenBufferSize.Y; + + ConSrvReleaseScreenBuffer(Buff, TRUE); + + ReadOutputCodeRequest->CodesRead = (DWORD)((ULONG_PTR)ReadBuffer - (ULONG_PTR)ReadOutputCodeRequest->pCode.pCode) / CodeSize; + // <= ReadOutputCodeRequest->NumCodesToRead + + return STATUS_SUCCESS; +} + +CSR_API(SrvWriteConsoleOutputString) +{ + NTSTATUS Status; + PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputCodeRequest; + PCONSOLE Console; + PTEXTMODE_SCREEN_BUFFER Buff; + USHORT CodeType; + PBYTE Buffer; // PUCHAR + PCHAR String, tmpString = NULL; + DWORD X, Y, Length; // , Written = 0; + ULONG CodeSize; + SMALL_RECT UpdateRect; + + DPRINT("SrvWriteConsoleOutputString\n"); + + CodeType = WriteOutputCodeRequest->CodeType; + switch (CodeType) + { + case CODE_ASCII: + CodeSize = sizeof(CHAR); + break; + + case CODE_UNICODE: + CodeSize = sizeof(WCHAR); + break; + + case CODE_ATTRIBUTE: + CodeSize = sizeof(WORD); + break; + + default: + return STATUS_INVALID_PARAMETER; + } + + if (!CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&WriteOutputCodeRequest->pCode.pCode, + WriteOutputCodeRequest->Length, + CodeSize)) + { + return STATUS_INVALID_PARAMETER; + } + + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + WriteOutputCodeRequest->OutputHandle, + &Buff, + GENERIC_WRITE, + TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Console = Buff->Header.Console; + + switch (CodeType) + { + case CODE_UNICODE: + { + Length = WideCharToMultiByte(Console->OutputCodePage, 0, + (PWCHAR)WriteOutputCodeRequest->pCode.UnicodeChar, + WriteOutputCodeRequest->Length, + NULL, 0, NULL, NULL); + tmpString = String = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length); + if (String) + { + WideCharToMultiByte(Console->OutputCodePage, 0, + (PWCHAR)WriteOutputCodeRequest->pCode.UnicodeChar, + WriteOutputCodeRequest->Length, + String, Length, NULL, NULL); + } + else + { + Status = STATUS_NO_MEMORY; + } + + break; + } + + case CODE_ASCII: + String = (PCHAR)WriteOutputCodeRequest->pCode.AsciiChar; + break; + + case CODE_ATTRIBUTE: + default: + // *(ReadBuffer++) = Code; + String = (PCHAR)WriteOutputCodeRequest->pCode.Attribute; + break; + } + + if (String && NT_SUCCESS(Status)) + { + X = WriteOutputCodeRequest->Coord.X; + Y = (WriteOutputCodeRequest->Coord.Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y; + Length = WriteOutputCodeRequest->Length; + Buffer = &Buff->Buffer[2 * (Y * Buff->ScreenBufferSize.X + X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)]; + + while (Length--) + { + *Buffer = *String++; + // ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize); + String = (PCHAR)((ULONG_PTR)String + CodeSize); + // Written++; + Buffer += 2; + if (++X == Buff->ScreenBufferSize.X) + { + if (++Y == Buff->ScreenBufferSize.Y) + { + Y = 0; + Buffer = Buff->Buffer + (CodeType == CODE_ATTRIBUTE ? 1 : 0); + } + X = 0; + } + } + + if ((PCONSOLE_SCREEN_BUFFER)Buff == Console->ActiveBuffer) + { + ConioComputeUpdateRect(Buff, &UpdateRect, &WriteOutputCodeRequest->Coord, + WriteOutputCodeRequest->Length); + ConioDrawRegion(Console, &UpdateRect); + } + + // WriteOutputCodeRequest->EndCoord.X = X; + // WriteOutputCodeRequest->EndCoord.Y = (Y + Buff->ScreenBufferSize.Y - Buff->VirtualY) % Buff->ScreenBufferSize.Y; + } + + if (tmpString) + RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString); + + ConSrvReleaseScreenBuffer(Buff, TRUE); + + // WriteOutputCodeRequest->NrCharactersWritten = Written; + return Status; +} + +CSR_API(SrvFillConsoleOutput) +{ + NTSTATUS Status; + PCONSOLE_FILLOUTPUTCODE FillOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FillOutputRequest; + PCONSOLE Console; + PTEXTMODE_SCREEN_BUFFER Buff; + DWORD X, Y, Length; // , Written = 0; + USHORT CodeType; + BYTE Code; + PBYTE Buffer; + SMALL_RECT UpdateRect; + + DPRINT("SrvFillConsoleOutput\n"); + + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), FillOutputRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Console = Buff->Header.Console; + + CodeType = FillOutputRequest->CodeType; + + X = FillOutputRequest->Coord.X; + Y = (FillOutputRequest->Coord.Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y; + Length = FillOutputRequest->Length; + Buffer = &Buff->Buffer[2 * (Y * Buff->ScreenBufferSize.X + X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)]; + + switch (CodeType) + { + case CODE_ASCII: + Code = (BYTE)FillOutputRequest->Code.AsciiChar; + break; + + case CODE_UNICODE: + ConsoleUnicodeCharToAnsiChar(Console, (PCHAR)&Code, &FillOutputRequest->Code.UnicodeChar); + break; + + case CODE_ATTRIBUTE: + Code = (BYTE)FillOutputRequest->Code.Attribute; + break; + + default: + ConSrvReleaseScreenBuffer(Buff, TRUE); + return STATUS_INVALID_PARAMETER; + } + + while (Length--) + { + *Buffer = Code; + Buffer += 2; + // Written++; + if (++X == Buff->ScreenBufferSize.X) + { + if (++Y == Buff->ScreenBufferSize.Y) + { + Y = 0; + Buffer = Buff->Buffer + (CodeType == CODE_ATTRIBUTE ? 1 : 0); + } + X = 0; + } + } + + if ((PCONSOLE_SCREEN_BUFFER)Buff == Console->ActiveBuffer) + { + ConioComputeUpdateRect(Buff, &UpdateRect, &FillOutputRequest->Coord, + FillOutputRequest->Length); + ConioDrawRegion(Console, &UpdateRect); + } + + ConSrvReleaseScreenBuffer(Buff, TRUE); +/* + Length = FillOutputRequest->Length; + FillOutputRequest->NrCharactersWritten = Length; +*/ + return STATUS_SUCCESS; +} + +CSR_API(SrvGetConsoleScreenBufferInfo) +{ + NTSTATUS Status; + PCONSOLE_GETSCREENBUFFERINFO ScreenBufferInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScreenBufferInfoRequest; + // PCONSOLE Console; + PTEXTMODE_SCREEN_BUFFER Buff; + PCONSOLE_SCREEN_BUFFER_INFO pInfo = &ScreenBufferInfoRequest->Info; + + DPRINT("SrvGetConsoleScreenBufferInfo\n"); + + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ScreenBufferInfoRequest->OutputHandle, &Buff, GENERIC_READ, TRUE); + if (!NT_SUCCESS(Status)) return Status; + + // Console = Buff->Header.Console; + + pInfo->dwSize = Buff->ScreenBufferSize; + pInfo->dwCursorPosition = Buff->CursorPosition; + pInfo->wAttributes = Buff->ScreenDefaultAttrib; + pInfo->srWindow.Left = Buff->ViewOrigin.X; + pInfo->srWindow.Top = Buff->ViewOrigin.Y; + pInfo->srWindow.Right = Buff->ViewOrigin.X + Buff->ViewSize.X - 1; + pInfo->srWindow.Bottom = Buff->ViewOrigin.Y + Buff->ViewSize.Y - 1; + pInfo->dwMaximumWindowSize = Buff->ScreenBufferSize; // TODO: Refine the computation + + ConSrvReleaseScreenBuffer(Buff, TRUE); + return STATUS_SUCCESS; +} + +CSR_API(SrvSetConsoleTextAttribute) +{ + NTSTATUS Status; + PCONSOLE_SETTEXTATTRIB SetTextAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetTextAttribRequest; + PTEXTMODE_SCREEN_BUFFER Buff; + + DPRINT("SrvSetConsoleTextAttribute\n"); + + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetTextAttribRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Buff->ScreenDefaultAttrib = SetTextAttribRequest->Attrib; + + ConSrvReleaseScreenBuffer(Buff, TRUE); + return STATUS_SUCCESS; +} + +CSR_API(SrvSetConsoleScreenBufferSize) +{ + NTSTATUS Status; + PCONSOLE_SETSCREENBUFFERSIZE SetScreenBufferSizeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferSizeRequest; + PCONSOLE Console; + PTEXTMODE_SCREEN_BUFFER Buff; + + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetScreenBufferSizeRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Console = Buff->Header.Console; + + Status = ConioResizeBuffer(Console, Buff, SetScreenBufferSizeRequest->Size); + if (NT_SUCCESS(Status)) ConioResizeTerminal(Console); + + ConSrvReleaseScreenBuffer(Buff, TRUE); + return Status; +} + +CSR_API(SrvScrollConsoleScreenBuffer) +{ + PCONSOLE_SCROLLSCREENBUFFER ScrollScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScrollScreenBufferRequest; + PCONSOLE Console; + PTEXTMODE_SCREEN_BUFFER Buff; + SMALL_RECT ScreenBuffer; + SMALL_RECT SrcRegion; + SMALL_RECT DstRegion; + SMALL_RECT UpdateRegion; + SMALL_RECT ScrollRectangle; + SMALL_RECT ClipRectangle; + NTSTATUS Status; + HANDLE OutputHandle; + BOOLEAN UseClipRectangle; + COORD DestinationOrigin; + CHAR_INFO Fill; + CHAR FillChar; + + DPRINT("SrvScrollConsoleScreenBuffer\n"); + + OutputHandle = ScrollScreenBufferRequest->OutputHandle; + UseClipRectangle = ScrollScreenBufferRequest->UseClipRectangle; + DestinationOrigin = ScrollScreenBufferRequest->DestinationOrigin; + Fill = ScrollScreenBufferRequest->Fill; + + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), OutputHandle, &Buff, GENERIC_WRITE, TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Console = Buff->Header.Console; + + ScrollRectangle = ScrollScreenBufferRequest->ScrollRectangle; + + /* Make sure source rectangle is inside the screen buffer */ + ConioInitRect(&ScreenBuffer, 0, 0, Buff->ScreenBufferSize.Y - 1, Buff->ScreenBufferSize.X - 1); + if (!ConioGetIntersection(&SrcRegion, &ScreenBuffer, &ScrollRectangle)) + { + ConSrvReleaseScreenBuffer(Buff, TRUE); + return STATUS_SUCCESS; + } + + /* If the source was clipped on the left or top, adjust the destination accordingly */ + if (ScrollRectangle.Left < 0) + { + DestinationOrigin.X -= ScrollRectangle.Left; + } + if (ScrollRectangle.Top < 0) + { + DestinationOrigin.Y -= ScrollRectangle.Top; + } + + if (UseClipRectangle) + { + ClipRectangle = ScrollScreenBufferRequest->ClipRectangle; + if (!ConioGetIntersection(&ClipRectangle, &ClipRectangle, &ScreenBuffer)) + { + ConSrvReleaseScreenBuffer(Buff, TRUE); + return STATUS_SUCCESS; + } + } + else + { + ClipRectangle = ScreenBuffer; + } + + ConioInitRect(&DstRegion, + DestinationOrigin.Y, + DestinationOrigin.X, + DestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1, + DestinationOrigin.X + ConioRectWidth(&SrcRegion) - 1); + + if (ScrollScreenBufferRequest->Unicode) + ConsoleUnicodeCharToAnsiChar(Console, &FillChar, &Fill.Char.UnicodeChar); + else + FillChar = Fill.Char.AsciiChar; + + ConioMoveRegion(Buff, &SrcRegion, &DstRegion, &ClipRectangle, Fill.Attributes << 8 | (BYTE)FillChar); + + if ((PCONSOLE_SCREEN_BUFFER)Buff == Console->ActiveBuffer) + { + ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion); + if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &ClipRectangle)) + { + /* Draw update region */ + ConioDrawRegion(Console, &UpdateRegion); + } + } + + ConSrvReleaseScreenBuffer(Buff, TRUE); + return STATUS_SUCCESS; +} + +/* EOF */