[CONSRV]: Use InterlockedExchange16 to exchange Begin and End COORD structure members.
[reactos.git] / reactos / win32ss / user / winsrv / consrv / frontends / gui / conwnd.c
index 49fb50b..acc83a4 100644 (file)
@@ -12,7 +12,7 @@
 /* INCLUDES *******************************************************************/
 
 #include <consrv.h>
-
+#include <intrin.h>
 #include <windowsx.h>
 
 #define NDEBUG
@@ -48,9 +48,7 @@ SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData)
     PCONSOLE_PROCESS_DATA ProcessData;
     CLIENT_ID ConsoleLeaderCID;
 
-    ProcessData = CONTAINING_RECORD(GuiData->Console->ProcessList.Blink,
-                                    CONSOLE_PROCESS_DATA,
-                                    ConsoleLink);
+    ProcessData = ConDrvGetConsoleLeaderProcess(GuiData->Console);
     ConsoleLeaderCID = ProcessData->Process->ClientId;
     SetWindowLongPtrW(GuiData->hWindow, GWLP_CONSOLE_LEADER_PID,
                       (LONG_PTR)(ConsoleLeaderCID.UniqueProcess));
@@ -200,8 +198,8 @@ GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer,
 }
 
 static VOID
-GuiConsoleAppendMenuItems(HMENU hMenu,
-                          const GUICONSOLE_MENUITEM *Items)
+AppendMenuItems(HMENU hMenu,
+                const GUICONSOLE_MENUITEM *Items)
 {
     UINT i = 0;
     WCHAR szMenuString[255];
@@ -221,8 +219,7 @@ GuiConsoleAppendMenuItems(HMENU hMenu,
                     hSubMenu = CreatePopupMenu();
                     if (hSubMenu != NULL)
                     {
-                        GuiConsoleAppendMenuItems(hSubMenu,
-                                                  Items[i].SubMenu);
+                        AppendMenuItems(hSubMenu, Items[i].SubMenu);
 
                         if (!AppendMenuW(hMenu,
                                          MF_STRING | MF_POPUP,
@@ -254,50 +251,121 @@ GuiConsoleAppendMenuItems(HMENU hMenu,
 }
 
 static VOID
-GuiConsoleCreateSysMenu(HWND hWnd)
+CreateSysMenu(HWND hWnd)
 {
+    MENUITEMINFOW mii;
+    WCHAR szMenuStringBack[255];
+    WCHAR *ptrTab;
     HMENU hMenu = GetSystemMenu(hWnd, FALSE);
     if (hMenu != NULL)
     {
-        GuiConsoleAppendMenuItems(hMenu, GuiConsoleMainMenuItems);
+        mii.cbSize = sizeof(mii);
+        mii.fMask = MIIM_STRING;   
+        mii.dwTypeData = szMenuStringBack;
+        mii.cch = sizeof(szMenuStringBack)/sizeof(WCHAR);
+
+        GetMenuItemInfoW(hMenu, SC_CLOSE, FALSE, &mii);
+
+        ptrTab = wcschr(szMenuStringBack, '\t');
+        if (ptrTab)
+        {
+           *ptrTab = '\0';
+           mii.cch = wcslen(szMenuStringBack);
+
+           SetMenuItemInfoW(hMenu, SC_CLOSE, FALSE, &mii);
+        }
+
+        AppendMenuItems(hMenu, GuiConsoleMainMenuItems);
         DrawMenuBar(hWnd);
     }
 }
 
 static VOID
-GuiSendMenuEvent(PCONSOLE Console, UINT CmdId)
+SendMenuEvent(PCONSOLE Console, UINT CmdId)
 {
     INPUT_RECORD er;
 
+    DPRINT1("Menu item ID: %d\n", CmdId);
+
+    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
     er.EventType = MENU_EVENT;
     er.Event.MenuEvent.dwCommandId = CmdId;
-
-    DPRINT("Menu item ID: %d\n", CmdId);
     ConioProcessInputEvent(Console, &er);
+
+    LeaveCriticalSection(&Console->Lock);
 }
 
 static VOID
-GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData);
+Copy(PGUI_CONSOLE_DATA GuiData);
 static VOID
-GuiConsolePaste(PGUI_CONSOLE_DATA GuiData);
+Paste(PGUI_CONSOLE_DATA GuiData);
 static VOID
-GuiConsoleUpdateSelection(PCONSOLE Console, PCOORD coord);
+UpdateSelection(PGUI_CONSOLE_DATA GuiData,
+                PCOORD SelectionAnchor OPTIONAL,
+                PCOORD coord);
+
 static VOID
-GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData, DWORD WidthUnit, DWORD HeightUnit);
+Mark(PGUI_CONSOLE_DATA GuiData)
+{
+    PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
 
-static LRESULT
-GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
+    /* Clear the old selection */
+    GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
+
+    /* Restart a new selection */
+    GuiData->dwSelectionCursor = ActiveBuffer->ViewOrigin;
+    UpdateSelection(GuiData,
+                    &GuiData->dwSelectionCursor,
+                    &GuiData->dwSelectionCursor);
+}
+
+static VOID
+SelectAll(PGUI_CONSOLE_DATA GuiData)
 {
-    LRESULT Ret = TRUE;
-    PCONSOLE Console = GuiData->Console;
-    PCONSOLE_SCREEN_BUFFER ActiveBuffer;
+    PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
+    COORD SelectionAnchor;
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+    /* Clear the old selection */
+    GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
+
+    /*
+     * The selection area extends to the whole screen buffer's width.
+     */
+    SelectionAnchor.X = SelectionAnchor.Y = 0;
+    GuiData->dwSelectionCursor.X = ActiveBuffer->ScreenBufferSize.X - 1;
+
+    /*
+     * Determine whether the selection must extend to just some part
+     * (for text-mode screen buffers) or to all of the screen buffer's
+     * height (for graphics ones).
+     */
+    if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
     {
-        Ret = FALSE;
-        goto Quit;
+        /*
+         * We select all the characters from the first line
+         * to the line where the cursor is positioned.
+         */
+        GuiData->dwSelectionCursor.Y = ActiveBuffer->CursorPosition.Y;
     }
-    ActiveBuffer = GuiData->ActiveBuffer;
+    else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
+    {
+        /*
+         * We select all the screen buffer area.
+         */
+        GuiData->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
+    }
+
+    /* Restart a new selection */
+    GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION;
+    UpdateSelection(GuiData, &SelectionAnchor, &GuiData->dwSelectionCursor);
+}
+
+static LRESULT
+OnCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
+{
+    LRESULT Ret = TRUE;
+    PCONSOLE Console = GuiData->Console;
 
     /*
      * In case the selected menu item belongs to the user-reserved menu id range,
@@ -306,76 +374,28 @@ GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM
      */
     if (GuiData->CmdIdLow <= (UINT)wParam && (UINT)wParam <= GuiData->CmdIdHigh)
     {
-        GuiSendMenuEvent(Console, (UINT)wParam);
-        goto Unlock_Quit;
+        SendMenuEvent(Console, (UINT)wParam);
+        goto Quit;
     }
 
     /* ... otherwise, perform actions. */
     switch (wParam)
     {
         case ID_SYSTEM_EDIT_MARK:
-        {
-            /* Clear the old selection */
-            // GuiConsoleUpdateSelection(Console, NULL);
-            Console->Selection.dwFlags = CONSOLE_NO_SELECTION;
-
-            /* Restart a new selection */
-            Console->dwSelectionCursor.X = ActiveBuffer->ViewOrigin.X;
-            Console->dwSelectionCursor.Y = ActiveBuffer->ViewOrigin.Y;
-            Console->Selection.dwSelectionAnchor = Console->dwSelectionCursor;
-            GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
-
+            Mark(GuiData);
             break;
-        }
 
         case ID_SYSTEM_EDIT_COPY:
-            GuiConsoleCopy(GuiData);
+            Copy(GuiData);
             break;
 
         case ID_SYSTEM_EDIT_PASTE:
-            GuiConsolePaste(GuiData);
+            Paste(GuiData);
             break;
 
         case ID_SYSTEM_EDIT_SELECTALL:
-        {
-            /* Clear the old selection */
-            // GuiConsoleUpdateSelection(Console, NULL);
-            Console->Selection.dwFlags = CONSOLE_NO_SELECTION;
-
-            /*
-             * The selection area extends to the whole screen buffer's width.
-             */
-            Console->Selection.dwSelectionAnchor.X = 0;
-            Console->Selection.dwSelectionAnchor.Y = 0;
-            Console->dwSelectionCursor.X = ActiveBuffer->ScreenBufferSize.X - 1;
-
-            /*
-             * Determine whether the selection must extend to just some part
-             * (for text-mode screen buffers) or to all of the screen buffer's
-             * height (for graphics ones).
-             */
-            if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
-            {
-                /*
-                 * We select all the characters from the first line
-                 * to the line where the cursor is positioned.
-                 */
-                Console->dwSelectionCursor.Y = ActiveBuffer->CursorPosition.Y;
-            }
-            else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
-            {
-                /*
-                 * We select all the screen buffer area.
-                 */
-                Console->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
-            }
-
-            /* Restart a new selection */
-            Console->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION;
-            GuiConsoleUpdateSelection(Console, &Console->dwSelectionCursor);
-
+            SelectAll(GuiData);
             break;
-        }
 
         case ID_SYSTEM_EDIT_SCROLL:
             DPRINT1("Scrolling is not handled yet\n");
@@ -398,8 +418,6 @@ GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM
             break;
     }
 
-Unlock_Quit:
-    LeaveCriticalSection(&Console->Lock);
 Quit:
     if (!Ret)
         Ret = DefWindowProcW(GuiData->hWindow, WM_SYSCOMMAND, wParam, lParam);
@@ -416,7 +434,7 @@ GuiGetGuiData(HWND hWnd)
 }
 
 static VOID
-GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData, DWORD WidthUnit, DWORD HeightUnit)
+ResizeConWnd(PGUI_CONSOLE_DATA GuiData, DWORD WidthUnit, DWORD HeightUnit)
 {
     PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer;
     SCROLLINFO sInfo;
@@ -468,7 +486,7 @@ GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData, DWORD WidthUnit, DWORD HeightU
 }
 
 static BOOL
-GuiConsoleHandleNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
+OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
 {
     PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Create->lpCreateParams;
     PCONSOLE Console;
@@ -477,8 +495,6 @@ GuiConsoleHandleNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
     TEXTMETRICW Metrics;
     SIZE CharSize;
 
-    DPRINT("GuiConsoleHandleNcCreate\n");
-
     if (NULL == GuiData)
     {
         DPRINT1("GuiConsoleNcCreate: No GUI data\n");
@@ -556,6 +572,13 @@ GuiConsoleHandleNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
     GuiData->hBitmap = NULL;
     GuiData->hSysPalette = NULL; /* Original system palette */
 
+    /* Update the icons of the window */
+    if (GuiData->hIcon != ghDefaultIcon)
+    {
+        DefWindowProcW(GuiData->hWindow, WM_SETICON, ICON_BIG  , (LPARAM)GuiData->hIcon  );
+        DefWindowProcW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
+    }
+
     // FIXME: Keep these instructions here ? ///////////////////////////////////
     Console->ActiveBuffer->CursorBlinkOn = TRUE;
     Console->ActiveBuffer->ForceCursorOff = FALSE;
@@ -564,14 +587,83 @@ GuiConsoleHandleNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
     SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)GuiData);
 
     SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
-    GuiConsoleCreateSysMenu(GuiData->hWindow);
+    CreateSysMenu(GuiData->hWindow);
 
-    DPRINT("GuiConsoleHandleNcCreate - setting start event\n");
+    DPRINT("OnNcCreate - setting start event\n");
     SetEvent(GuiData->hGuiInitEvent);
 
     return (BOOL)DefWindowProcW(GuiData->hWindow, WM_NCCREATE, 0, (LPARAM)Create);
 }
 
+
+BOOL
+EnterFullScreen(PGUI_CONSOLE_DATA GuiData);
+VOID
+LeaveFullScreen(PGUI_CONSOLE_DATA GuiData);
+VOID
+SwitchFullScreen(PGUI_CONSOLE_DATA GuiData, BOOL FullScreen);
+VOID
+GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData);
+
+static VOID
+OnActivate(PGUI_CONSOLE_DATA GuiData, WPARAM wParam)
+{
+    PCONSOLE Console = GuiData->Console;
+    WORD ActivationState = LOWORD(wParam);
+
+    DPRINT1("WM_ACTIVATE - ActivationState = %d\n");
+
+    if ( ActivationState == WA_ACTIVE ||
+         ActivationState == WA_CLICKACTIVE )
+    {
+        if (GuiData->GuiInfo.FullScreen)
+        {
+            EnterFullScreen(GuiData);
+            // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
+            // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
+        }
+    }
+    else // if (ActivationState == WA_INACTIVE)
+    {
+        if (GuiData->GuiInfo.FullScreen)
+        {
+            SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+            LeaveFullScreen(GuiData);
+            // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+            // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+        }
+    }
+
+    /*
+     * When we are in QuickEdit mode, ignore the next mouse signal
+     * when we are going to be enabled again via the mouse, in order
+     * to prevent e.g. an erroneous right-click from the user which
+     * would have as an effect to paste some unwanted text...
+     */
+    if (Console->QuickEdit && (ActivationState == WA_CLICKACTIVE))
+        GuiData->IgnoreNextMouseSignal = TRUE;
+}
+
+static VOID
+OnFocus(PGUI_CONSOLE_DATA GuiData, BOOL SetFocus)
+{
+    PCONSOLE Console = GuiData->Console;
+    INPUT_RECORD er;
+
+    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
+    er.EventType = FOCUS_EVENT;
+    er.Event.FocusEvent.bSetFocus = SetFocus;
+    ConioProcessInputEvent(Console, &er);
+
+    LeaveCriticalSection(&Console->Lock);
+
+    if (SetFocus)
+        DPRINT1("TODO: Create console caret\n");
+    else
+        DPRINT1("TODO: Destroy console caret\n");
+}
+
 static VOID
 SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
 {
@@ -586,101 +678,256 @@ SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
     Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ViewOrigin.Y) * HeightUnit;
 }
 
+VOID
+GetSelectionBeginEnd(PCOORD Begin, PCOORD End,
+                     PCOORD SelectionAnchor,
+                     PSMALL_RECT SmallRect)
+{
+    if (Begin == NULL || End == NULL) return;
+
+    *Begin = *SelectionAnchor;
+    End->X = (SelectionAnchor->X == SmallRect->Left) ? SmallRect->Right
+              /* Case X != Left, must be == Right */ : SmallRect->Left;
+    End->Y = (SelectionAnchor->Y == SmallRect->Top ) ? SmallRect->Bottom
+              /* Case Y != Top, must be == Bottom */ : SmallRect->Top;
+
+    /* Exchange Begin / End if Begin > End lexicographically */
+    if (Begin->Y > End->Y || (Begin->Y == End->Y && Begin->X > End->X))
+    {
+        End->X = _InterlockedExchange16(&Begin->X, End->X);
+        End->Y = _InterlockedExchange16(&Begin->Y, End->Y);
+    }
+}
+
+static HRGN
+CreateSelectionRgn(PGUI_CONSOLE_DATA GuiData,
+                   BOOL LineSelection,
+                   PCOORD SelectionAnchor,
+                   PSMALL_RECT SmallRect)
+{
+    if (!LineSelection)
+    {
+        RECT rect;
+        SmallRectToRect(GuiData, &rect, SmallRect);
+        return CreateRectRgnIndirect(&rect);
+    }
+    else
+    {
+        HRGN SelRgn;
+        COORD Begin, End;
+
+        GetSelectionBeginEnd(&Begin, &End, SelectionAnchor, SmallRect);
+
+        if (Begin.Y == End.Y)
+        {
+            SMALL_RECT sr;
+            RECT       r ;
+
+            sr.Left   = Begin.X;
+            sr.Top    = Begin.Y;
+            sr.Right  = End.X;
+            sr.Bottom = End.Y;
+
+            // Debug thingie to see whether I can put this corner case
+            // together with the previous one.
+            if (SmallRect->Left   != sr.Left  ||
+                SmallRect->Top    != sr.Top   ||
+                SmallRect->Right  != sr.Right ||
+                SmallRect->Bottom != sr.Bottom)
+            {
+                DPRINT1("\n"
+                        "SmallRect = (%d, %d, %d, %d)\n"
+                        "sr = (%d, %d, %d, %d)\n"
+                        "\n",
+                        SmallRect->Left, SmallRect->Top, SmallRect->Right, SmallRect->Bottom,
+                        sr.Left, sr.Top, sr.Right, sr.Bottom);
+            }
+
+            SmallRectToRect(GuiData, &r, &sr);
+            SelRgn = CreateRectRgnIndirect(&r);
+        }
+        else
+        {
+            PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
+
+            HRGN       rg1, rg2, rg3;
+            SMALL_RECT sr1, sr2, sr3;
+            RECT       r1 , r2 , r3 ;
+
+            sr1.Left   = Begin.X;
+            sr1.Top    = Begin.Y;
+            sr1.Right  = ActiveBuffer->ScreenBufferSize.X - 1;
+            sr1.Bottom = Begin.Y;
+
+            sr2.Left   = 0;
+            sr2.Top    = Begin.Y + 1;
+            sr2.Right  = ActiveBuffer->ScreenBufferSize.X - 1;
+            sr2.Bottom = End.Y - 1;
+
+            sr3.Left   = 0;
+            sr3.Top    = End.Y;
+            sr3.Right  = End.X;
+            sr3.Bottom = End.Y;
+
+            SmallRectToRect(GuiData, &r1, &sr1);
+            SmallRectToRect(GuiData, &r2, &sr2);
+            SmallRectToRect(GuiData, &r3, &sr3);
+
+            rg1 = CreateRectRgnIndirect(&r1);
+            rg2 = CreateRectRgnIndirect(&r2);
+            rg3 = CreateRectRgnIndirect(&r3);
+
+            CombineRgn(rg1, rg1, rg2, RGN_XOR);
+            CombineRgn(rg1, rg1, rg3, RGN_XOR);
+            DeleteObject(rg3);
+            DeleteObject(rg2);
+
+            SelRgn = rg1;
+        }
+
+        return SelRgn;
+    }
+}
+
+static VOID
+PaintSelectionRect(PGUI_CONSOLE_DATA GuiData, PPAINTSTRUCT pps)
+{
+    HRGN rgnPaint = CreateRectRgnIndirect(&pps->rcPaint);
+    HRGN rgnSel   = CreateSelectionRgn(GuiData, GuiData->LineSelection,
+                                       &GuiData->Selection.dwSelectionAnchor,
+                                       &GuiData->Selection.srSelection);
+
+    /* Invert the selection */
+
+    int ErrorCode = CombineRgn(rgnPaint, rgnPaint, rgnSel, RGN_AND);
+    if (ErrorCode != ERROR && ErrorCode != NULLREGION)
+    {
+        InvertRgn(pps->hdc, rgnPaint);
+    }
+
+    DeleteObject(rgnSel);
+    DeleteObject(rgnPaint);
+}
+
 static VOID
-GuiConsoleUpdateSelection(PCONSOLE Console, PCOORD coord)
+UpdateSelection(PGUI_CONSOLE_DATA GuiData,
+                PCOORD SelectionAnchor OPTIONAL,
+                PCOORD coord)
 {
-    PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
-    RECT oldRect;
+    PCONSOLE Console = GuiData->Console;
+    HRGN oldRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection,
+                                     &GuiData->Selection.dwSelectionAnchor,
+                                     &GuiData->Selection.srSelection);
 
-    SmallRectToRect(GuiData, &oldRect, &Console->Selection.srSelection);
+    /* Update the anchor if needed (use the old one if NULL) */
+    if (SelectionAnchor)
+        GuiData->Selection.dwSelectionAnchor = *SelectionAnchor;
 
     if (coord != NULL)
     {
-        RECT newRect;
         SMALL_RECT rc;
+        HRGN newRgn;
+
+        /*
+         * Pressing the Control key while selecting text, allows us to enter
+         * into line-selection mode, the selection mode of *nix terminals.
+         */
+        BOOL OldLineSel = GuiData->LineSelection;
+        GuiData->LineSelection = !!(GetKeyState(VK_CONTROL) & 0x8000);
 
         /* Exchange left/top with right/bottom if required */
-        rc.Left   = min(Console->Selection.dwSelectionAnchor.X, coord->X);
-        rc.Top    = min(Console->Selection.dwSelectionAnchor.Y, coord->Y);
-        rc.Right  = max(Console->Selection.dwSelectionAnchor.X, coord->X);
-        rc.Bottom = max(Console->Selection.dwSelectionAnchor.Y, coord->Y);
+        rc.Left   = min(GuiData->Selection.dwSelectionAnchor.X, coord->X);
+        rc.Top    = min(GuiData->Selection.dwSelectionAnchor.Y, coord->Y);
+        rc.Right  = max(GuiData->Selection.dwSelectionAnchor.X, coord->X);
+        rc.Bottom = max(GuiData->Selection.dwSelectionAnchor.Y, coord->Y);
 
-        SmallRectToRect(GuiData, &newRect, &rc);
+        newRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection,
+                                    &GuiData->Selection.dwSelectionAnchor,
+                                    &rc);
 
-        if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+        if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
         {
-            if (memcmp(&rc, &Console->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
+            if (OldLineSel != GuiData->LineSelection ||
+                memcmp(&rc, &GuiData->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
             {
-                HRGN rgn1, rgn2;
-
                 /* Calculate the region that needs to be updated */
-                if ((rgn1 = CreateRectRgnIndirect(&oldRect)))
+                if (oldRgn && newRgn && CombineRgn(newRgn, newRgn, oldRgn, RGN_XOR) != ERROR)
                 {
-                    if ((rgn2 = CreateRectRgnIndirect(&newRect)))
-                    {
-                        if (CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
-                        {
-                            InvalidateRgn(GuiData->hWindow, rgn1, FALSE);
-                        }
-                        DeleteObject(rgn2);
-                    }
-                    DeleteObject(rgn1);
+                    InvalidateRgn(GuiData->hWindow, newRgn, FALSE);
                 }
             }
         }
         else
         {
-            InvalidateRect(GuiData->hWindow, &newRect, FALSE);
+            InvalidateRgn(GuiData->hWindow, newRgn, FALSE);
         }
 
-        Console->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY;
-        Console->Selection.srSelection = rc;
-        Console->dwSelectionCursor = *coord;
+        DeleteObject(newRgn);
+
+        GuiData->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY;
+        GuiData->Selection.srSelection = rc;
+        GuiData->dwSelectionCursor = *coord;
 
-        if ((Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
+        if ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
         {
-            LPWSTR SelectionType, WindowTitle = NULL;
-            SIZE_T Length = 0;
+            LPWSTR SelTypeStr = NULL   , WindowTitle = NULL;
+            SIZE_T SelTypeStrLength = 0, Length = 0;
 
             /* Clear the old selection */
-            if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+            if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
             {
-                InvalidateRect(GuiData->hWindow, &oldRect, FALSE);
+                InvalidateRgn(GuiData->hWindow, oldRgn, FALSE);
             }
 
-            if (Console->Selection.dwFlags & CONSOLE_MOUSE_SELECTION)
-            {
-                SelectionType = L"Selection - ";
-            }
-            else
+            /*
+             * When passing a zero-length buffer size, LoadString(...) returns
+             * a read-only pointer buffer to the program's resource string.
+             */
+            SelTypeStrLength =
+                LoadStringW(ConSrvDllInstance,
+                            (GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION)
+                                ? IDS_SELECT_TITLE : IDS_MARK_TITLE,
+                            (LPWSTR)&SelTypeStr, 0);
+
+            /*
+             * Prepend the selection type string to the current console title
+             * if we succeeded in retrieving a valid localized string.
+             */
+            if (SelTypeStr)
             {
-                SelectionType = L"Mark - ";
-            }
+                // 3 for " - " and 1 for NULL
+                Length = Console->Title.Length + (SelTypeStrLength + 3 + 1) * sizeof(WCHAR);
+                WindowTitle = ConsoleAllocHeap(0, Length);
 
-            Length = Console->Title.Length + wcslen(SelectionType) + 1;
-            WindowTitle = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
-            wcscpy(WindowTitle, SelectionType);
-            wcscat(WindowTitle, Console->Title.Buffer);
-            SetWindowText(GuiData->hWindow, WindowTitle);
-            ConsoleFreeHeap(WindowTitle);
+                wcsncpy(WindowTitle, SelTypeStr, SelTypeStrLength);
+                WindowTitle[SelTypeStrLength] = L'\0';
+                wcscat(WindowTitle, L" - ");
+                wcscat(WindowTitle, Console->Title.Buffer);
 
-            Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS;
+                SetWindowText(GuiData->hWindow, WindowTitle);
+                ConsoleFreeHeap(WindowTitle);
+            }
+
+            GuiData->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS;
             ConioPause(Console, PAUSED_FROM_SELECTION);
         }
     }
     else
     {
         /* Clear the selection */
-        if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+        if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
         {
-            InvalidateRect(GuiData->hWindow, &oldRect, FALSE);
+            InvalidateRgn(GuiData->hWindow, oldRgn, FALSE);
         }
 
-        Console->Selection.dwFlags = CONSOLE_NO_SELECTION;
+        GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
         ConioUnpause(Console, PAUSED_FROM_SELECTION);
 
+        /* Restore the console title */
         SetWindowText(GuiData->hWindow, Console->Title.Buffer);
     }
+
+    DeleteObject(oldRgn);
 }
 
 
@@ -696,19 +943,12 @@ GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
                        PRECT rcFramebuffer);
 
 static VOID
-GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData)
+OnPaint(PGUI_CONSOLE_DATA GuiData)
 {
-    BOOL Success = TRUE;
-    PCONSOLE Console = GuiData->Console;
     PCONSOLE_SCREEN_BUFFER ActiveBuffer;
     PAINTSTRUCT ps;
     RECT rcPaint;
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
-    {
-        Success = FALSE;
-        goto Quit;
-    }
     ActiveBuffer = GuiData->ActiveBuffer;
 
     BeginPaint(GuiData->hWindow, &ps);
@@ -741,30 +981,40 @@ GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData)
                rcPaint.top,
                SRCCOPY);
 
-        if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+        /* Draw the selection region if needed */
+        if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
         {
-            SmallRectToRect(GuiData, &rcPaint, &Console->Selection.srSelection);
-
-            /* Invert the selection */
-            if (IntersectRect(&rcPaint, &ps.rcPaint, &rcPaint))
-            {
-                InvertRect(ps.hdc, &rcPaint);
-            }
+            PaintSelectionRect(GuiData, &ps);
         }
 
         LeaveCriticalSection(&GuiData->Lock);
     }
     EndPaint(GuiData->hWindow, &ps);
 
-Quit:
-    if (Success)
-        LeaveCriticalSection(&Console->Lock);
-    else
-        DefWindowProcW(GuiData->hWindow, WM_PAINT, 0, 0);
-
     return;
 }
 
+static VOID
+OnPaletteChanged(PGUI_CONSOLE_DATA GuiData)
+{
+    PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
+
+    // See WM_PALETTECHANGED message
+    // if ((HWND)wParam == hWnd) break;
+
+    // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
+    if (ActiveBuffer->PaletteHandle)
+    {
+        DPRINT("WM_PALETTECHANGED changing palette\n");
+
+        /* Specify the use of the system palette for the framebuffer */
+        SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage);
+
+        /* Realize the (logical) palette */
+        RealizePalette(GuiData->hMemDC);
+    }
+}
+
 static BOOL
 IsSystemKey(WORD VirtualKeyCode)
 {
@@ -789,7 +1039,7 @@ IsSystemKey(WORD VirtualKeyCode)
 }
 
 static VOID
-GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
+OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     PCONSOLE Console = GuiData->Console;
     PCONSOLE_SCREEN_BUFFER ActiveBuffer;
@@ -798,7 +1048,7 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
 
     ActiveBuffer = GuiData->ActiveBuffer;
 
-    if (Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS)
+    if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS)
     {
         WORD VirtualKeyCode = LOWORD(wParam);
 
@@ -807,30 +1057,30 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
         if (VirtualKeyCode == VK_RETURN)
         {
             /* Copy (and clear) selection if ENTER is pressed */
-            GuiConsoleCopy(GuiData);
+            Copy(GuiData);
             goto Quit;
         }
         else if ( VirtualKeyCode == VK_ESCAPE ||
-                 (VirtualKeyCode == 'C' && GetKeyState(VK_CONTROL) & 0x8000) )
+                 (VirtualKeyCode == 'C' && (GetKeyState(VK_CONTROL) & 0x8000)) )
         {
             /* Cancel selection if ESC or Ctrl-C are pressed */
-            GuiConsoleUpdateSelection(Console, NULL);
+            UpdateSelection(GuiData, NULL, NULL);
             goto Quit;
         }
 
-        if ((Console->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) == 0)
+        if ((GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) == 0)
         {
             /* Keyboard selection mode */
             BOOL Interpreted = FALSE;
-            BOOL MajPressed  = (GetKeyState(VK_SHIFT) & 0x8000);
+            BOOL MajPressed  = !!(GetKeyState(VK_SHIFT) & 0x8000);
 
             switch (VirtualKeyCode)
             {
                 case VK_LEFT:
                 {
                     Interpreted = TRUE;
-                    if (Console->dwSelectionCursor.X > 0)
-                        Console->dwSelectionCursor.X--;
+                    if (GuiData->dwSelectionCursor.X > 0)
+                        GuiData->dwSelectionCursor.X--;
 
                     break;
                 }
@@ -838,8 +1088,8 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
                 case VK_RIGHT:
                 {
                     Interpreted = TRUE;
-                    if (Console->dwSelectionCursor.X < ActiveBuffer->ScreenBufferSize.X - 1)
-                        Console->dwSelectionCursor.X++;
+                    if (GuiData->dwSelectionCursor.X < ActiveBuffer->ScreenBufferSize.X - 1)
+                        GuiData->dwSelectionCursor.X++;
 
                     break;
                 }
@@ -847,8 +1097,8 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
                 case VK_UP:
                 {
                     Interpreted = TRUE;
-                    if (Console->dwSelectionCursor.Y > 0)
-                        Console->dwSelectionCursor.Y--;
+                    if (GuiData->dwSelectionCursor.Y > 0)
+                        GuiData->dwSelectionCursor.Y--;
 
                     break;
                 }
@@ -856,8 +1106,8 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
                 case VK_DOWN:
                 {
                     Interpreted = TRUE;
-                    if (Console->dwSelectionCursor.Y < ActiveBuffer->ScreenBufferSize.Y - 1)
-                        Console->dwSelectionCursor.Y++;
+                    if (GuiData->dwSelectionCursor.Y < ActiveBuffer->ScreenBufferSize.Y - 1)
+                        GuiData->dwSelectionCursor.Y++;
 
                     break;
                 }
@@ -865,24 +1115,24 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
                 case VK_HOME:
                 {
                     Interpreted = TRUE;
-                    Console->dwSelectionCursor.X = 0;
-                    Console->dwSelectionCursor.Y = 0;
+                    GuiData->dwSelectionCursor.X = 0;
+                    GuiData->dwSelectionCursor.Y = 0;
                     break;
                 }
 
                 case VK_END:
                 {
                     Interpreted = TRUE;
-                    Console->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
+                    GuiData->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
                     break;
                 }
 
                 case VK_PRIOR:
                 {
                     Interpreted = TRUE;
-                    Console->dwSelectionCursor.Y -= ActiveBuffer->ViewSize.Y;
-                    if (Console->dwSelectionCursor.Y < 0)
-                        Console->dwSelectionCursor.Y = 0;
+                    GuiData->dwSelectionCursor.Y -= ActiveBuffer->ViewSize.Y;
+                    if (GuiData->dwSelectionCursor.Y < 0)
+                        GuiData->dwSelectionCursor.Y = 0;
 
                     break;
                 }
@@ -890,9 +1140,9 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
                 case VK_NEXT:
                 {
                     Interpreted = TRUE;
-                    Console->dwSelectionCursor.Y += ActiveBuffer->ViewSize.Y;
-                    if (Console->dwSelectionCursor.Y >= ActiveBuffer->ScreenBufferSize.Y)
-                        Console->dwSelectionCursor.Y  = ActiveBuffer->ScreenBufferSize.Y - 1;
+                    GuiData->dwSelectionCursor.Y += ActiveBuffer->ViewSize.Y;
+                    if (GuiData->dwSelectionCursor.Y >= ActiveBuffer->ScreenBufferSize.Y)
+                        GuiData->dwSelectionCursor.Y  = ActiveBuffer->ScreenBufferSize.Y - 1;
 
                     break;
                 }
@@ -903,10 +1153,9 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
 
             if (Interpreted)
             {
-                if (!MajPressed)
-                    Console->Selection.dwSelectionAnchor = Console->dwSelectionCursor;
-
-                GuiConsoleUpdateSelection(Console, &Console->dwSelectionCursor);
+                UpdateSelection(GuiData,
+                                !MajPressed ? &GuiData->dwSelectionCursor : NULL,
+                                &GuiData->dwSelectionCursor);
             }
             else if (!IsSystemKey(VirtualKeyCode))
             {
@@ -923,7 +1172,7 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
             if (!IsSystemKey(VirtualKeyCode))
             {
                 /* Clear the selection and send the key into the input buffer */
-                GuiConsoleUpdateSelection(Console, NULL);
+                UpdateSelection(GuiData, NULL, NULL);
             }
             else
             {
@@ -932,7 +1181,7 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
         }
     }
 
-    if ((Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
+    if ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
     {
         MSG Message;
 
@@ -949,12 +1198,13 @@ Quit:
 }
 
 
-// FIXME: Remove after fixing GuiConsoleHandleTimer
+// FIXME: Remove after fixing OnTimer
 VOID
-GuiInvalidateCell(IN OUT PFRONTEND This, SHORT x, SHORT y);
+InvalidateCell(PGUI_CONSOLE_DATA GuiData,
+               SHORT x, SHORT y);
 
 static VOID
-GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData)
+OnTimer(PGUI_CONSOLE_DATA GuiData)
 {
     PCONSOLE Console = GuiData->Console;
     PCONSOLE_SCREEN_BUFFER Buff;
@@ -967,7 +1217,7 @@ GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData)
 
     if (GetType(Buff) == TEXTMODE_BUFFER)
     {
-        GuiInvalidateCell(&Console->TermIFace, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+        InvalidateCell(GuiData, Buff->CursorPosition.X, Buff->CursorPosition.Y);
         Buff->CursorBlinkOn = !Buff->CursorBlinkOn;
 
         if ((GuiData->OldCursor.x != Buff->CursorPosition.X) ||
@@ -1059,7 +1309,7 @@ GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData)
 }
 
 static BOOL
-GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData)
+OnClose(PGUI_CONSOLE_DATA GuiData)
 {
     PCONSOLE Console = GuiData->Console;
 
@@ -1080,7 +1330,7 @@ GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData)
 }
 
 static LRESULT
-GuiConsoleHandleNcDestroy(HWND hWnd)
+OnNcDestroy(HWND hWnd)
 {
     PGUI_CONSOLE_DATA GuiData = GuiGetGuiData(hWnd);
 
@@ -1129,7 +1379,7 @@ PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
 }
 
 static LRESULT
-GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
+OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     BOOL Err = FALSE;
     PCONSOLE Console = GuiData->Console;
@@ -1164,7 +1414,7 @@ GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM
         goto Quit;
     }
 
-    if ( (Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) ||
+    if ( (GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) ||
          (Console->QuickEdit) )
     {
         switch (msg)
@@ -1172,27 +1422,26 @@ GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM
             case WM_LBUTTONDOWN:
             {
                 /* Clear the old selection */
-                // GuiConsoleUpdateSelection(Console, NULL);
-                Console->Selection.dwFlags = CONSOLE_NO_SELECTION;
+                GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
 
                 /* Restart a new selection */
-                Console->Selection.dwSelectionAnchor = PointToCoord(GuiData, lParam);
+                GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
                 SetCapture(GuiData->hWindow);
-                Console->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
-                GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
+                GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
+                UpdateSelection(GuiData,
+                                &GuiData->dwSelectionCursor,
+                                &GuiData->dwSelectionCursor);
 
                 break;
             }
 
             case WM_LBUTTONUP:
             {
-                // COORD c;
+                if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
 
-                if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
-
-                // c = PointToCoord(GuiData, lParam);
-                Console->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
-                // GuiConsoleUpdateSelection(Console, &c);
+                // GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
+                GuiData->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
+                // UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
                 ReleaseCapture();
 
                 break;
@@ -1204,10 +1453,7 @@ GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM
 
                 if (GetType(Buffer) == TEXTMODE_BUFFER)
                 {
-#ifdef IS_WHITESPACE
-#undef IS_WHITESPACE
-#endif
-#define IS_WHITESPACE(c)    \
+#define IS_WORD_SEP(c)  \
     ((c) == L'\0' || (c) == L' ' || (c) == L'\t' || (c) == L'\r' || (c) == L'\n')
 
                     PTEXTMODE_SCREEN_BUFFER TextBuffer = (PTEXTMODE_SCREEN_BUFFER)Buffer;
@@ -1219,15 +1465,15 @@ GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM
                     ptrL = ptrR = ConioCoordToPointer(TextBuffer, cL.X, cL.Y);
 
                     /* Enlarge the selection by checking for whitespace */
-                    while ((0 < cL.X) && !IS_WHITESPACE(ptrL->Char.UnicodeChar)
-                                      && !IS_WHITESPACE((ptrL-1)->Char.UnicodeChar))
+                    while ((0 < cL.X) && !IS_WORD_SEP(ptrL->Char.UnicodeChar)
+                                      && !IS_WORD_SEP((ptrL-1)->Char.UnicodeChar))
                     {
                         --cL.X;
                         --ptrL;
                     }
                     while ((cR.X < TextBuffer->ScreenBufferSize.X - 1) &&
-                           !IS_WHITESPACE(ptrR->Char.UnicodeChar)      &&
-                           !IS_WHITESPACE((ptrR+1)->Char.UnicodeChar))
+                           !IS_WORD_SEP(ptrR->Char.UnicodeChar)        &&
+                           !IS_WORD_SEP((ptrR+1)->Char.UnicodeChar))
                     {
                         ++cR.X;
                         ++ptrR;
@@ -1237,12 +1483,8 @@ GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM
                      * Update the selection started with the single
                      * left-click that preceded this double-click.
                      */
-                    Console->Selection.dwSelectionAnchor = cL;
-                    Console->dwSelectionCursor           = cR;
-
-                    SetCapture(GuiData->hWindow);
-                    Console->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
-                    GuiConsoleUpdateSelection(Console, &Console->dwSelectionCursor);
+                    GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
+                    UpdateSelection(GuiData, &cL, &cR);
 
                     /* Ignore the next mouse move signal */
                     GuiData->IgnoreNextMouseSignal = TRUE;
@@ -1254,13 +1496,13 @@ GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM
             case WM_RBUTTONDOWN:
             case WM_RBUTTONDBLCLK:
             {
-                if (!(Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
+                if (!(GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
                 {
-                    GuiConsolePaste(GuiData);
+                    Paste(GuiData);
                 }
                 else
                 {
-                    GuiConsoleCopy(GuiData);
+                    Copy(GuiData);
                 }
 
                 /* Ignore the next mouse move signal */
@@ -1270,13 +1512,12 @@ GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM
 
             case WM_MOUSEMOVE:
             {
-                COORD c;
-
                 if (!(wParam & MK_LBUTTON)) break;
-                if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
+                if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
 
-                c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */
-                GuiConsoleUpdateSelection(Console, &c);
+                // TODO: Scroll buffer to bring SelectionCursor into view
+                GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
+                UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
 
                 break;
             }
@@ -1427,10 +1668,8 @@ GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
                           PGUI_CONSOLE_DATA GuiData);
 
 static VOID
-GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData)
+Copy(PGUI_CONSOLE_DATA GuiData)
 {
-    PCONSOLE Console = GuiData->Console;
-
     if (OpenClipboard(GuiData->hWindow) == TRUE)
     {
         PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
@@ -1448,7 +1687,7 @@ GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData)
     }
 
     /* Clear the selection */
-    GuiConsoleUpdateSelection(Console, NULL);
+    UpdateSelection(GuiData, NULL, NULL);
 }
 
 VOID
@@ -1459,7 +1698,7 @@ GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
                          PGUI_CONSOLE_DATA GuiData);
 
 static VOID
-GuiConsolePaste(PGUI_CONSOLE_DATA GuiData)
+Paste(PGUI_CONSOLE_DATA GuiData)
 {
     if (OpenClipboard(GuiData->hWindow) == TRUE)
     {
@@ -1479,7 +1718,7 @@ GuiConsolePaste(PGUI_CONSOLE_DATA GuiData)
 }
 
 static VOID
-GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
+OnGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
 {
     PCONSOLE Console = GuiData->Console;
     PCONSOLE_SCREEN_BUFFER ActiveBuffer;
@@ -1511,7 +1750,7 @@ GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
 }
 
 static VOID
-GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
+OnSize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
 {
     PCONSOLE Console = GuiData->Console;
 
@@ -1560,7 +1799,7 @@ GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
             Buff->ViewSize.Y = (chary <= Buff->ScreenBufferSize.Y) ? chary : Buff->ScreenBufferSize.Y;
         }
 
-        GuiConsoleResizeWindow(GuiData, WidthUnit, HeightUnit);
+        ResizeConWnd(GuiData, WidthUnit, HeightUnit);
 
         // Adjust the start of the visible area if we are attempting to show nonexistent areas
         if ((Buff->ScreenBufferSize.X - Buff->ViewOrigin.X) < Buff->ViewSize.X) Buff->ViewOrigin.X = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
@@ -1573,6 +1812,20 @@ GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
     LeaveCriticalSection(&Console->Lock);
 }
 
+static VOID
+OnMove(PGUI_CONSOLE_DATA GuiData)
+{
+    RECT rcWnd;
+
+    // TODO: Simplify the code.
+    // See: GuiConsoleNotifyWndProc() PM_CREATE_CONSOLE.
+
+    /* Retrieve our real position */
+    GetWindowRect(GuiData->hWindow, &rcWnd);
+    GuiData->GuiInfo.WindowOrigin.x = rcWnd.left;
+    GuiData->GuiInfo.WindowOrigin.y = rcWnd.top;
+}
+
 /*
 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
 
@@ -1603,7 +1856,7 @@ GuiConsoleHandleScrollbarMenu(VOID)
 */
 
 static LRESULT
-GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
+OnScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
 {
     PCONSOLE Console = GuiData->Console;
     PCONSOLE_SCREEN_BUFFER Buff;
@@ -1711,15 +1964,6 @@ Quit:
 }
 
 
-BOOL
-EnterFullScreen(PGUI_CONSOLE_DATA GuiData);
-VOID
-LeaveFullScreen(PGUI_CONSOLE_DATA GuiData);
-VOID
-SwitchFullScreen(PGUI_CONSOLE_DATA GuiData, BOOL FullScreen);
-VOID
-GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData);
-
 static LRESULT CALLBACK
 ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
@@ -1735,11 +1979,11 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
      */
     if (msg == WM_NCCREATE)
     {
-        return (LRESULT)GuiConsoleHandleNcCreate(hWnd, (LPCREATESTRUCTW)lParam);
+        return (LRESULT)OnNcCreate(hWnd, (LPCREATESTRUCTW)lParam);
     }
     else if (msg == WM_NCDESTROY)
     {
-        return GuiConsoleHandleNcDestroy(hWnd);
+        return OnNcDestroy(hWnd);
     }
 
     /*
@@ -1764,60 +2008,23 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
     switch (msg)
     {
         case WM_ACTIVATE:
-        {
-            WORD ActivationState = LOWORD(wParam);
-
-            DPRINT1("WM_ACTIVATE - ActivationState = %d\n");
-
-            if ( ActivationState == WA_ACTIVE ||
-                 ActivationState == WA_CLICKACTIVE )
-            {
-                if (GuiData->GuiInfo.FullScreen)
-                {
-                    EnterFullScreen(GuiData);
-                    // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
-                    // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
-                }
-            }
-            else // if (ActivationState == WA_INACTIVE)
-            {
-                if (GuiData->GuiInfo.FullScreen)
-                {
-                    SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
-                    LeaveFullScreen(GuiData);
-                    // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
-                    // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
-                }
-            }
-
-            /*
-             * When we are in QuickEdit mode, ignore the next mouse signal
-             * when we are going to be enabled again via the mouse, in order
-             * to prevent e.g. an erroneous right-click from the user which
-             * would have as an effect to paste some unwanted text...
-             */
-            if (Console->QuickEdit && (ActivationState == WA_CLICKACTIVE))
-                GuiData->IgnoreNextMouseSignal = TRUE;
-
+            OnActivate(GuiData, wParam);
             break;
-        }
 
         case WM_CLOSE:
-            if (GuiConsoleHandleClose(GuiData)) goto Default;
+            if (OnClose(GuiData)) goto Default;
             break;
 
         case WM_PAINT:
-            GuiConsoleHandlePaint(GuiData);
+            OnPaint(GuiData);
             break;
 
         case WM_TIMER:
-            GuiConsoleHandleTimer(GuiData);
+            OnTimer(GuiData);
             break;
 
         case WM_PALETTECHANGED:
         {
-            PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
-
             DPRINT("WM_PALETTECHANGED called\n");
 
             /*
@@ -1836,21 +2043,8 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
             if ((HWND)wParam == hWnd) break;
 
             DPRINT("WM_PALETTECHANGED ok\n");
-
-            // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
-            if (ActiveBuffer->PaletteHandle)
-            {
-                DPRINT("WM_PALETTECHANGED changing palette\n");
-
-                /* Specify the use of the system palette for the framebuffer */
-                SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage);
-
-                /* Realize the (logical) palette */
-                RealizePalette(GuiData->hMemDC);
-            }
-
+            OnPaletteChanged(GuiData);
             DPRINT("WM_PALETTECHANGED quit\n");
-
             break;
         }
 
@@ -1872,8 +2066,13 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
                 break;
             }
+            /* Detect Alt-Esc/Space/Tab presses defer to DefWindowProc */
+            if ( (HIWORD(lParam) & KF_ALTDOWN) && (wParam == VK_ESCAPE || wParam == VK_SPACE || wParam == VK_TAB))
+            {
+               return DefWindowProcW(hWnd, msg, wParam, lParam);
+            }
 
-            GuiConsoleHandleKey(GuiData, msg, wParam, lParam);
+            OnKey(GuiData, msg, wParam, lParam);
             break;
         }
 
