[CONSOLE.CPL-KERNEL32]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Wed, 29 May 2013 00:29:07 +0000 (00:29 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Wed, 29 May 2013 00:29:07 +0000 (00:29 +0000)
Fix some compilation warnings with MSVC.

[KERNEL32-CONSRV]
- Implement console graphics screen buffers, as described in http://blog.airesoft.co.uk/2012/10/things-ms-can-do-that-they-dont-tell-you-about-console-graphics/ .
  The idea is that the console server creates a memory shared section to be shared with the client console application (it increases performance). A mutex is used to "say" to the console server that he can repaint the screen. The function InvalidateConsoleDIBits is implemented too. The definition of the structure CONSOLE_GRAPHICS_BUFFER_INFO comes directly from the site.
- CreateConsoleScreenBuffer was modified to be able to create such buffers.
This is needed for a working NTVDM-like application.

[CONSRV]
- Rework the console buffer structures so that text-mode buffers and graphics-mode buffers can "inherit" from an "abstract" structure, CONSOLE_SCREEN_BUFFER. Add few helper functions for manipulating them.
- Reorganize the output code in "graphics.c" and "text.c" files to separate text-mode only code from graphics-mode only code, both in the console server and in the GUI front-end.

Other fixes:
- Fix mouse handling (left and right clicks when one goes away from the "Selection" mode); do not handle mouse signal when we reactivate the GUI front-end window by a click.
- Fix GetLargestConsoleWindowSize API in console server side. Now pressing Alt+F9 in Far Manager to "change" the "video" mode works correctly.

Finally:
- Start to implement a (fake, i.e. not using directly a VGA driver) console fullscreen mode. Currently Alt-Enter key presses call a stub which just alternates DPRINTing between "switch to fullscreen mode" and "switch to windowed mode".

Images here:
- Example of an application (a 16-bit emulator by Mysoft) which uses the console graphics screen-buffer functionality: http://img577.imageshack.us/img577/1693/mysoftemulatorargon.png
- A potpourri of console applications which use graphics screen-buffers: http://img571.imageshack.us/img571/6526/consoledelirium.png

Enjoy :)

svn path=/trunk/; revision=59099

30 files changed:
reactos/dll/cpl/console/console.c
reactos/dll/cpl/console/layout.c
reactos/dll/cpl/console/options.c
reactos/dll/win32/kernel32/client/console/console.c
reactos/dll/win32/kernel32/client/console/history.c
reactos/include/psdk/winbase.h
reactos/include/psdk/wincon.h
reactos/include/reactos/subsys/win/conmsg.h
reactos/win32ss/user/consrv/CMakeLists.txt
reactos/win32ss/user/consrv/api.h
reactos/win32ss/user/consrv/coninput.c
reactos/win32ss/user/consrv/conio.h
reactos/win32ss/user/consrv/conoutput.c
reactos/win32ss/user/consrv/conoutput.h
reactos/win32ss/user/consrv/console.c
reactos/win32ss/user/consrv/consrv.h
reactos/win32ss/user/consrv/frontends/gui/graphics.c [new file with mode: 0644]
reactos/win32ss/user/consrv/frontends/gui/guisettings.c
reactos/win32ss/user/consrv/frontends/gui/guisettings.h
reactos/win32ss/user/consrv/frontends/gui/guiterm.c
reactos/win32ss/user/consrv/frontends/gui/text.c [new file with mode: 0644]
reactos/win32ss/user/consrv/frontends/tui/tuiterm.c
reactos/win32ss/user/consrv/graphics.c [new file with mode: 0644]
reactos/win32ss/user/consrv/handle.c
reactos/win32ss/user/consrv/include/conio.h
reactos/win32ss/user/consrv/include/settings.h
reactos/win32ss/user/consrv/init.c
reactos/win32ss/user/consrv/lineinput.c
reactos/win32ss/user/consrv/settings.c
reactos/win32ss/user/consrv/text.c [new file with mode: 0644]

index c365752..a674aa0 100644 (file)
@@ -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;
index e6fd38e..e4e6978 100644 (file)
@@ -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);
index 9ba28cf..e3a1914 100644 (file)
@@ -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);
index c0e2286..657196d 100644 (file)
@@ -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 */
index 5924e4a..ae8e93d 100644 (file)
@@ -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;
 }
 
 
index 82fdeea..a123ebd 100644 (file)
@@ -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
index bbc1bfe..90998c9 100644 (file)
@@ -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
index 366fe2e..ee65004 100644 (file)
@@ -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;
index 2519d33..f43f2da 100644 (file)
@@ -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...()
 
index 5819706..b37f5d7 100644 (file)
@@ -24,6 +24,7 @@ CSR_API(SrvFlushConsoleInputBuffer);
 CSR_API(SrvGetConsoleNumberOfInputEvents);
 
 /* conoutput.c */
+CSR_API(SrvInvalidateBitMapRect);
 CSR_API(SrvReadConsoleOutput);
 CSR_API(SrvWriteConsole);
 CSR_API(SrvWriteConsoleOutput);
index 6793b5d..525ae01 100644 (file)
@@ -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,
index 7235ac2..677a3ed 100644 (file)
@@ -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) \
     (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 */
index 08f3cb9..d74f76d 100644 (file)
@@ -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)
  */
 #define NDEBUG
 #include <debug.h>
 
-/*
-// Define wmemset(...)
-#include <wchar.h>
-#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)];
-}
-
-static VOID FASTCALL
-ClearLineBuffer(PCONSOLE_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;
-    }
-}
-
-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
+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);
+
+VOID
+TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
+VOID
+GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
+
+
+NTSTATUS
+CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
+                                 IN 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)
-{
-    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) && Buff == Console->ActiveBuffer)
-    {
-        ConioWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY,
-                         ScrolledLines, Buffer, Length);
-    }
-
-    return STATUS_SUCCESS;
-}
-
-__inline BOOLEAN ConioGetIntersection(
-    SMALL_RECT* Intersection,
-    SMALL_RECT* Rect1,
-    SMALL_RECT* Rect2)
+ConSrvCreateScreenBuffer(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
+                         IN OUT PCONSOLE Console,
+                         IN ULONG BufferType,
+                         IN PVOID ScreenBufferInfo)
 {
-    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;
-}
-
-__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;
-}
+    NTSTATUS Status = STATUS_SUCCESS;
 
-/*
- * 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)
+    if ( Console == NULL || Buffer == NULL ||
+        (BufferType != CONSOLE_TEXTMODE_BUFFER && BufferType != CONSOLE_GRAPHICS_BUFFER) )
     {
-        /* 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++)
+    if (BufferType == CONSOLE_TEXTMODE_BUFFER)
     {
-        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
-        }
+        Status = TEXTMODE_BUFFER_Initialize(Buffer,
+                                            Console,
+                                            (PTEXTMODE_BUFFER_INFO)ScreenBufferInfo);
     }
-
-    if (Size.Y > ScreenBuffer->ScreenBufferSize.Y)
+    else if (BufferType == CONSOLE_GRAPHICS_BUFFER)
     {
-        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
+        Status = GRAPHICS_BUFFER_Initialize(Buffer,
+                                            Console,
+                                            (PGRAPHICS_BUFFER_INFO)ScreenBufferInfo);
     }
-
-    (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)
+    else
     {
-        INPUT_RECORD er;
-
-        er.EventType = WINDOW_BUFFER_SIZE_EVENT;
-        er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize;
-
-        ConioProcessInputEvent(Console, &er);
+        /* Never ever go there!! */
+        ASSERT(FALSE);
     }
 
-    /* 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.
+    /* Insert the newly created screen buffer into the list, if succeeded */
+    if (NT_SUCCESS(Status)) InsertHeadList(&Console->BufferList, &(*Buffer)->ListEntry);
 
-    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;
+        ConioInitRect(&Region, 0, 0, ActiveBuffer->ViewSize.Y - 1, ActiveBuffer->ViewSize.X - 1);
+        ConioDrawRegion(Console, &Region);
     }
-    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;
-    }
-}
-
-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;
-}
-
-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)
+VOID FASTCALL
+ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer)
 {
-    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");
 
-    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;
-    }
+    DPRINT("SrvInvalidateBitMapRect\n");
 
-    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,148 +260,134 @@ CSR_API(SrvSetConsoleCursorPosition)
     {
         if (!ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
         {
-            ConSrvReleaseScreenBuffer(Buff, TRUE);
-            return STATUS_UNSUCCESSFUL;
-        }
-    }
-
-    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;
+            Status = STATUS_UNSUCCESSFUL;
+            goto Quit;
         }
     }
 
+Quit:
     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;
+        ScreenBufferInfo = &TextModeInfo;
 
-        ScreenAttrib = Console->ActiveBuffer->ScreenDefaultAttrib;
-        PopupAttrib  = Console->ActiveBuffer->PopupDefaultAttrib;
+        /*
+        if (Console->ActiveBuffer)
+        {
+            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;
 
-    // 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;
+            TextModeInfo.IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible;
+            TextModeInfo.CursorSize      = Console->ActiveBuffer->CursorInfo.dwSize;
+        }
+        */
 
-        if (Console->ActiveBuffer)
+        /*
+         * 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)
         {
-            ScreenAttrib = Console->ActiveBuffer->ScreenDefaultAttrib;
-            PopupAttrib  = Console->ActiveBuffer->PopupDefaultAttrib;
-            DisplayMode  = Console->ActiveBuffer->DisplayMode;
+            PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)Console->ActiveBuffer;
+
+            TextModeInfo.ScreenAttrib = Buffer->ScreenDefaultAttrib;
+            TextModeInfo.PopupAttrib  = Buffer->PopupDefaultAttrib;
 
-            IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible;
-            CursorSize      = Console->ActiveBuffer->CursorInfo.dwSize;
+            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;
+        }
+
+        ScreenBufferInfo = &GraphicsInfo;
 
-        /* Insert the new handle inside the process handles table */
-        Status = ConSrvInsertObject(ProcessData,
-                                    &CreateScreenBufferRequest->OutputHandle,
-                                    &Buff->Header,
-                                    CreateScreenBufferRequest->Access,
-                                    CreateScreenBufferRequest->Inheritable,
-                                    CreateScreenBufferRequest->ShareMode);
+        /* Initialize shared variables */
+        CreateScreenBufferRequest->GraphicsBufferInfo.hMutex   = GraphicsInfo.Info.hMutex   = INVALID_HANDLE_VALUE;
+        CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMap = GraphicsInfo.Info.lpBitMap = NULL;
 
-        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+        /* A graphics screen buffer is never inheritable */
+        CreateScreenBufferRequest->Inheritable = FALSE;
     }
 
-    ConSrvReleaseConsole(Console, TRUE);
-    return Status;
-}
+    Status = ConSrvCreateScreenBuffer(&Buff,
+                                      Console,
+                                      CreateScreenBufferRequest->ScreenBufferType,
+                                      ScreenBufferInfo);
+    if (!NT_SUCCESS(Status)) goto Quit;
 
-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;
+    /* Insert the new handle inside the process handles table */
+    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
 
-    DPRINT("SrvGetConsoleScreenBufferInfo\n");
+    Status = ConSrvInsertObject(ProcessData,
+                                &CreateScreenBufferRequest->OutputHandle,
+                                &Buff->Header,
+                                CreateScreenBufferRequest->Access,
+                                CreateScreenBufferRequest->Inheritable,
+                                CreateScreenBufferRequest->ShareMode);
 
-    Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ScreenBufferInfoRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
-    if (!NT_SUCCESS(Status)) return Status;
+    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
 
-    Console = Buff->Header.Console;
+    if (!NT_SUCCESS(Status)) goto Quit;
 
-    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;
+    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;
+    }
 
-    ConSrvReleaseScreenBuffer(Buff, TRUE);
-    return STATUS_SUCCESS;
+Quit:
+    ConSrvReleaseConsole(Console, TRUE);
+    return Status;
 }
 
 CSR_API(SrvSetConsoleActiveScreenBuffer)
@@ -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);
-
-    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);
-        }
-    }
+    ConioSetActiveScreenBuffer(Buff);
 
+Quit:
     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 */
index 6a903d5..f10320b 100644 (file)
@@ -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 */
index 34ca2d5..8b0330a 100644 (file)
@@ -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;
-
-    // These two lines are frontend-specific.
-    Console->ConsoleSize.X = WindowRect.Right - WindowRect.Left + 1;
-    Console->ConsoleSize.Y = WindowRect.Bottom - WindowRect.Top + 1;
+    Buff->ViewOrigin.X = WindowRect.Left;
+    Buff->ViewOrigin.Y = WindowRect.Top;
 
-    // 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)
index ec9b9aa..335bdc5 100644 (file)
@@ -24,6 +24,7 @@
 #include <wincon.h>
 #include <winuser.h>
 #define NTOS_MODE_USER
+#include <ndk/exfuncs.h>
 #include <ndk/iofuncs.h>
 #include <ndk/mmfuncs.h>
 #include <ndk/obfuncs.h>
