[CONSRV] Cache the console window system menu handle; simplify its initialization...
[reactos.git] / win32ss / user / winsrv / consrv / frontends / gui / conwnd.c
index 84de187..13f5da9 100644 (file)
@@ -1,12 +1,13 @@
 /*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS Console Server DLL
- * FILE:            frontends/gui/conwnd.c
+ * FILE:            win32ss/user/winsrv/consrv/frontends/gui/conwnd.c
  * PURPOSE:         GUI Console Window Class
  * PROGRAMMERS:     Gé van Geldorp
  *                  Johannes Anderwald
  *                  Jeffrey Morlan
  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
+ *                  Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
  */
 
 /* INCLUDES *******************************************************************/
 #include <consrv.h>
 #include <intrin.h>
 #include <windowsx.h>
+#include <shellapi.h>
 
 #define NDEBUG
 #include <debug.h>
 
+#include "font.h"
 #include "guiterm.h"
-#include "conwnd.h"
 #include "resource.h"
 
 /* GLOBALS ********************************************************************/
@@ -137,7 +139,7 @@ RegisterConWndClass(IN HINSTANCE hInstance)
                                  GetSystemMetrics(SM_CXSMICON),
                                  GetSystemMetrics(SM_CYSMICON),
                                  LR_SHARED);
-    ghDefaultCursor = LoadCursorW(NULL, IDC_ARROW);
+    ghDefaultCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW));
 
     WndClass.cbSize = sizeof(WNDCLASSEXW);
     WndClass.lpszClassName = GUI_CONWND_CLASS;
@@ -171,32 +173,6 @@ UnRegisterConWndClass(HINSTANCE hInstance)
     return !!UnregisterClassW(GUI_CONWND_CLASS, hInstance);
 }
 
-
-
-static VOID
-GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer,
-                         IN PGUI_CONSOLE_DATA GuiData,
-                         OUT PUINT WidthUnit,
-                         OUT PUINT HeightUnit)
-{
-    if (Buffer == NULL || GuiData == NULL ||
-        WidthUnit == NULL || HeightUnit == NULL)
-    {
-        return;
-    }
-
-    if (GetType(Buffer) == TEXTMODE_BUFFER)
-    {
-        *WidthUnit  = GuiData->CharWidth ;
-        *HeightUnit = GuiData->CharHeight;
-    }
-    else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
-    {
-        *WidthUnit  = 1;
-        *HeightUnit = 1;
-    }
-}
-
 static VOID
 AppendMenuItems(HMENU hMenu,
                 const GUICONSOLE_MENUITEM *Items)
