/* INCLUDES *******************************************************************/
#include <consrv.h>
-
+#include <intrin.h>
#include <windowsx.h>
#define NDEBUG
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));
if (LoadStringW(ConSrvDllInstance,
Items[i].uID,
szMenuString,
- sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
+ ARRAYSIZE(szMenuString)) > 0)
{
if (Items[i].SubMenu != NULL)
{
} while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
}
-static VOID
+//static
+VOID
CreateSysMenu(HWND hWnd)
{
MENUITEMINFOW mii;
if (hMenu != NULL)
{
mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_STRING;
+ mii.fMask = MIIM_STRING;
mii.dwTypeData = szMenuStringBack;
mii.cch = sizeof(szMenuStringBack)/sizeof(WCHAR);
}
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;
static VOID
Paste(PGUI_CONSOLE_DATA GuiData);
static VOID
-UpdateSelection(PGUI_CONSOLE_DATA GuiData, PCOORD coord);
+UpdateSelection(PGUI_CONSOLE_DATA GuiData,
+ PCOORD SelectionAnchor OPTIONAL,
+ PCOORD coord);
static VOID
Mark(PGUI_CONSOLE_DATA GuiData)
PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
/* Clear the old selection */
- // UpdateSelection(GuiData, NULL);
GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
/* Restart a new selection */
- GuiData->dwSelectionCursor.X = ActiveBuffer->ViewOrigin.X;
- GuiData->dwSelectionCursor.Y = ActiveBuffer->ViewOrigin.Y;
- GuiData->Selection.dwSelectionAnchor = GuiData->dwSelectionCursor;
- UpdateSelection(GuiData, &GuiData->Selection.dwSelectionAnchor);
+ GuiData->dwSelectionCursor = ActiveBuffer->ViewOrigin;
+ UpdateSelection(GuiData,
+ &GuiData->dwSelectionCursor,
+ &GuiData->dwSelectionCursor);
}
static VOID
SelectAll(PGUI_CONSOLE_DATA GuiData)
{
PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
+ COORD SelectionAnchor;
/* Clear the old selection */
- // UpdateSelection(GuiData, NULL);
GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
/*
* The selection area extends to the whole screen buffer's width.
*/
- GuiData->Selection.dwSelectionAnchor.X = 0;
- GuiData->Selection.dwSelectionAnchor.Y = 0;
+ SelectionAnchor.X = SelectionAnchor.Y = 0;
GuiData->dwSelectionCursor.X = ActiveBuffer->ScreenBufferSize.X - 1;
/*
/* Restart a new selection */
GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION;
- UpdateSelection(GuiData, &GuiData->dwSelectionCursor);
+ UpdateSelection(GuiData, &SelectionAnchor, &GuiData->dwSelectionCursor);
}
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,
// 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;
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);
}
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 )
}
/*
- * 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;
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
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
-UpdateSelection(PGUI_CONSOLE_DATA GuiData, PCOORD coord)
+UpdateSelection(PGUI_CONSOLE_DATA GuiData,
+ PCOORD SelectionAnchor OPTIONAL,
+ PCOORD coord)
{
- PCONSOLE Console = GuiData->Console;
- RECT oldRect;
+ PCONSRV_CONSOLE Console = GuiData->Console;
+ HRGN oldRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection,
+ &GuiData->Selection.dwSelectionAnchor,
+ &GuiData->Selection.srSelection);
- SmallRectToRect(GuiData, &oldRect, &GuiData->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(GuiData->Selection.dwSelectionAnchor.X, coord->X);
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 (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
{
- if (memcmp(&rc, &GuiData->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);
}
+ DeleteObject(newRgn);
+
GuiData->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY;
GuiData->Selection.srSelection = rc;
GuiData->dwSelectionCursor = *coord;
/* Clear the old selection */
if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
{
- InvalidateRect(GuiData->hWindow, &oldRect, FALSE);
+ InvalidateRgn(GuiData->hWindow, oldRgn, FALSE);
}
/*
wcscat(WindowTitle, L" - ");
wcscat(WindowTitle, Console->Title.Buffer);
- SetWindowText(GuiData->hWindow, WindowTitle);
+ SetWindowTextW(GuiData->hWindow, WindowTitle);
ConsoleFreeHeap(WindowTitle);
}
/* Clear the selection */
if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
{
- InvalidateRect(GuiData->hWindow, &oldRect, FALSE);
+ InvalidateRgn(GuiData->hWindow, oldRgn, FALSE);
}
GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
ConioUnpause(Console, PAUSED_FROM_SELECTION);
/* Restore the console title */
- SetWindowText(GuiData->hWindow, Console->Title.Buffer);
+ SetWindowTextW(GuiData->hWindow, Console->Title.Buffer);
}
+
+ DeleteObject(oldRgn);
}
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 &&
rcPaint.top,
SRCCOPY);
+ /* Draw the selection region if needed */
if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
{
- SmallRectToRect(GuiData, &rcPaint, &GuiData->Selection.srSelection);
-
- /* Invert the selection */
- if (IntersectRect(&rcPaint, &ps.rcPaint, &rcPaint))
- {
- InvertRect(ps.hdc, &rcPaint);
- }
+ PaintSelectionRect(GuiData, &ps);
}
LeaveCriticalSection(&GuiData->Lock);
{
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;
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;
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 */
- UpdateSelection(GuiData, NULL);
+ UpdateSelection(GuiData, NULL, NULL);
goto Quit;
}
{
/* Keyboard selection mode */
BOOL Interpreted = FALSE;
- BOOL MajPressed = (GetKeyState(VK_SHIFT) & 0x8000);
+ BOOL MajPressed = !!(GetKeyState(VK_SHIFT) & 0x8000);
switch (VirtualKeyCode)
{
if (Interpreted)
{
- if (!MajPressed)
- GuiData->Selection.dwSelectionAnchor = GuiData->dwSelectionCursor;
-
- UpdateSelection(GuiData, &GuiData->dwSelectionCursor);
+ UpdateSelection(GuiData,
+ !MajPressed ? &GuiData->dwSelectionCursor : NULL,
+ &GuiData->dwSelectionCursor);
}
else if (!IsSystemKey(VirtualKeyCode))
{
if (!IsSystemKey(VirtualKeyCode))
{
/* Clear the selection and send the key into the input buffer */
- UpdateSelection(GuiData, NULL);
+ UpdateSelection(GuiData, NULL, NULL);
}
else
{
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;
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)
* 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;
{
PGUI_CONSOLE_DATA GuiData = GuiGetGuiData(hWnd);
- KillTimer(hWnd, CONGUI_UPDATE_TIMER);
+ if (GuiData->IsWindowVisible)
+ {
+ KillTimer(hWnd, CONGUI_UPDATE_TIMER);
+ }
+
GetSystemMenu(hWnd, TRUE);
if (GuiData)
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 */
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;
goto Quit;
}
- if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+ if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE))
{
Err = TRUE;
goto Quit;
case WM_LBUTTONDOWN:
{
/* Clear the old selection */
- // UpdateSelection(GuiData, NULL);
GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
/* Restart a new selection */
- GuiData->Selection.dwSelectionAnchor = PointToCoord(GuiData, lParam);
+ GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
SetCapture(GuiData->hWindow);
GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
- UpdateSelection(GuiData, &GuiData->Selection.dwSelectionAnchor);
+ UpdateSelection(GuiData,
+ &GuiData->dwSelectionCursor,
+ &GuiData->dwSelectionCursor);
break;
}
case WM_LBUTTONUP:
{
- // COORD c;
-
if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
- // c = PointToCoord(GuiData, lParam);
+ // GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
GuiData->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
- // UpdateSelection(GuiData, &c);
+ // UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
ReleaseCapture();
break;
* Update the selection started with the single
* left-click that preceded this double-click.
*/
- GuiData->Selection.dwSelectionAnchor = cL;
- GuiData->dwSelectionCursor = cR;
-
GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
- UpdateSelection(GuiData, &GuiData->dwSelectionCursor);
+ UpdateSelection(GuiData, &cL, &cR);
/* Ignore the next mouse move signal */
GuiData->IgnoreNextMouseSignal = TRUE;
case WM_MOUSEMOVE:
{
- COORD c;
-
if (!(wParam & MK_LBUTTON)) break;
if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
- c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */
- UpdateSelection(GuiData, &c);
+ // TODO: Scroll buffer to bring SelectionCursor into view
+ GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
+ UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
break;
}
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;
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;
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;
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)
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;
static VOID
Copy(PGUI_CONSOLE_DATA GuiData)
{
- if (OpenClipboard(GuiData->hWindow) == TRUE)
+ if (OpenClipboard(GuiData->hWindow))
{
PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
}
/* Clear the selection */
- UpdateSelection(GuiData, NULL);
+ UpdateSelection(GuiData, NULL, NULL);
}
VOID
static VOID
Paste(PGUI_CONSOLE_DATA GuiData)
{
- if (OpenClipboard(GuiData->hWindow) == TRUE)
+ if (OpenClipboard(GuiData->hWindow))
{
PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
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;
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))
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;
// 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);
// HACK: This functionality is standard for general scrollbars. Don't add it by hand.
VOID
-FASTCALL
GuiConsoleHandleScrollbarMenu(VOID)
{
HMENU hMenu;
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;
{
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,
/* 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);
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
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:
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();
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 ;
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: