[CONSRV]: GUI frontend: support the 3rd and 4th mouse button.
[reactos.git] / reactos / win32ss / user / winsrv / consrv / frontends / gui / conwnd.c
index acc83a4..e9b31c1 100644 (file)
@@ -48,7 +48,7 @@ SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData)
     PCONSOLE_PROCESS_DATA ProcessData;
     CLIENT_ID ConsoleLeaderCID;
 
-    ProcessData = ConDrvGetConsoleLeaderProcess(GuiData->Console);
+    ProcessData = ConSrvGetConsoleLeaderProcess(GuiData->Console);
     ConsoleLeaderCID = ProcessData->Process->ClientId;
     SetWindowLongPtrW(GuiData->hWindow, GWLP_CONSOLE_LEADER_PID,
                       (LONG_PTR)(ConsoleLeaderCID.UniqueProcess));
@@ -212,7 +212,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)
                 {
@@ -250,7 +250,8 @@ AppendMenuItems(HMENU hMenu,
     } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
 }
 
-static VOID
+//static
+VOID
 CreateSysMenu(HWND hWnd)
 {
     MENUITEMINFOW mii;
@@ -260,7 +261,7 @@ CreateSysMenu(HWND hWnd)
     if (hMenu != NULL)
     {
         mii.cbSize = sizeof(mii);
-        mii.fMask = MIIM_STRING;   
+        mii.fMask = MIIM_STRING;
         mii.dwTypeData = szMenuStringBack;
         mii.cch = sizeof(szMenuStringBack)/sizeof(WCHAR);
 
@@ -281,13 +282,13 @@ CreateSysMenu(HWND hWnd)
 }
 
 static VOID
-SendMenuEvent(PCONSOLE Console, UINT CmdId)
+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;
 
     er.EventType = MENU_EVENT;
     er.Event.MenuEvent.dwCommandId = CmdId;
@@ -365,7 +366,7 @@ static LRESULT
 OnCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
 {
     LRESULT Ret = TRUE;
-    PCONSOLE Console = GuiData->Console;
+    PCONSRV_CONSOLE Console = GuiData->Console;
 
     /*
      * In case the selected menu item belongs to the user-reserved menu id range,
@@ -485,88 +486,187 @@ ResizeConWnd(PGUI_CONSOLE_DATA GuiData, DWORD WidthUnit, DWORD HeightUnit)
     // to: InvalidateRect(GuiData->hWindow, NULL, TRUE);
 }
 
-static BOOL
-OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
-{
-    PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Create->lpCreateParams;
-    PCONSOLE Console;
-    HDC hDC;
-    HFONT OldFont;
-    TEXTMETRICW Metrics;
-    SIZE CharSize;
 
-    if (NULL == GuiData)
+VOID
+DeleteFonts(PGUI_CONSOLE_DATA GuiData)
+{
+    ULONG i;
+    for (i = 0; i < ARRAYSIZE(GuiData->Font); ++i)
     {
-        DPRINT1("GuiConsoleNcCreate: No GUI data\n");
-        return FALSE;
+        if (GuiData->Font[i] != NULL) DeleteObject(GuiData->Font[i]);
+        GuiData->Font[i] = NULL;
     }
+}
 
-    Console = GuiData->Console;
+static HFONT
+CreateDerivedFont(HFONT OrgFont,
+                  // COORD   FontSize,
+                  ULONG   FontWeight,
+                  // BOOLEAN bItalic,
+                  BOOLEAN bUnderline,
+                  BOOLEAN bStrikeOut)
+{
+    LOGFONT lf;
 
-    GuiData->hWindow = hWnd;
+    /* Initialize the LOGFONT structure */
+    RtlZeroMemory(&lf, sizeof(lf));
+
+    /* Retrieve the details of the current font */
+    if (GetObject(OrgFont, sizeof(lf), &lf) == 0)
+        return NULL;
+
+    /* Change the font attributes */
+    // lf.lfHeight = FontSize.Y;
+    // lf.lfWidth  = FontSize.X;
+    lf.lfWeight = FontWeight;
+    // lf.lfItalic = bItalic;
+    lf.lfUnderline = bUnderline;
+    lf.lfStrikeOut = bStrikeOut;
+
+    /* Build a new font */
+    return CreateFontIndirect(&lf);
+}
+
+BOOL
+InitFonts(PGUI_CONSOLE_DATA GuiData,
+          LPWSTR FaceName, // Points to a WCHAR array of LF_FACESIZE elements.
+          ULONG  FontFamily,
+          COORD  FontSize,
+          ULONG  FontWeight)
+{
+    HDC hDC;
+    HFONT OldFont, NewFont;
+    TEXTMETRICW Metrics;
+    SIZE CharSize;
 
-    GuiData->Font = CreateFontW(LOWORD(GuiData->GuiInfo.FontSize),
-                                0, // HIWORD(GuiData->GuiInfo.FontSize),
-                                0,
-                                TA_BASELINE,
-                                GuiData->GuiInfo.FontWeight,
-                                FALSE,
-                                FALSE,
-                                FALSE,
-                                OEM_CHARSET,
-                                OUT_DEFAULT_PRECIS,
-                                CLIP_DEFAULT_PRECIS,
-                                NONANTIALIASED_QUALITY,
-                                FIXED_PITCH | GuiData->GuiInfo.FontFamily /* FF_DONTCARE */,
-                                GuiData->GuiInfo.FaceName);
-
-    if (NULL == GuiData->Font)
-    {
-        DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
-        GuiData->hWindow = NULL;
-        SetEvent(GuiData->hGuiInitEvent);
-        return FALSE;
-    }
     hDC = GetDC(GuiData->hWindow);
-    if (NULL == hDC)
+
+    /*
+     * Initialize a new NORMAL font and get its metrics.
+     */
+
+    FontSize.Y = FontSize.Y > 0 ? -MulDiv(FontSize.Y, GetDeviceCaps(hDC, LOGPIXELSY), 72)
+                                : FontSize.Y;
+
+    NewFont = CreateFontW(FontSize.Y,
+                          FontSize.X,
+                          0,
+                          TA_BASELINE,
+                          FontWeight,
+                          FALSE,
+                          FALSE,
+                          FALSE,
+                          OEM_CHARSET,
+                          OUT_DEFAULT_PRECIS,
+                          CLIP_DEFAULT_PRECIS,
+                          DEFAULT_QUALITY,
+                          FIXED_PITCH | FontFamily,
+                          FaceName);
+    if (NewFont == NULL)
     {
-        DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
-        DeleteObject(GuiData->Font);
-        GuiData->hWindow = NULL;
-        SetEvent(GuiData->hGuiInitEvent);
+        DPRINT1("InitFonts: CreateFontW failed\n");
+        ReleaseDC(GuiData->hWindow, hDC);
         return FALSE;
     }
-    OldFont = SelectObject(hDC, GuiData->Font);
-    if (NULL == OldFont)
+
+    OldFont = SelectObject(hDC, NewFont);
+    if (OldFont == NULL)
     {
-        DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
+        DPRINT1("InitFonts: SelectObject failed\n");
         ReleaseDC(GuiData->hWindow, hDC);
-        DeleteObject(GuiData->Font);
-        GuiData->hWindow = NULL;
-        SetEvent(GuiData->hGuiInitEvent);
+        DeleteObject(NewFont);
         return FALSE;
     }
+
     if (!GetTextMetricsW(hDC, &Metrics))
     {
-        DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
+        DPRINT1("InitFonts: GetTextMetrics failed\n");
         SelectObject(hDC, OldFont);
         ReleaseDC(GuiData->hWindow, hDC);
-        DeleteObject(GuiData->Font);
-        GuiData->hWindow = NULL;
-        SetEvent(GuiData->hGuiInitEvent);
+        DeleteObject(NewFont);
         return FALSE;
     }
     GuiData->CharWidth  = Metrics.tmMaxCharWidth;
     GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
 
-    /* Measure real char width more precisely if possible. */
+    /* 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);
 
+    /*
+     * Initialization succeeded.
+     */
+    // Delete all the old fonts first.
+    DeleteFonts(GuiData);
+    GuiData->Font[FONT_NORMAL] = NewFont;
+
+    /*
+     * Now build the other fonts (bold, underlined, mixed).
+     */
+    GuiData->Font[FONT_BOLD] =
+        CreateDerivedFont(GuiData->Font[FONT_NORMAL],
+                          FontWeight < FW_BOLD ? FW_BOLD : FontWeight,
+                          FALSE,
+                          FALSE);
+    GuiData->Font[FONT_UNDERLINE] =
+        CreateDerivedFont(GuiData->Font[FONT_NORMAL],
+                          FontWeight,
+                          TRUE,
+                          FALSE);
+    GuiData->Font[FONT_BOLD | FONT_UNDERLINE] =
+        CreateDerivedFont(GuiData->Font[FONT_NORMAL],
+                          FontWeight < FW_BOLD ? FW_BOLD : FontWeight,
+                          TRUE,
+                          FALSE);
+
+    /*
+     * Save the settings.
+     */
+    if (FaceName != GuiData->GuiInfo.FaceName)
+    {
+        wcsncpy(GuiData->GuiInfo.FaceName, FaceName, LF_FACESIZE);
+        GuiData->GuiInfo.FaceName[LF_FACESIZE - 1] = UNICODE_NULL;
+    }
+    GuiData->GuiInfo.FontFamily = FontFamily;
+    GuiData->GuiInfo.FontSize   = FontSize;
+    GuiData->GuiInfo.FontWeight = FontWeight;
+
+    return TRUE;
+}
+
+
+static BOOL
+OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
+{
+    PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Create->lpCreateParams;
+    PCONSRV_CONSOLE Console;
+
+    if (NULL == GuiData)
+    {
+        DPRINT1("GuiConsoleNcCreate: No GUI data\n");
+        return FALSE;
+    }
+
+    Console = GuiData->Console;
+
+    GuiData->hWindow = hWnd;
+
+    /* Initialize the fonts */
+    if (!InitFonts(GuiData,
+                   GuiData->GuiInfo.FaceName,
+                   GuiData->GuiInfo.FontFamily,
+                   GuiData->GuiInfo.FontSize,
+                   GuiData->GuiInfo.FontWeight))
+    {
+        DPRINT1("GuiConsoleNcCreate: InitFonts failed\n");
+        GuiData->hWindow = NULL;
+        NtSetEvent(GuiData->hGuiInitEvent, NULL);
+        return FALSE;
+    }
+
     /* Initialize the terminal framebuffer */
     GuiData->hMemDC  = CreateCompatibleDC(NULL);
     GuiData->hBitmap = NULL;
@@ -586,11 +686,16 @@ OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
 
     SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)GuiData);
 