@@ -212,7 +188,7 @@ AppendMenuItems(HMENU hMenu,
             if (LoadStringW(ConSrvDllInstance,
                             Items[i].uID,
                             szMenuString,
-                            sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
+                            ARRAYSIZE(szMenuString)) > 0)
             {
                 if (Items[i].SubMenu != NULL)
                 {
@@ -255,30 +231,32 @@ VOID
 CreateSysMenu(HWND hWnd)
 {
     MENUITEMINFOW mii;
+    HMENU hMenu;
+    PWCHAR ptrTab;
     WCHAR szMenuStringBack[255];
-    WCHAR *ptrTab;
-    HMENU hMenu = GetSystemMenu(hWnd, FALSE);
-    if (hMenu != NULL)
-    {
-        mii.cbSize = sizeof(mii);
-        mii.fMask = MIIM_STRING;   
-        mii.dwTypeData = szMenuStringBack;
-        mii.cch = sizeof(szMenuStringBack)/sizeof(WCHAR);
 
-        GetMenuItemInfoW(hMenu, SC_CLOSE, FALSE, &mii);
+    hMenu = GetSystemMenu(hWnd, FALSE);
+    if (hMenu == NULL)
+        return;
 
-        ptrTab = wcschr(szMenuStringBack, '\t');
-        if (ptrTab)
-        {
-           *ptrTab = '\0';
-           mii.cch = wcslen(szMenuStringBack);
+    mii.cbSize = sizeof(mii);
+    mii.fMask = MIIM_STRING;
+    mii.dwTypeData = szMenuStringBack;
+    mii.cch = ARRAYSIZE(szMenuStringBack);
 
-           SetMenuItemInfoW(hMenu, SC_CLOSE, FALSE, &mii);
-        }
+    GetMenuItemInfoW(hMenu, SC_CLOSE, FALSE, &mii);
+
+    ptrTab = wcschr(szMenuStringBack, L'\t');
+    if (ptrTab)
+    {
+        *ptrTab = L'\0';
+        mii.cch = wcslen(szMenuStringBack);
 
-        AppendMenuItems(hMenu, GuiConsoleMainMenuItems);
-        DrawMenuBar(hWnd);
+        SetMenuItemInfoW(hMenu, SC_CLOSE, FALSE, &mii);
     }
+
+    AppendMenuItems(hMenu, GuiConsoleMainMenuItems);
+    DrawMenuBar(hWnd);
 }
 
 static VOID
@@ -286,10 +264,11 @@ SendMenuEvent(PCONSRV_CONSOLE Console, UINT CmdId)
 {
     INPUT_RECORD er;
 
-    DPRINT1("Menu item ID: %d\n", CmdId);
+    DPRINT("Menu item ID: %d\n", CmdId);
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return;
 
+    /* Send a menu event */
     er.EventType = MENU_EVENT;
     er.Event.MenuEvent.dwCommandId = CmdId;
     ConioProcessInputEvent(Console, &er);
@@ -448,7 +427,7 @@ ResizeConWnd(PGUI_CONSOLE_DATA GuiData, DWORD WidthUnit, DWORD HeightUnit)
              2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
 
     /* Set scrollbar sizes */
-    sInfo.cbSize = sizeof(SCROLLINFO);
+    sInfo.cbSize = sizeof(sInfo);
     sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
     sInfo.nMin = 0;
     if (Buff->ScreenBufferSize.Y > Buff->ViewSize.Y)
@@ -479,7 +458,7 @@ ResizeConWnd(PGUI_CONSOLE_DATA GuiData, DWORD WidthUnit, DWORD HeightUnit)
         ShowScrollBar(GuiData->hWindow, SB_HORZ, FALSE);
     }
 
-    /* Resize the window  */
+    /* Resize the window */
     SetWindowPos(GuiData->hWindow, NULL, 0, 0, Width, Height,
                  SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS);
     // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call
@@ -491,7 +470,7 @@ VOID
 DeleteFonts(PGUI_CONSOLE_DATA GuiData)
 {
     ULONG i;
-    for (i = 0; i < sizeof(GuiData->Font) / sizeof(GuiData->Font[0]); ++i)
+    for (i = 0; i < ARRAYSIZE(GuiData->Font); ++i)
     {
         if (GuiData->Font[i] != NULL) DeleteObject(GuiData->Font[i]);
         GuiData->Font[i] = NULL;
@@ -506,13 +485,13 @@ CreateDerivedFont(HFONT OrgFont,
                   BOOLEAN bUnderline,
                   BOOLEAN bStrikeOut)
 {
-    LOGFONT lf;
+    LOGFONTW lf;
 
     /* Initialize the LOGFONT structure */
     RtlZeroMemory(&lf, sizeof(lf));
 
     /* Retrieve the details of the current font */
-    if (GetObject(OrgFont, sizeof(lf), &lf) == 0)
+    if (GetObjectW(OrgFont, sizeof(lf), &lf) == 0)
         return NULL;
 
     /* Change the font attributes */
@@ -524,7 +503,7 @@ CreateDerivedFont(HFONT OrgFont,
     lf.lfStrikeOut = bStrikeOut;
 
     /* Build a new font */
-    return CreateFontIndirect(&lf);
+    return CreateFontIndirectW(&lf);
 }
 
 BOOL
@@ -535,67 +514,32 @@ InitFonts(PGUI_CONSOLE_DATA GuiData,
           ULONG  FontWeight)
 {
     HDC hDC;
-    HFONT OldFont, NewFont;
-    TEXTMETRICW Metrics;
-    SIZE CharSize;
+    HFONT hFont;
 
     /*
-     * Initialize a new NORMAL font and get its metrics.
+     * Initialize a new NORMAL font and get its character cell size.
      */
-
-    NewFont = CreateFontW(FontSize.Y,
-                          FontSize.X,
-                          0,
-                          TA_BASELINE,
-                          FontWeight,
-                          FALSE,
-                          FALSE,
-                          FALSE,
-                          OEM_CHARSET,
-                          OUT_DEFAULT_PRECIS,
-                          CLIP_DEFAULT_PRECIS,
-                          DEFAULT_QUALITY, // NONANTIALIASED_QUALITY ; ANTIALIASED_QUALITY
-                          FIXED_PITCH | FontFamily,
-                          FaceName);
-    if (NewFont == NULL)
+    /* NOTE: FontSize is always in cell height/width units (pixels) */
+    hFont = CreateConsoleFontEx((LONG)(ULONG)FontSize.Y,
+                                (LONG)(ULONG)FontSize.X,
+                                FaceName,
+                                FontFamily,
+                                FontWeight,
+                                GuiData->Console->OutputCodePage);
+    if (hFont == NULL)
     {
-        DPRINT1("InitFonts: CreateFontW failed\n");
+        DPRINT1("InitFonts: CreateConsoleFontEx failed\n");
         return FALSE;
     }
 
     hDC = GetDC(GuiData->hWindow);
-    if (hDC == NULL)
-    {
-        DPRINT1("InitFonts: GetDC failed\n");
-        DeleteObject(NewFont);
-        return FALSE;
-    }
-
-    OldFont = SelectObject(hDC, NewFont);
-    if (OldFont == NULL)
+    if (!GetFontCellSize(hDC, hFont, &GuiData->CharHeight, &GuiData->CharWidth))
     {
-        DPRINT1("InitFonts: SelectObject failed\n");
+        DPRINT1("InitFonts: GetFontCellSize failed\n");
         ReleaseDC(GuiData->hWindow, hDC);
-        DeleteObject(NewFont);
+        DeleteObject(hFont);
         return FALSE;
     }
-
-    if (!GetTextMetricsW(hDC, &Metrics))
-    {
-        DPRINT1("InitFonts: GetTextMetrics failed\n");
-        SelectObject(hDC, OldFont);
-        ReleaseDC(GuiData->hWindow, hDC);
-        DeleteObject(NewFont);
-        return FALSE;
-    }
-    GuiData->CharWidth  = Metrics.tmMaxCharWidth;
-    GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
-
-    /* Measure real char width more precisely if possible. */
-    if (GetTextExtentPoint32W(hDC, L"R", 1, &CharSize))
-        GuiData->CharWidth = CharSize.cx;
-
-    SelectObject(hDC, OldFont);
     ReleaseDC(GuiData->hWindow, hDC);
 
     /*
@@ -603,7 +547,7 @@ InitFonts(PGUI_CONSOLE_DATA GuiData,
      */
     // Delete all the old fonts first.
     DeleteFonts(GuiData);
-    GuiData->Font[FONT_NORMAL] = NewFont;
+    GuiData->Font[FONT_NORMAL] = hFont;
 
     /*
      * Now build the other fonts (bold, underlined, mixed).
@@ -629,9 +573,8 @@ InitFonts(PGUI_CONSOLE_DATA GuiData,
      */
     if (FaceName != GuiData->GuiInfo.FaceName)
     {
-        SIZE_T Length = min(wcslen(FaceName) + 1, LF_FACESIZE); // wcsnlen
-        wcsncpy(GuiData->GuiInfo.FaceName, FaceName, LF_FACESIZE);
-        GuiData->GuiInfo.FaceName[Length] = L'\0'; // NULL-terminate
+        StringCchCopyNW(GuiData->GuiInfo.FaceName, ARRAYSIZE(GuiData->GuiInfo.FaceName),
+                        FaceName, LF_FACESIZE);
     }
     GuiData->GuiInfo.FontFamily = FontFamily;
     GuiData->GuiInfo.FontSize   = FontSize;
@@ -647,7 +590,7 @@ OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
     PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Create->lpCreateParams;
     PCONSRV_CONSOLE Console;
 
-    if (NULL == GuiData)
+    if (GuiData == NULL)
     {
         DPRINT1("GuiConsoleNcCreate: No GUI data\n");
         return FALSE;
@@ -656,6 +599,7 @@ OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
     Console = GuiData->Console;
 
     GuiData->hWindow = hWnd;
+    GuiData->hSysMenu = GetSystemMenu(hWnd, FALSE);
 
     /* Initialize the fonts */
     if (!InitFonts(GuiData,
@@ -666,7 +610,7 @@ OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
     {
         DPRINT1("GuiConsoleNcCreate: InitFonts failed\n");
         GuiData->hWindow = NULL;
-        SetEvent(GuiData->hGuiInitEvent);
+        NtSetEvent(GuiData->hGuiInitEvent, NULL);
         return FALSE;
     }
 
@@ -689,32 +633,29 @@ OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
 
     SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)GuiData);
 
-    SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
+    if (GuiData->IsWindowVisible)
+    {
+        SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
+    }
+
     // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
     //CreateSysMenu(GuiData->hWindow);
 
     DPRINT("OnNcCreate - setting start event\n");
-    SetEvent(GuiData->hGuiInitEvent);
+    NtSetEvent(GuiData->hGuiInitEvent, NULL);
+
+    /* We accept dropped files */
+    DragAcceptFiles(GuiData->hWindow, TRUE);
 
     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)
 {
     WORD ActivationState = LOWORD(wParam);
 
-    DPRINT1("WM_ACTIVATE - ActivationState = %d\n");
+    DPRINT("WM_ACTIVATE - ActivationState = %d\n", ActivationState);
 
     if ( ActivationState == WA_ACTIVE ||
          ActivationState == WA_CLICKACTIVE )
@@ -752,8 +693,18 @@ OnFocus(PGUI_CONSOLE_DATA GuiData, BOOL SetFocus)
     PCONSRV_CONSOLE Console = GuiData->Console;
     INPUT_RECORD er;
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return;
+
+    /* Set console focus state */
+    Console->HasFocus = SetFocus;
+
+    /*
+     * Set the priority of the processes of this console
+     * in accordance with the console focus state.
+     */
+    ConSrvSetConsoleProcessFocus(Console, SetFocus);
 
+    /* Send a focus event */
     er.EventType = FOCUS_EVENT;
     er.Event.FocusEvent.bSetFocus = SetFocus;
     ConioProcessInputEvent(Console, &er);
@@ -761,23 +712,9 @@ OnFocus(PGUI_CONSOLE_DATA GuiData, BOOL SetFocus)
     LeaveCriticalSection(&Console->Lock);
 
     if (SetFocus)
-        DPRINT1("TODO: Create console caret\n");
+        DPRINT("TODO: Create console caret\n");
     else
-        DPRINT1("TODO: Destroy console caret\n");
-}
-
-static VOID
-SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
-{
-    PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
-    UINT WidthUnit, HeightUnit;
-
-    GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
-
-    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;
+        DPRINT("TODO: Destroy console caret\n");
 }
 
 VOID
@@ -925,6 +862,8 @@ UpdateSelection(PGUI_CONSOLE_DATA GuiData,
     if (SelectionAnchor)
         GuiData->Selection.dwSelectionAnchor = *SelectionAnchor;
 
+    // TODO: Scroll buffer to bring 'coord' into view
+
     if (coord != NULL)
     {
         SMALL_RECT rc;
@@ -935,7 +874,7 @@ UpdateSelection(PGUI_CONSOLE_DATA GuiData,
          * into line-selection mode, the selection mode of *nix terminals.
          */
         BOOL OldLineSel = GuiData->LineSelection;
-        GuiData->LineSelection = !!(GetKeyState(VK_CONTROL) & 0x8000);
+        GuiData->LineSelection = !!(GetKeyState(VK_CONTROL) & KEY_PRESSED);
 
         /* Exchange left/top with right/bottom if required */
         rc.Left   = min(GuiData->Selection.dwSelectionAnchor.X, coord->X);
@@ -1002,11 +941,11 @@ UpdateSelection(PGUI_CONSOLE_DATA GuiData,
                 WindowTitle = ConsoleAllocHeap(0, Length);
 
                 wcsncpy(WindowTitle, SelTypeStr, SelTypeStrLength);
-                WindowTitle[SelTypeStrLength] = L'\0';
+                WindowTitle[SelTypeStrLength] = UNICODE_NULL;
                 wcscat(WindowTitle, L" - ");
                 wcscat(WindowTitle, Console->Title.Buffer);
 
-                SetWindowText(GuiData->hWindow, WindowTitle);
+                SetWindowTextW(GuiData->hWindow, WindowTitle);
                 ConsoleFreeHeap(WindowTitle);
             }
 
@@ -1026,24 +965,12 @@ UpdateSelection(PGUI_CONSOLE_DATA GuiData,
         ConioUnpause(Console, PAUSED_FROM_SELECTION);
 
         /* Restore the console title */
-        SetWindowText(GuiData->hWindow, Console->Title.Buffer);
+        SetWindowTextW(GuiData->hWindow, Console->Title.Buffer);
     }
 
     DeleteObject(oldRgn);
 }
 
-
-VOID
-GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
-                       PGUI_CONSOLE_DATA GuiData,
-                       PRECT rcView,
-                       PRECT rcFramebuffer);
-VOID
-GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
-                       PGUI_CONSOLE_DATA GuiData,
-                       PRECT rcView,
-                       PRECT rcFramebuffer);
-
 static VOID
 OnPaint(PGUI_CONSOLE_DATA GuiData)
 {
@@ -1051,6 +978,9 @@ OnPaint(PGUI_CONSOLE_DATA GuiData)
     PAINTSTRUCT ps;
     RECT rcPaint;
 
+    /* Do nothing if the window is hidden */
+    if (!GuiData->IsWindowVisible) return;
+
     BeginPaint(GuiData->hWindow, &ps);
     if (ps.hdc != NULL &&
         ps.rcPaint.left < ps.rcPaint.right &&
@@ -1099,6 +1029,9 @@ OnPaletteChanged(PGUI_CONSOLE_DATA GuiData)
 {
     PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
 
+    /* Do nothing if the window is hidden */
+    if (!GuiData->IsWindowVisible) return;
+
     // See WM_PALETTECHANGED message
     // if ((HWND)wParam == hWnd) break;
 
@@ -1144,7 +1077,7 @@ OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
     PCONSRV_CONSOLE Console = GuiData->Console;
     PCONSOLE_SCREEN_BUFFER ActiveBuffer;
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return;
 
     ActiveBuffer = GuiData->ActiveBuffer;
 
@@ -1161,7 +1094,7 @@ OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
             goto Quit;
         }
         else if ( VirtualKeyCode == VK_ESCAPE ||
-                 (VirtualKeyCode == 'C' && (GetKeyState(VK_CONTROL) & 0x8000)) )
+                 (VirtualKeyCode == 'C' && (GetKeyState(VK_CONTROL) & KEY_PRESSED)) )
         {
             /* Cancel selection if ESC or Ctrl-C are pressed */
             UpdateSelection(GuiData, NULL, NULL);
@@ -1172,7 +1105,7 @@ OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
         {
             /* Keyboard selection mode */
             BOOL Interpreted = FALSE;
-            BOOL MajPressed  = !!(GetKeyState(VK_SHIFT) & 0x8000);
+            BOOL MajPressed  = !!(GetKeyState(VK_SHIFT) & KEY_PRESSED);
 
             switch (VirtualKeyCode)
             {
@@ -1309,9 +1242,12 @@ OnTimer(PGUI_CONSOLE_DATA GuiData)
     PCONSRV_CONSOLE Console = GuiData->Console;
     PCONSOLE_SCREEN_BUFFER Buff;
 
+    /* Do nothing if the window is hidden */
+    if (!GuiData->IsWindowVisible) return;
+
     SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL);
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return;
 
     Buff = GuiData->ActiveBuffer;
 
@@ -1323,15 +1259,15 @@ OnTimer(PGUI_CONSOLE_DATA GuiData)
         if ((GuiData->OldCursor.x != Buff->CursorPosition.X) ||
             (GuiData->OldCursor.y != Buff->CursorPosition.Y))
         {
-            SCROLLINFO xScroll;
+            SCROLLINFO sInfo;
             int OldScrollX = -1, OldScrollY = -1;
             int NewScrollX = -1, NewScrollY = -1;
 
-            xScroll.cbSize = sizeof(SCROLLINFO);
-            xScroll.fMask = SIF_POS;
+            sInfo.cbSize = sizeof(sInfo);
+            sInfo.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 (GetScrollInfo(GuiData->hWindow, SB_HORZ, &sInfo)) OldScrollX = sInfo.nPos;
+            if (GetScrollInfo(GuiData->hWindow, SB_VERT, &sInfo)) OldScrollY = sInfo.nPos;
 
             // If we successfully got the info for the horizontal scrollbar
             if (OldScrollX >= 0)
@@ -1386,13 +1322,13 @@ OnTimer(PGUI_CONSOLE_DATA GuiData)
                                SW_INVALIDATE);
                 if (NewScrollX >= 0)
                 {
-                    xScroll.nPos = NewScrollX;
-                    SetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll, TRUE);
+                    sInfo.nPos = NewScrollX;
+                    SetScrollInfo(GuiData->hWindow, SB_HORZ, &sInfo, TRUE);
                 }
                 if (NewScrollY >= 0)
                 {
-                    xScroll.nPos = NewScrollY;
-                    SetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll, TRUE);
+                    sInfo.nPos = NewScrollY;
+                    SetScrollInfo(GuiData->hWindow, SB_VERT, &sInfo, TRUE);
                 }
                 UpdateWindow(GuiData->hWindow);
                 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
@@ -1413,7 +1349,7 @@ OnClose(PGUI_CONSOLE_DATA GuiData)
 {
     PCONSRV_CONSOLE Console = GuiData->Console;
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE))
         return TRUE;
 
     // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
@@ -1434,11 +1370,17 @@ OnNcDestroy(HWND hWnd)
 {
     PGUI_CONSOLE_DATA GuiData = GuiGetGuiData(hWnd);
 
-    KillTimer(hWnd, CONGUI_UPDATE_TIMER);
+    /* Free the GuiData registration */
+    SetWindowLongPtrW(hWnd, GWLP_USERDATA, (DWORD_PTR)NULL);
+
+    /* Reset the system menu back to default and destroy the previous menu */
     GetSystemMenu(hWnd, TRUE);
 
     if (GuiData)
     {
+        if (GuiData->IsWindowVisible)
+            KillTimer(hWnd, CONGUI_UPDATE_TIMER);
+
         /* Free the terminal framebuffer */
         if (GuiData->hMemDC ) DeleteDC(GuiData->hMemDC);
         if (GuiData->hBitmap) DeleteObject(GuiData->hBitmap);
@@ -1446,12 +1388,117 @@ OnNcDestroy(HWND hWnd)
         DeleteFonts(GuiData);
     }
 
-    /* Free the GuiData registration */
-    SetWindowLongPtrW(hWnd, GWLP_USERDATA, (DWORD_PTR)NULL);
-
     return DefWindowProcW(hWnd, WM_NCDESTROY, 0, 0);
 }
 
+static VOID
+OnScroll(PGUI_CONSOLE_DATA GuiData, INT nBar, WORD sbCode)
+{
+    PCONSRV_CONSOLE Console = GuiData->Console;
+    PCONSOLE_SCREEN_BUFFER Buff;
+    SCROLLINFO sInfo;
+    INT oldPos, Maximum;
+    PSHORT pOriginXY;
+
+    ASSERT(nBar == SB_HORZ || nBar == SB_VERT);
+
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return;
+
+    Buff = GuiData->ActiveBuffer;
+
+    if (nBar == SB_HORZ)
+    {
+        Maximum = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
+        pOriginXY = &Buff->ViewOrigin.X;
+    }
+    else // if (nBar == SB_VERT)
+    {
+        Maximum = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
+        pOriginXY = &Buff->ViewOrigin.Y;
+    }
+
+    /* Set scrollbar sizes */
+    sInfo.cbSize = sizeof(sInfo);
+    sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
+
+    if (!GetScrollInfo(GuiData->hWindow, nBar, &sInfo)) goto Quit;
+
+    oldPos = sInfo.nPos;
+
+    switch (sbCode)
+    {
+        case SB_LINEUP:   // SB_LINELEFT:
+            sInfo.nPos--;
+            break;
+
+        case SB_LINEDOWN: // SB_LINERIGHT:
+            sInfo.nPos++;
+            break;
+
+        case SB_PAGEUP:   // SB_PAGELEFT:
+            sInfo.nPos -= sInfo.nPage;
+            break;
+
+        case SB_PAGEDOWN: // SB_PAGERIGHT:
+            sInfo.nPos += sInfo.nPage;
+            break;
+
+        case SB_THUMBTRACK:
+            sInfo.nPos = sInfo.nTrackPos;
+            ConioPause(Console, PAUSED_FROM_SCROLLBAR);
+            break;
+
+        case SB_THUMBPOSITION:
+            sInfo.nPos = sInfo.nTrackPos;
+            ConioUnpause(Console, PAUSED_FROM_SCROLLBAR);
+            break;
+
+        case SB_TOP:    // SB_LEFT:
+            sInfo.nPos = sInfo.nMin;
+            break;
+
+        case SB_BOTTOM: // SB_RIGHT:
+            sInfo.nPos = sInfo.nMax;
+            break;
+
+        default:
+            break;
+    }
+
+    sInfo.nPos = min(max(sInfo.nPos, 0), Maximum);
+
+    if (oldPos != sInfo.nPos)
+    {
+        USHORT OldX = Buff->ViewOrigin.X;
+        USHORT OldY = Buff->ViewOrigin.Y;
+        UINT   WidthUnit, HeightUnit;
+
+        /* We now modify Buff->ViewOrigin */
+        *pOriginXY = sInfo.nPos;
+
+        GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
+
+        ScrollWindowEx(GuiData->hWindow,
+                       (OldX - Buff->ViewOrigin.X) * WidthUnit ,
+                       (OldY - Buff->ViewOrigin.Y) * HeightUnit,
+                       NULL,
+                       NULL,
+                       NULL,
+                       NULL,
+                       SW_INVALIDATE);
+
+        sInfo.fMask = SIF_POS;
+        SetScrollInfo(GuiData->hWindow, nBar, &sInfo, TRUE);
+
+        UpdateWindow(GuiData->hWindow);
+        // InvalidateRect(GuiData->hWindow, NULL, FALSE);
+    }
+
+Quit:
+    LeaveCriticalSection(&Console->Lock);
+    return;
+}
+
 static COORD
 PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
 {
@@ -1481,22 +1528,38 @@ PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
 static LRESULT
 OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
 {
-    BOOL Err = FALSE;
+    BOOL DoDefault = FALSE;
     PCONSRV_CONSOLE Console = GuiData->Console;
 
-    // FIXME: It's here that we need to check whether we has focus or not
-    // and whether we are in edit mode or not, to know if we need to deal
-    // with the mouse, or not.
+    /*
+     * HACK FOR CORE-8394 (Part 2):
+     *
+     * Check whether we should ignore the next mouse move event.
+     * In either case we reset the HACK flag.
+     *
+     * See Part 1 of this hack below.
+     */
+    if (GuiData->HackCORE8394IgnoreNextMove && msg == WM_MOUSEMOVE)
+    {
+        GuiData->HackCORE8394IgnoreNextMove = FALSE;
+        goto Quit;
+    }
+    GuiData->HackCORE8394IgnoreNextMove = FALSE;
+
+    // FIXME: It's here that we need to check whether we have focus or not
+    // and whether we are or not in edit mode, in order to know if we need
+    // to deal with the mouse.
 
     if (GuiData->IgnoreNextMouseSignal)
     {
         if (msg != WM_LBUTTONDOWN &&
             msg != WM_MBUTTONDOWN &&
-            msg != WM_RBUTTONDOWN)
+            msg != WM_RBUTTONDOWN &&
+            msg != WM_XBUTTONDOWN)
         {
             /*
              * If this mouse signal is not a button-down action
-             * then it is the last signal being ignored.
+             * then this is the last one being ignored.
              */
             GuiData->IgnoreNextMouseSignal = FALSE;
         }
@@ -1506,14 +1569,14 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
              * This mouse signal is a button-down action.
              * Ignore it and perform default action.
              */
-            Err = TRUE;
+            DoDefault = TRUE;
         }
         goto Quit;
     }
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE))
     {
-        Err = TRUE;
+        DoDefault = TRUE;
         goto Quit;
     }
 
@@ -1524,16 +1587,32 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
         {
             case WM_LBUTTONDOWN:
             {
-                /* Clear the old selection */
-                GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
+                /* Check for selection state */
+                if ( (GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
+                     (GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION)       &&
+                     (GetKeyState(VK_SHIFT) & KEY_PRESSED) )
+                {
+                    /*
+                     * A mouse selection is currently in progress and the user
+                     * has pressed the SHIFT key and clicked somewhere, update
+                     * the selection.
+                     */
+                    GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
+                    UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
+                }
+                else
+                {
+                    /* Clear the old selection */
+                    GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
 
-                /* Restart a new selection */
-                GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
-                SetCapture(GuiData->hWindow);
-                GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
-                UpdateSelection(GuiData,
-                                &GuiData->dwSelectionCursor,
-                                &GuiData->dwSelectionCursor);
+                    /* Restart a new selection */
+                    GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
+                    SetCapture(GuiData->hWindow);
+                    GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
+                    UpdateSelection(GuiData,
+                                    &GuiData->dwSelectionCursor,
+                                    &GuiData->dwSelectionCursor);
+                }
 
                 break;
             }
@@ -1591,6 +1670,7 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
 
                     /* Ignore the next mouse move signal */
                     GuiData->IgnoreNextMouseSignal = TRUE;
+#undef IS_WORD_SEP
                 }
 
                 break;
@@ -1615,18 +1695,16 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
 
             case WM_MOUSEMOVE:
             {
-                if (!(wParam & MK_LBUTTON)) break;
+                if (!(GET_KEYSTATE_WPARAM(wParam) & MK_LBUTTON)) break;
                 if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
 
-                // TODO: Scroll buffer to bring SelectionCursor into view
                 GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
                 UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
-
                 break;
             }
 
             default:
-                Err = FALSE; // TRUE;
+                DoDefault = TRUE; // FALSE;
                 break;
         }
     }
@@ -1658,6 +1736,26 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
                 dwEventFlags  = 0;
                 break;
 
+            case WM_XBUTTONDOWN:
+            {
+                /* Get which X-button was pressed */
+                WORD wButton = GET_XBUTTON_WPARAM(wParam);
+
+                /* Check for X-button validity */
+                if (wButton & ~(XBUTTON1 | XBUTTON2))
+                {
+                    DPRINT1("X-button 0x%04x invalid\n", wButton);
+                    DoDefault = TRUE;
+                    break;
+                }
+
+                SetCapture(GuiData->hWindow);
+                dwButtonState = (wButton == XBUTTON1 ? FROM_LEFT_3RD_BUTTON_PRESSED
+                                                     : FROM_LEFT_4TH_BUTTON_PRESSED);
+                dwEventFlags  = 0;
+                break;
+            }
+
             case WM_LBUTTONUP:
                 ReleaseCapture();
                 dwButtonState = 0;
@@ -1676,6 +1774,24 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
                 dwEventFlags  = 0;
                 break;
 
+            case WM_XBUTTONUP:
+            {
+                /* Get which X-button was released */
+                WORD wButton = GET_XBUTTON_WPARAM(wParam);
+
+                /* Check for X-button validity */
+                if (wButton & ~(XBUTTON1 | XBUTTON2))
+                {
+                    DPRINT1("X-button 0x%04x invalid\n", wButton);
+                    /* Ok, just release the button anyway... */
+                }
+
+                ReleaseCapture();
+                dwButtonState = 0;
+                dwEventFlags  = 0;
+                break;
+            }
+
             case WM_LBUTTONDBLCLK:
                 dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
                 dwEventFlags  = DOUBLE_CLICK;
@@ -1691,6 +1807,25 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
                 dwEventFlags  = DOUBLE_CLICK;
                 break;
 
+            case WM_XBUTTONDBLCLK:
+            {
+                /* Get which X-button was double-clicked */
+                WORD wButton = GET_XBUTTON_WPARAM(wParam);
+
+                /* Check for X-button validity */
+                if (wButton & ~(XBUTTON1 | XBUTTON2))
+                {
+                    DPRINT1("X-button 0x%04x invalid\n", wButton);
+                    DoDefault = TRUE;
+                    break;
+                }
+
+                dwButtonState = (wButton == XBUTTON1 ? FROM_LEFT_3RD_BUTTON_PRESSED
+                                                     : FROM_LEFT_4TH_BUTTON_PRESSED);
+                dwEventFlags  = DOUBLE_CLICK;
+                break;
+            }
+
             case WM_MOUSEMOVE:
                 dwButtonState = 0;
                 dwEventFlags  = MOUSE_MOVED;
@@ -1707,25 +1842,35 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
                 break;
 
             default:
-                Err = TRUE;
+                DoDefault = TRUE;
                 break;
         }
 
         /*
-         * HACK FOR CORE-8394: Ignore the next mouse move signal
-         * just after mouse down click actions.
+         * HACK FOR CORE-8394 (Part 1):
+         *
+         * It appears that depending on which VM ReactOS runs, the next mouse
+         * signal coming after a button-down action can be a mouse-move (e.g.
+         * on VBox, whereas on QEMU it is not the case). However it is NOT a
+         * rule, so that we cannot use the IgnoreNextMouseSignal flag to just
+         * "ignore" the next mouse event, thinking it would always be a mouse-
+         * move signal.
+         *
+         * To work around this problem (that should really be fixed in Win32k),
+         * we use a second flag to ignore this possible next mouse move signal.
          */
         switch (msg)
         {
             case WM_LBUTTONDOWN:
             case WM_MBUTTONDOWN:
             case WM_RBUTTONDOWN:
-                GuiData->IgnoreNextMouseSignal = TRUE;
+            case WM_XBUTTONDOWN:
+                GuiData->HackCORE8394IgnoreNextMove = TRUE;
             default:
                 break;
         }
 
-        if (!Err)
+        if (!DoDefault)
         {
             if (wKeyState & MK_LBUTTON)
                 dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
@@ -1733,27 +1878,32 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
                 dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
             if (wKeyState & MK_RBUTTON)
                 dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
+            if (wKeyState & MK_XBUTTON1)
+                dwButtonState |= FROM_LEFT_3RD_BUTTON_PRESSED;
+            if (wKeyState & MK_XBUTTON2)
+                dwButtonState |= FROM_LEFT_4TH_BUTTON_PRESSED;
 
-            if (GetKeyState(VK_RMENU) & 0x8000)
+            if (GetKeyState(VK_RMENU) & KEY_PRESSED)
                 dwControlKeyState |= RIGHT_ALT_PRESSED;
-            if (GetKeyState(VK_LMENU) & 0x8000)
+            if (GetKeyState(VK_LMENU) & KEY_PRESSED)
                 dwControlKeyState |= LEFT_ALT_PRESSED;
-            if (GetKeyState(VK_RCONTROL) & 0x8000)
+            if (GetKeyState(VK_RCONTROL) & KEY_PRESSED)
                 dwControlKeyState |= RIGHT_CTRL_PRESSED;
-            if (GetKeyState(VK_LCONTROL) & 0x8000)
+            if (GetKeyState(VK_LCONTROL) & KEY_PRESSED)
                 dwControlKeyState |= LEFT_CTRL_PRESSED;
-            if (GetKeyState(VK_SHIFT) & 0x8000)
+            if (GetKeyState(VK_SHIFT) & KEY_PRESSED)
                 dwControlKeyState |= SHIFT_PRESSED;
-            if (GetKeyState(VK_NUMLOCK) & 0x0001)
+            if (GetKeyState(VK_NUMLOCK) & KEY_TOGGLED)
                 dwControlKeyState |= NUMLOCK_ON;
-            if (GetKeyState(VK_SCROLL) & 0x0001)
+            if (GetKeyState(VK_SCROLL) & KEY_TOGGLED)
                 dwControlKeyState |= SCROLLLOCK_ON;
-            if (GetKeyState(VK_CAPITAL) & 0x0001)
+            if (GetKeyState(VK_CAPITAL) & KEY_TOGGLED)
                 dwControlKeyState |= CAPSLOCK_ON;
             /* See WM_CHAR MSDN documentation for instance */
             if (lParam & 0x01000000)
                 dwControlKeyState |= ENHANCED_KEY;
 
+            /* Send a mouse event */
             er.EventType = MOUSE_EVENT;
             er.Event.MouseEvent.dwMousePosition   = PointToCoord(GuiData, lParam);
             er.Event.MouseEvent.dwButtonState     = dwButtonState;
@@ -1765,29 +1915,49 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
     }
     else
     {
-        Err = TRUE;
+        DoDefault = TRUE;
     }
 
     LeaveCriticalSection(&Console->Lock);
 
 Quit:
-    if (Err)
-        return DefWindowProcW(GuiData->hWindow, msg, wParam, lParam);
-    else
+    if (!DoDefault)
         return 0;
+
+    if (msg == WM_MOUSEWHEEL || msg == WM_MOUSEHWHEEL)
+    {
+        INT   nBar;
+        WORD  sbCode;
+        // WORD  wKeyState = GET_KEYSTATE_WPARAM(wParam);
+        SHORT wDelta    = GET_WHEEL_DELTA_WPARAM(wParam);
+
+        if (msg == WM_MOUSEWHEEL)
+            nBar = SB_VERT;
+        else // if (msg == WM_MOUSEHWHEEL)
+            nBar = SB_HORZ;
+
+        // NOTE: We currently do not support zooming...
+        // if (wKeyState & MK_CONTROL)
+
+        // FIXME: For some reason our win32k does not set the key states
+        // when sending WM_MOUSEWHEEL or WM_MOUSEHWHEEL ...
+        // if (wKeyState & MK_SHIFT)
+        if (GetKeyState(VK_SHIFT) & KEY_PRESSED)
+            sbCode = (wDelta >= 0 ? SB_PAGEUP : SB_PAGEDOWN);
+        else
+            sbCode = (wDelta >= 0 ? SB_LINEUP : SB_LINEDOWN);
+
+        OnScroll(GuiData, nBar, sbCode);
+    }
+
+    return DefWindowProcW(GuiData->hWindow, msg, wParam, lParam);
 }
 
-VOID
-GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
-                          PGUI_CONSOLE_DATA GuiData);
-VOID
-GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
-                          PGUI_CONSOLE_DATA GuiData);
 
 static VOID
 Copy(PGUI_CONSOLE_DATA GuiData)
 {
-    if (OpenClipboard(GuiData->hWindow) == TRUE)
+    if (OpenClipboard(GuiData->hWindow))
     {
         PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
 
@@ -1807,17 +1977,10 @@ Copy(PGUI_CONSOLE_DATA GuiData)
     UpdateSelection(GuiData, NULL, NULL);
 }
 
-VOID
-GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
-                         PGUI_CONSOLE_DATA GuiData);
-VOID
-GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
-                         PGUI_CONSOLE_DATA GuiData);
-
 static VOID
 Paste(PGUI_CONSOLE_DATA GuiData)
 {
-    if (OpenClipboard(GuiData->hWindow) == TRUE)
+    if (OpenClipboard(GuiData->hWindow))
     {
         PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
 
@@ -1842,7 +2005,7 @@ OnGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
     DWORD windx, windy;
     UINT  WidthUnit, HeightUnit;
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return;
 
     ActiveBuffer = GuiData->ActiveBuffer;
 
@@ -1857,8 +2020,8 @@ OnGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
     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 (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
+    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;
@@ -1871,9 +2034,12 @@ OnSize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
 {
     PCONSRV_CONSOLE Console = GuiData->Console;
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+    /* Do nothing if the window is hidden */
+    if (!GuiData->IsWindowVisible) return;
 
-    if ((GuiData->WindowSizeLock == FALSE) &&
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return;
+
+    if (!GuiData->WindowSizeLock &&
         (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED))
     {
         PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer;
@@ -1887,38 +2053,38 @@ OnSize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
         windx = LOWORD(lParam);
         windy = HIWORD(lParam);
 
-        // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
-        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
+        /* Compensate for existing scroll bars (because lParam values do not accommodate scroll bar) */
+        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 / (int)WidthUnit ;
         chary = windy / (int)HeightUnit;
 
-        // Character alignment (round size up or down)
+        /* Character alignment (round size up or down) */
         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
+        /* Compensate for added scroll bars in window */
+        if (charx < (DWORD)Buff->ScreenBufferSize.X) windy -= GetSystemMetrics(SM_CYHSCROLL); // Window will have a horizontal scroll bar
+        if (chary < (DWORD)Buff->ScreenBufferSize.Y) windx -= GetSystemMetrics(SM_CXVSCROLL); // Window will have a vertical scroll bar
 
         charx = windx / (int)WidthUnit ;
         chary = windy / (int)HeightUnit;
 
-        // Character alignment (round size up or down)
+        /* Character alignment (round size up or down) */
         if ((windx % WidthUnit ) >= (WidthUnit  / 2)) ++charx;
         if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary;
 
-        // Resize window
+        /* Resize window */
         if ((charx != Buff->ViewSize.X) || (chary != Buff->ViewSize.Y))
         {
-            Buff->ViewSize.X = (charx <= Buff->ScreenBufferSize.X) ? charx : Buff->ScreenBufferSize.X;
-            Buff->ViewSize.Y = (chary <= Buff->ScreenBufferSize.Y) ? chary : Buff->ScreenBufferSize.Y;
+            Buff->ViewSize.X = (charx <= (DWORD)Buff->ScreenBufferSize.X) ? charx : Buff->ScreenBufferSize.X;
+            Buff->ViewSize.Y = (chary <= (DWORD)Buff->ScreenBufferSize.Y) ? chary : Buff->ScreenBufferSize.Y;
         }
 
         ResizeConWnd(GuiData, WidthUnit, HeightUnit);
 
-        // Adjust the start of the visible area if we are attempting to show nonexistent areas
+        /* 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;
         if ((Buff->ScreenBufferSize.Y - Buff->ViewOrigin.Y) < Buff->ViewSize.Y) Buff->ViewOrigin.Y = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
         InvalidateRect(GuiData->hWindow, NULL, TRUE);
@@ -1943,6 +2109,30 @@ OnMove(PGUI_CONSOLE_DATA GuiData)
     GuiData->GuiInfo.WindowOrigin.y = rcWnd.top;
 }
 
+static VOID
+OnDropFiles(PCONSRV_CONSOLE Console, HDROP hDrop)
+{
+    LPWSTR pszPath;
+    WCHAR szPath[MAX_PATH + 2];
+
+    szPath[0] = L'"';
+
+    DragQueryFileW(hDrop, 0, &szPath[1], ARRAYSIZE(szPath) - 1);
+    DragFinish(hDrop);
+
+    if (wcschr(&szPath[1], L' ') != NULL)
+    {
+        StringCchCatW(szPath, ARRAYSIZE(szPath), L"\"");
+        pszPath = szPath;
+    }
+    else
+    {
+        pszPath = &szPath[1];
+    }
+
+    PasteText(Console, pszPath, wcslen(pszPath));
+}
+
 /*
 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
 
@@ -1971,115 +2161,6 @@ GuiConsoleHandleScrollbarMenu(VOID)
 }
 */
 
-static LRESULT
-OnScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
-{
-    PCONSRV_CONSOLE Console = GuiData->Console;
-    PCONSOLE_SCREEN_BUFFER Buff;
-    SCROLLINFO sInfo;
-    int fnBar;
-    int old_pos, Maximum;
-    PSHORT pShowXY;
-
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return 0;
-
-    Buff = GuiData->ActiveBuffer;
-
-    if (uMsg == WM_HSCROLL)
-    {
-        fnBar = SB_HORZ;
-        Maximum = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
-        pShowXY = &Buff->ViewOrigin.X;
-    }
-    else
-    {
-        fnBar = SB_VERT;
-        Maximum = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
-        pShowXY = &Buff->ViewOrigin.Y;
-    }
-
-    /* set scrollbar sizes */
-    sInfo.cbSize = sizeof(SCROLLINFO);
-    sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
-
-    if (!GetScrollInfo(GuiData->hWindow, fnBar, &sInfo)) goto Quit;
-
-    old_pos = sInfo.nPos;
-
-    switch (LOWORD(wParam))
-    {
-        case SB_LINELEFT:
-            sInfo.nPos -= 1;
-            break;
-
-        case SB_LINERIGHT:
-            sInfo.nPos += 1;
-            break;
-
-        case SB_PAGELEFT:
-            sInfo.nPos -= sInfo.nPage;
-            break;
-
-        case SB_PAGERIGHT:
-            sInfo.nPos += sInfo.nPage;
-            break;
-
-        case SB_THUMBTRACK:
-            sInfo.nPos = sInfo.nTrackPos;
-            ConioPause(Console, PAUSED_FROM_SCROLLBAR);
-            break;
-
-        case SB_THUMBPOSITION:
-            ConioUnpause(Console, PAUSED_FROM_SCROLLBAR);
-            break;
-
-        case SB_TOP:
-            sInfo.nPos = sInfo.nMin;
-            break;
-
-        case SB_BOTTOM:
-            sInfo.nPos = sInfo.nMax;
-            break;
-
-        default:
-            break;
-    }
-
-    sInfo.nPos = max(sInfo.nPos, 0);
-    sInfo.nPos = min(sInfo.nPos, Maximum);
-
-    if (old_pos != sInfo.nPos)
-    {
-        USHORT OldX = Buff->ViewOrigin.X;
-        USHORT OldY = Buff->ViewOrigin.Y;
-        UINT   WidthUnit, HeightUnit;
-
-        *pShowXY = sInfo.nPos;
-
-        GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
-
-        ScrollWindowEx(GuiData->hWindow,
-                       (OldX - Buff->ViewOrigin.X) * WidthUnit ,
-                       (OldY - Buff->ViewOrigin.Y) * HeightUnit,
-                       NULL,
-                       NULL,
-                       NULL,
-                       NULL,
-                       SW_INVALIDATE);
-
-        sInfo.fMask = SIF_POS;
-        SetScrollInfo(GuiData->hWindow, fnBar, &sInfo, TRUE);
-
-        UpdateWindow(GuiData->hWindow);
-        // InvalidateRect(GuiData->hWindow, NULL, FALSE);
-    }
-
-Quit:
-    LeaveCriticalSection(&Console->Lock);
-    return 0;
-}
-
-
 static LRESULT CALLBACK
 ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
@@ -2194,6 +2275,9 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
         case WM_SETCURSOR:
         {
+            /* Do nothing if the window is hidden */
+            if (!GuiData->IsWindowVisible) goto Default;
+
             /*
              * The message was sent because we are manually triggering a change.
              * Check whether the mouse is indeed present on this console window
@@ -2243,12 +2327,15 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
         case WM_LBUTTONDOWN:
         case WM_MBUTTONDOWN:
         case WM_RBUTTONDOWN:
+        case WM_XBUTTONDOWN:
         case WM_LBUTTONUP:
         case WM_MBUTTONUP:
         case WM_RBUTTONUP:
+        case WM_XBUTTONUP:
         case WM_LBUTTONDBLCLK:
         case WM_MBUTTONDBLCLK:
         case WM_RBUTTONDBLCLK:
+        case WM_XBUTTONDBLCLK:
         case WM_MOUSEMOVE:
         case WM_MOUSEWHEEL:
         case WM_MOUSEHWHEEL:
@@ -2258,14 +2345,18 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
         }
 
         case WM_HSCROLL:
+            OnScroll(GuiData, SB_HORZ, LOWORD(wParam));
+            break;
+
         case WM_VSCROLL:
-        {
-            Result = OnScroll(GuiData, msg, wParam);
+            OnScroll(GuiData, SB_VERT, LOWORD(wParam));
             break;
-        }
 
         case WM_CONTEXTMENU:
         {
+            /* Do nothing if the window is hidden */
+            if (!GuiData->IsWindowVisible) break;
+
             if (DefWindowProcW(hWnd /*GuiData->hWindow*/, WM_NCHITTEST, 0, lParam) == HTCLIENT)
             {
                 HMENU hMenu = CreatePopupMenu();
@@ -2328,6 +2419,10 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
             break;
         }
 
+        case WM_DROPFILES:
+            OnDropFiles(Console, (HDROP)wParam);
+            break;
+
         case WM_SETFOCUS:
         case WM_KILLFOCUS:
             OnFocus(GuiData, (msg == WM_SETFOCUS));
@@ -2394,6 +2489,9 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
             DWORD Width, Height;
             UINT  WidthUnit, HeightUnit;
 
+            /* Do nothing if the window is hidden */
+            if (!GuiData->IsWindowVisible) break;
+
             GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
 
             Width  = Buff->ScreenBufferSize.X * WidthUnit ;
@@ -2417,12 +2515,6 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
             break;
         }
 
-        case PM_APPLY_CONSOLE_INFO:
-        {
-            GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
-            break;
-        }
-
         /*
          * Undocumented message sent by Windows' console.dll for applying console info.
          * See http://www.catch22.net/sites/default/source/files/setconsoleinfo.c
@@ -2431,19 +2523,18 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
          */
         case WM_SETCONSOLEINFO:
         {
-            DPRINT1("WM_SETCONSOLEINFO message\n");
-            GuiApplyWindowsConsoleSettings(GuiData, (HANDLE)wParam);
+            GuiApplyUserSettings(GuiData, (HANDLE)wParam);
             break;
         }
 
         case PM_CONSOLE_BEEP:
-            DPRINT1("Beep !!\n");
+            DPRINT1("Beep\n");
             Beep(800, 200);
             break;
 
-        // case PM_CONSOLE_SET_TITLE:
-            // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
-            // break;
+         case PM_CONSOLE_SET_TITLE:
+            SetWindowTextW(GuiData->hWindow, GuiData->Console->Title.Buffer);
+            break;
 
         default: Default:
             Result = DefWindowProcW(hWnd, msg, wParam, lParam);