@@ -1938,41 +2137,17 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
         case WM_MOUSEWHEEL:
         case WM_MOUSEHWHEEL:
         {
-            Result = GuiConsoleHandleMouse(GuiData, msg, wParam, lParam);
+            Result = OnMouse(GuiData, msg, wParam, lParam);
             break;
         }
 
         case WM_HSCROLL:
         case WM_VSCROLL:
         {
-            Result = GuiConsoleHandleScroll(GuiData, msg, wParam);
+            Result = OnScroll(GuiData, msg, wParam);
             break;
         }
 
-        case WM_NCRBUTTONDOWN:
-        {
-            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
-             * (non-client) application title-bar does not display the system
-             * menu and does not trigger a WM_NCRBUTTONUP message too.
-             * See: http://git.reactos.org/?p=reactos.git;a=blob;f=reactos/win32ss/user/user32/windows/defwnd.c;hb=332bc8f482f40fd05ab510f78276576719fbfba8#l1103
-             * and line 1135 too.
-             */
-#if 0
-            if (DefWindowProcW(hWnd, WM_NCHITTEST, 0, lParam) == HTCAPTION)
-            {
-                /* Call DefWindowProcW with the WM_CONTEXTMENU message */
-                msg = WM_CONTEXTMENU;
-            }
-#endif
-            goto Default;
-        }
-        // case WM_NCRBUTTONUP:
-            // DPRINT1("WM_NCRBUTTONUP\n");
-            // goto Default;
-
         case WM_CONTEXTMENU:
         {
             if (DefWindowProcW(hWnd /*GuiData->hWindow*/, WM_NCHITTEST, 0, lParam) == HTCLIENT)
@@ -1980,7 +2155,7 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
                 HMENU hMenu = CreatePopupMenu();
                 if (hMenu != NULL)
                 {
-                    GuiConsoleAppendMenuItems(hMenu, GuiConsoleEditMenuItems);
+                    AppendMenuItems(hMenu, GuiConsoleEditMenuItems);
                     TrackPopupMenuEx(hMenu,
                                      TPM_RIGHTBUTTON,
                                      GET_X_LPARAM(lParam),
@@ -2008,20 +2183,16 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
                 /* Enable or disable the Copy and Paste items */
                 EnableMenuItem(hMenu, ID_SYSTEM_EDIT_COPY , MF_BYCOMMAND |
-                               ((Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
-                                (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) ? MF_ENABLED : MF_GRAYED));
+                               ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
+                                (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) ? MF_ENABLED : MF_GRAYED));
                 // FIXME: Following whether the active screen buffer is text-mode
                 // or graphics-mode, search for CF_UNICODETEXT or CF_BITMAP formats.
                 EnableMenuItem(hMenu, ID_SYSTEM_EDIT_PASTE, MF_BYCOMMAND |
-                               (!(Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
+                               (!(GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
                                 IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED));
             }
 
-            if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
-            {
-                GuiSendMenuEvent(Console, WM_INITMENU);
-                LeaveCriticalSection(&Console->Lock);
-            }
+            SendMenuEvent(Console, WM_INITMENU);
             break;
         }
 
@@ -2029,11 +2200,7 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
         {
             if (HIWORD(wParam) == 0xFFFF) // Allow all the menu flags
             {
-                if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
-                {
-                    GuiSendMenuEvent(Console, WM_MENUSELECT);
-                    LeaveCriticalSection(&Console->Lock);
-                }
+                SendMenuEvent(Console, WM_MENUSELECT);
             }
             break;
         }
@@ -2041,57 +2208,65 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
         case WM_COMMAND:
         case WM_SYSCOMMAND:
         {
-            Result = GuiConsoleHandleSysMenuCommand(GuiData, wParam, lParam);
+            Result = OnCommand(GuiData, wParam, lParam);
             break;
         }
 
         case WM_SETFOCUS:
         case WM_KILLFOCUS:
-        {
-            if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
-            {
-                BOOL SetFocus = (msg == WM_SETFOCUS);
-                INPUT_RECORD er;
-
-                er.EventType = FOCUS_EVENT;
-                er.Event.FocusEvent.bSetFocus = SetFocus;
-                ConioProcessInputEvent(Console, &er);
-
-                if (SetFocus)
-                    DPRINT1("TODO: Create console caret\n");
-                else
-                    DPRINT1("TODO: Destroy console caret\n");
-
-                LeaveCriticalSection(&Console->Lock);
-            }
+            OnFocus(GuiData, (msg == WM_SETFOCUS));
             break;
-        }
 
         case WM_GETMINMAXINFO:
-            GuiConsoleGetMinMaxInfo(GuiData, (PMINMAXINFO)lParam);
+            OnGetMinMaxInfo(GuiData, (PMINMAXINFO)lParam);
             break;
 
         case WM_MOVE:
+            OnMove(GuiData);
+            break;
+
+#if 0 // This code is here to prepare & control dynamic console SB resizing.
+        case WM_SIZING:
         {
-            if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+            PRECT dragRect = (PRECT)lParam;
+            switch (wParam)
             {
-                // TODO: Simplify the code.
-                // See: GuiConsoleNotifyWndProc() PM_CREATE_CONSOLE.
-
-                RECT rcWnd;
-
-                /* Retrieve our real position */
-                GetWindowRect(GuiData->hWindow, &rcWnd);
-                GuiData->GuiInfo.WindowOrigin.x = rcWnd.left;
-                GuiData->GuiInfo.WindowOrigin.y = rcWnd.top;
-
-                LeaveCriticalSection(&Console->Lock);
+                case WMSZ_LEFT:
+                    DPRINT1("WMSZ_LEFT\n");
+                    break;
+                case WMSZ_RIGHT:
+                    DPRINT1("WMSZ_RIGHT\n");
+                    break;
+                case WMSZ_TOP:
+                    DPRINT1("WMSZ_TOP\n");
+                    break;
+                case WMSZ_TOPLEFT:
+                    DPRINT1("WMSZ_TOPLEFT\n");
+                    break;
+                case WMSZ_TOPRIGHT:
+                    DPRINT1("WMSZ_TOPRIGHT\n");
+                    break;
+                case WMSZ_BOTTOM:
+                    DPRINT1("WMSZ_BOTTOM\n");
+                    break;
+                case WMSZ_BOTTOMLEFT:
+                    DPRINT1("WMSZ_BOTTOMLEFT\n");
+                    break;
+                case WMSZ_BOTTOMRIGHT:
+                    DPRINT1("WMSZ_BOTTOMRIGHT\n");
+                    break;
+                default:
+                    DPRINT1("wParam = %d\n", wParam);
+                    break;
             }
+            DPRINT1("dragRect = {.left = %d ; .top = %d ; .right = %d ; .bottom = %d}\n",
+                    dragRect->left, dragRect->top, dragRect->right, dragRect->bottom);
             break;
         }
+#endif
 
         case WM_SIZE:
-            GuiConsoleResize(GuiData, wParam, lParam);
+            OnSize(GuiData, wParam, lParam);
             break;
 
         case PM_RESIZE_TERMINAL:
@@ -2121,18 +2296,14 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
             /* Resize the window to the user's values */
             GuiData->WindowSizeLock = TRUE;
-            GuiConsoleResizeWindow(GuiData, WidthUnit, HeightUnit);
+            ResizeConWnd(GuiData, WidthUnit, HeightUnit);
             GuiData->WindowSizeLock = FALSE;
             break;
         }
 
         case PM_APPLY_CONSOLE_INFO:
         {
-            if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
-            {
-                GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
-                LeaveCriticalSection(&Console->Lock);
-            }
+            GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
             break;
         }