-    SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
-    CreateSysMenu(GuiData->hWindow);
+    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);
 
     return (BOOL)DefWindowProcW(GuiData->hWindow, WM_NCCREATE, 0, (LPARAM)Create);
 }
@@ -608,10 +713,9 @@ 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");
+    DPRINT("WM_ACTIVATE - ActivationState = %d\n", ActivationState);
 
     if ( ActivationState == WA_ACTIVE ||
          ActivationState == WA_CLICKACTIVE )
@@ -635,22 +739,21 @@ OnActivate(PGUI_CONSOLE_DATA GuiData, WPARAM wParam)
     }
 
     /*
-     * 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...
+     * Ignore the next mouse signal when we are going to be enabled again via
+     * the mouse, in order to prevent, e.g. when we are in Edit mode, erroneous
+     * mouse actions from the user that could spoil text selection or copy/pastes.
      */
-    if (Console->QuickEdit && (ActivationState == WA_CLICKACTIVE))
+    if (ActivationState == WA_CLICKACTIVE)
         GuiData->IgnoreNextMouseSignal = TRUE;
 }
 
 static VOID
 OnFocus(PGUI_CONSOLE_DATA GuiData, BOOL SetFocus)
 {
-    PCONSOLE Console = GuiData->Console;
+    PCONSRV_CONSOLE Console = GuiData->Console;
     INPUT_RECORD er;
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return;
 
     er.EventType = FOCUS_EVENT;
     er.Event.FocusEvent.bSetFocus = SetFocus;
@@ -659,9 +762,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");
+        DPRINT("TODO: Destroy console caret\n");
 }
 
 static VOID