diff --git a/reactos/win32ss/user/consrv/frontends/gui/graphics.c b/reactos/win32ss/user/consrv/frontends/gui/graphics.c
new file mode 100644 (file)
index 0000000..43df51c
--- /dev/null
@@ -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 <debug.h>
+
+
+/* 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 */
index 8a143d2..7b9a72b 100644 (file)
@@ -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
         }
 
         /*
index 1ec60ba..dd1930b 100644 (file)
@@ -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;
index 9b3c2a2..61583d1 100644 (file)
@@ -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;
+
+    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->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;
+    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,81 +828,88 @@ 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;
-
-        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;
+        GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+        Buff->CursorBlinkOn = !Buff->CursorBlinkOn;
 
-        // If we successfully got the info for the horizontal scrollbar
-        if (OldScrollX >= 0)
-        {
-            if ((Buff->CursorPosition.X < Buff->ShowX)||(Buff->CursorPosition.X >= (Buff->ShowX + Console->ConsoleSize.X)))
-            {
-                // Handle the horizontal scroll bar
-                if (Buff->CursorPosition.X >= Console->ConsoleSize.X) NewScrollX = Buff->CursorPosition.X - Console->ConsoleSize.X + 1;
-                else NewScrollX = 0;
-            }
-            else
-            {
-                NewScrollX = OldScrollX;
-            }
-        }
-        // If we successfully got the info for the vertical scrollbar
-        if (OldScrollY >= 0)
+        if ((GuiData->OldCursor.x != Buff->CursorPosition.X) || (GuiData->OldCursor.y != Buff->CursorPosition.Y))
         {
-            if ((Buff->CursorPosition.Y < Buff->ShowY) || (Buff->CursorPosition.Y >= (Buff->ShowY + Console->ConsoleSize.Y)))
+            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 vertical scroll bar
-                if (Buff->CursorPosition.Y >= Console->ConsoleSize.Y) NewScrollY = Buff->CursorPosition.Y - Console->ConsoleSize.Y + 1;
-                else NewScrollY = 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)
             {
-                NewScrollY = OldScrollY;
+                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->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)
+            // 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))
             {
-                xScroll.nPos = NewScrollY;
-                SetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll, TRUE);
+                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;
             }
-            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;
-
-        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));
-        }
+        PCONSOLE Console = GuiData->Console;
+        PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
 
-        /* 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)
+        if (GetType(Buffer) == TEXTMODE_BUFFER)
         {
-            CloseClipboard();
-            return;
+            GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer);
         }
-
-        DPRINT("Copying %dx%d selection\n", selWidth, selHeight);
-        dstPos = data;
-
-        for (yPos = 0; yPos < selHeight; yPos++)
+        else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
         {
-            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;
-            }
+            GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer);
         }
 
-        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);
         }
-
-        str = GlobalLock(hData);
-        if (str == NULL)
+        else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
         {
-            CloseClipboard();
-            return;
+            GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer);
         }
-        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 (file)
index 0000000..cdfedf4
--- /dev/null
@@ -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 <debug.h>
+
+
+/* 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 */
index b68133a..aa56b69 100644 (file)
@@ -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 (file)
index 0000000..51b6e79
--- /dev/null
@@ -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 <debug.h>
+
+
+/* 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 */
index 6f5f9b3..37c6868 100644 (file)
@@ -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;
     }
index 96b1350..dc56a26 100644 (file)
 /* 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 */
+    WORD ScreenDefaultAttrib;       /* Default screen char attribute */
+    WORD PopupDefaultAttrib;        /* Default popup char attribute */
+} TEXTMODE_SCREEN_BUFFER, *PTEXTMODE_SCREEN_BUFFER;
 
-    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 ??
+/*
+ * 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;
+
 
-    WORD ScreenDefaultAttrib;       /* Default screen char attribute */
-    WORD PopupDefaultAttrib;        /* Default popup char attribute */
-    USHORT Mode;
-    ULONG  DisplayMode;
-} CONSOLE_SCREEN_BUFFER, *PCONSOLE_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);
 
index fa324a2..551ccdc 100644 (file)
@@ -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;
 
index 4512dad..028627e 100644 (file)
@@ -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",
index 224d678..3e090a9 100644 (file)
@@ -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;
index cb00795..468eebe 100644 (file)
@@ -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)
-    {
-        if (NT_SUCCESS(ConioResizeBuffer(Console, ActiveBuffer, BufSize)))
-            SizeChanged = TRUE;
+        /* 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)
+    {
+        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 (file)
index 0000000..4712e6b
--- /dev/null
@@ -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 <debug.h>
+
+/*
+// Define wmemset(...)
+#include <wchar.h>
+#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 */