@@ -814,7 +917,7 @@ UpdateSelection(PGUI_CONSOLE_DATA GuiData,
                 PCOORD SelectionAnchor OPTIONAL,
                 PCOORD coord)
 {
-    PCONSOLE Console = GuiData->Console;
+    PCONSRV_CONSOLE Console = GuiData->Console;
     HRGN oldRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection,
                                      &GuiData->Selection.dwSelectionAnchor,
                                      &GuiData->Selection.srSelection);
@@ -904,7 +1007,7 @@ UpdateSelection(PGUI_CONSOLE_DATA GuiData,
                 wcscat(WindowTitle, L" - ");
                 wcscat(WindowTitle, Console->Title.Buffer);
 
-                SetWindowText(GuiData->hWindow, WindowTitle);
+                SetWindowTextW(GuiData->hWindow, WindowTitle);
                 ConsoleFreeHeap(WindowTitle);
             }
 
@@ -924,7 +1027,7 @@ 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);
@@ -945,11 +1048,12 @@ GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
 static VOID
 OnPaint(PGUI_CONSOLE_DATA GuiData)
 {
-    PCONSOLE_SCREEN_BUFFER ActiveBuffer;
+    PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
     PAINTSTRUCT ps;
     RECT rcPaint;
 
-    ActiveBuffer = GuiData->ActiveBuffer;
+    /* Do nothing if the window is hidden */
+    if (!GuiData->IsWindowVisible) return;
 
     BeginPaint(GuiData->hWindow, &ps);
     if (ps.hdc != NULL &&
@@ -999,6 +1103,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;
 
@@ -1041,10 +1148,10 @@ IsSystemKey(WORD VirtualKeyCode)
 static VOID
 OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
 {
-    PCONSOLE Console = GuiData->Console;
+    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;
 
@@ -1206,12 +1313,15 @@ InvalidateCell(PGUI_CONSOLE_DATA GuiData,
 static VOID
 OnTimer(PGUI_CONSOLE_DATA GuiData)
 {
-    PCONSOLE Console = GuiData->Console;
+    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;
 
@@ -1311,9 +1421,9 @@ OnTimer(PGUI_CONSOLE_DATA GuiData)
 static BOOL
 OnClose(PGUI_CONSOLE_DATA GuiData)
 {
-    PCONSOLE Console = GuiData->Console;
+    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)
@@ -1323,7 +1433,7 @@ OnClose(PGUI_CONSOLE_DATA GuiData)
      * We shouldn't wait here, though, since the console lock is entered.
      * A copy of the thread list probably needs to be made.
      */
-    ConDrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT);
+    ConSrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT);
 
     LeaveCriticalSection(&Console->Lock);
     return FALSE;
@@ -1334,7 +1444,11 @@ OnNcDestroy(HWND hWnd)
 {
     PGUI_CONSOLE_DATA GuiData = GuiGetGuiData(hWnd);
 
-    KillTimer(hWnd, CONGUI_UPDATE_TIMER);
+    if (GuiData->IsWindowVisible)
+    {
+        KillTimer(hWnd, CONGUI_UPDATE_TIMER);
+    }
+
     GetSystemMenu(hWnd, TRUE);
 
     if (GuiData)
@@ -1343,7 +1457,7 @@ OnNcDestroy(HWND hWnd)
         if (GuiData->hMemDC ) DeleteDC(GuiData->hMemDC);
         if (GuiData->hBitmap) DeleteObject(GuiData->hBitmap);
         // if (GuiData->hSysPalette) DeleteObject(GuiData->hSysPalette);
-        if (GuiData->Font) DeleteObject(GuiData->Font);
+        DeleteFonts(GuiData);
     }
 
     /* Free the GuiData registration */
@@ -1382,25 +1496,29 @@ static LRESULT
 OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     BOOL Err = FALSE;
-    PCONSOLE Console = GuiData->Console;
+    PCONSRV_CONSOLE Console = GuiData->Console;
+
+    // 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_MOUSEMOVE)
+            msg != WM_XBUTTONDOWN)
         {
             /*
-             * If this mouse signal is not a button-down action or a move,
-             * then it is the last signal being ignored.
+             * If this mouse signal is not a button-down action
+             * then this is the last one being ignored.
              */
             GuiData->IgnoreNextMouseSignal = FALSE;
         }
         else
         {
             /*
-             * This mouse signal is a button-down action or a move.
+             * This mouse signal is a button-down action.
              * Ignore it and perform default action.
              */
             Err = TRUE;
@@ -1408,7 +1526,7 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
         goto Quit;
     }
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE))
     {
         Err = TRUE;
         goto Quit;
@@ -1555,6 +1673,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);
+                    Err = 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;
@@ -1573,6 +1711,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;
@@ -1588,6 +1744,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);
+                    Err = 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;
@@ -1608,6 +1783,21 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
                 break;
         }
 
+        /*
+         * HACK FOR CORE-8394: Ignore the next mouse move signal
+         * just after mouse down click actions.
+         */
+        switch (msg)
+        {
+            case WM_LBUTTONDOWN:
+            case WM_MBUTTONDOWN:
+            case WM_RBUTTONDOWN:
+            case WM_XBUTTONDOWN:
+                GuiData->IgnoreNextMouseSignal = TRUE;
+            default:
+                break;
+        }
+
         if (!Err)
         {
             if (wKeyState & MK_LBUTTON)
@@ -1616,6 +1806,10 @@ 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)
                 dwControlKeyState |= RIGHT_ALT_PRESSED;
@@ -1670,7 +1864,7 @@ GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
 static VOID
 Copy(PGUI_CONSOLE_DATA GuiData)
 {
-    if (OpenClipboard(GuiData->hWindow) == TRUE)
+    if (OpenClipboard(GuiData->hWindow))
     {
         PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
 
@@ -1700,7 +1894,7 @@ GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
 static VOID
 Paste(PGUI_CONSOLE_DATA GuiData)
 {
-    if (OpenClipboard(GuiData->hWindow) == TRUE)
+    if (OpenClipboard(GuiData->hWindow))
     {
         PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
 
@@ -1720,12 +1914,12 @@ Paste(PGUI_CONSOLE_DATA GuiData)
 static VOID
 OnGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
 {
-    PCONSOLE Console = GuiData->Console;
+    PCONSRV_CONSOLE Console = GuiData->Console;
     PCONSOLE_SCREEN_BUFFER ActiveBuffer;
     DWORD windx, windy;
     UINT  WidthUnit, HeightUnit;
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return;
 
     ActiveBuffer = GuiData->ActiveBuffer;
 
@@ -1752,9 +1946,12 @@ OnGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
 static VOID
 OnSize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
 {
-    PCONSOLE Console = GuiData->Console;
+    PCONSRV_CONSOLE Console = GuiData->Console;
 
-    if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+    /* Do nothing if the window is hidden */
+    if (!GuiData->IsWindowVisible) return;
+
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return;
 
     if ((GuiData->WindowSizeLock == FALSE) &&
         (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED))
@@ -1782,8 +1979,8 @@ OnSize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
         if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary;
 
         // Compensate for added scroll bars in new window
-        if (charx < Buff->ScreenBufferSize.X) windy -= GetSystemMetrics(SM_CYHSCROLL);    // new window will have a horizontal scroll bar
-        if (chary < Buff->ScreenBufferSize.Y) windx -= GetSystemMetrics(SM_CXVSCROLL);    // new window will have a vertical scroll bar
+        if (charx < (DWORD)Buff->ScreenBufferSize.X) windy -= GetSystemMetrics(SM_CYHSCROLL);    // new window will have a horizontal scroll bar
+        if (chary < (DWORD)Buff->ScreenBufferSize.Y) windx -= GetSystemMetrics(SM_CXVSCROLL);    // new window will have a vertical scroll bar
 
         charx = windx / (int)WidthUnit ;
         chary = windy / (int)HeightUnit;
@@ -1795,8 +1992,8 @@ OnSize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
         // 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);
@@ -1830,7 +2027,6 @@ OnMove(PGUI_CONSOLE_DATA GuiData)
 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
 
 VOID
-FASTCALL
 GuiConsoleHandleScrollbarMenu(VOID)
 {
     HMENU hMenu;
@@ -1858,14 +2054,14 @@ GuiConsoleHandleScrollbarMenu(VOID)
 static LRESULT
 OnScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
 {
-    PCONSOLE Console = GuiData->Console;
+    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;
+    if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return 0;
 
     Buff = GuiData->ActiveBuffer;
 
@@ -1969,7 +2165,7 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     LRESULT Result = 0;
     PGUI_CONSOLE_DATA GuiData = NULL;
-    PCONSOLE Console = NULL;
+    PCONSRV_CONSOLE Console = NULL;
 
     /*
      * - If it's the first time we create a window for the terminal,
@@ -2069,7 +2265,7 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
             /* 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);
+                return DefWindowProcW(hWnd, msg, wParam, lParam);
             }
 
             OnKey(GuiData, msg, wParam, lParam);
@@ -2078,6 +2274,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
@@ -2127,12 +2326,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:
@@ -2150,6 +2352,9 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
         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();
@@ -2278,6 +2483,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 ;
@@ -2301,19 +2509,25 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
             break;
         }
 
-        case PM_APPLY_CONSOLE_INFO:
+        /*
+         * Undocumented message sent by Windows' console.dll for applying console info.
+         * See http://www.catch22.net/sites/default/source/files/setconsoleinfo.c
+         * and http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf
+         * for more information.
+         */
+        case WM_SETCONSOLEINFO:
         {
-            GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
+            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);
+            // SetWindowTextW(GuiData->hWindow, GuiData->Console->Title.Buffer);
             // break;
 
         default: Default: