2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: frontends/gui/conwnd.c
5 * PURPOSE: GUI Console Window Class
6 * PROGRAMMERS: Gé van Geldorp
9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
12 /* INCLUDES *******************************************************************/
25 /* GLOBALS ********************************************************************/
27 // #define PM_CREATE_CONSOLE (WM_APP + 1)
28 // #define PM_DESTROY_CONSOLE (WM_APP + 2)
31 #define CONGUI_MIN_WIDTH 10
32 #define CONGUI_MIN_HEIGHT 10
33 #define CONGUI_UPDATE_TIME 0
34 #define CONGUI_UPDATE_TIMER 1
36 #define CURSOR_BLINK_TIME 500
39 /**************************************************************\
40 \** Define the Console Leader Process for the console window **/
41 #define GWLP_CONWND_ALLOC (2 * sizeof(LONG_PTR))
42 #define GWLP_CONSOLE_LEADER_PID 0
43 #define GWLP_CONSOLE_LEADER_TID 4
46 SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData
)
48 PCONSOLE_PROCESS_DATA ProcessData
;
49 CLIENT_ID ConsoleLeaderCID
;
51 ProcessData
= ConSrvGetConsoleLeaderProcess(GuiData
->Console
);
52 ConsoleLeaderCID
= ProcessData
->Process
->ClientId
;
53 SetWindowLongPtrW(GuiData
->hWindow
, GWLP_CONSOLE_LEADER_PID
,
54 (LONG_PTR
)(ConsoleLeaderCID
.UniqueProcess
));
55 SetWindowLongPtrW(GuiData
->hWindow
, GWLP_CONSOLE_LEADER_TID
,
56 (LONG_PTR
)(ConsoleLeaderCID
.UniqueThread
));
58 /**************************************************************/
60 HICON ghDefaultIcon
= NULL
;
61 HICON ghDefaultIconSm
= NULL
;
62 HCURSOR ghDefaultCursor
= NULL
;
64 typedef struct _GUICONSOLE_MENUITEM
67 const struct _GUICONSOLE_MENUITEM
*SubMenu
;
69 } GUICONSOLE_MENUITEM
, *PGUICONSOLE_MENUITEM
;
71 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems
[] =
73 { IDS_MARK
, NULL
, ID_SYSTEM_EDIT_MARK
},
74 { IDS_COPY
, NULL
, ID_SYSTEM_EDIT_COPY
},
75 { IDS_PASTE
, NULL
, ID_SYSTEM_EDIT_PASTE
},
76 { IDS_SELECTALL
, NULL
, ID_SYSTEM_EDIT_SELECTALL
},
77 { IDS_SCROLL
, NULL
, ID_SYSTEM_EDIT_SCROLL
},
78 { IDS_FIND
, NULL
, ID_SYSTEM_EDIT_FIND
},
80 { 0, NULL
, 0 } /* End of list */
83 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems
[] =
85 { IDS_EDIT
, GuiConsoleEditMenuItems
, 0 },
86 { IDS_DEFAULTS
, NULL
, ID_SYSTEM_DEFAULTS
},
87 { IDS_PROPERTIES
, NULL
, ID_SYSTEM_PROPERTIES
},
89 { 0, NULL
, 0 } /* End of list */
93 * Default 16-color palette for foreground and background
94 * (corresponding flags in comments).
96 const COLORREF s_Colors
[16] =
98 RGB(0, 0, 0), // (Black)
99 RGB(0, 0, 128), // BLUE
100 RGB(0, 128, 0), // GREEN
101 RGB(0, 128, 128), // BLUE | GREEN
102 RGB(128, 0, 0), // RED
103 RGB(128, 0, 128), // BLUE | RED
104 RGB(128, 128, 0), // GREEN | RED
105 RGB(192, 192, 192), // BLUE | GREEN | RED
107 RGB(128, 128, 128), // (Grey) INTENSITY
108 RGB(0, 0, 255), // BLUE | INTENSITY
109 RGB(0, 255, 0), // GREEN | INTENSITY
110 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
111 RGB(255, 0, 0), // RED | INTENSITY
112 RGB(255, 0, 255), // BLUE | RED | INTENSITY
113 RGB(255, 255, 0), // GREEN | RED | INTENSITY
114 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
117 /* FUNCTIONS ******************************************************************/
119 static LRESULT CALLBACK
120 ConWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
123 RegisterConWndClass(IN HINSTANCE hInstance
)
125 WNDCLASSEXW WndClass
;
128 ghDefaultIcon
= LoadImageW(hInstance
,
129 MAKEINTRESOURCEW(IDI_TERMINAL
),
131 GetSystemMetrics(SM_CXICON
),
132 GetSystemMetrics(SM_CYICON
),
134 ghDefaultIconSm
= LoadImageW(hInstance
,
135 MAKEINTRESOURCEW(IDI_TERMINAL
),
137 GetSystemMetrics(SM_CXSMICON
),
138 GetSystemMetrics(SM_CYSMICON
),
140 ghDefaultCursor
= LoadCursorW(NULL
, IDC_ARROW
);
142 WndClass
.cbSize
= sizeof(WNDCLASSEXW
);
143 WndClass
.lpszClassName
= GUI_CONWND_CLASS
;
144 WndClass
.lpfnWndProc
= ConWndProc
;
145 WndClass
.style
= CS_DBLCLKS
/* | CS_HREDRAW | CS_VREDRAW */;
146 WndClass
.hInstance
= hInstance
;
147 WndClass
.hIcon
= ghDefaultIcon
;
148 WndClass
.hIconSm
= ghDefaultIconSm
;
149 WndClass
.hCursor
= ghDefaultCursor
;
150 WndClass
.hbrBackground
= (HBRUSH
)GetStockObject(BLACK_BRUSH
); // The color of a terminal when it is switched off.
151 WndClass
.lpszMenuName
= NULL
;
152 WndClass
.cbClsExtra
= 0;
153 WndClass
.cbWndExtra
= GWLP_CONWND_ALLOC
;
155 WndClassAtom
= RegisterClassExW(&WndClass
);
156 if (WndClassAtom
== 0)
158 DPRINT1("Failed to register GUI console class\n");
162 NtUserConsoleControl(GuiConsoleWndClassAtom
, &WndClassAtom
, sizeof(ATOM
));
165 return (WndClassAtom
!= 0);
169 UnRegisterConWndClass(HINSTANCE hInstance
)
171 return !!UnregisterClassW(GUI_CONWND_CLASS
, hInstance
);
177 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer
,
178 IN PGUI_CONSOLE_DATA GuiData
,
180 OUT PUINT HeightUnit
)
182 if (Buffer
== NULL
|| GuiData
== NULL
||
183 WidthUnit
== NULL
|| HeightUnit
== NULL
)
188 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
190 *WidthUnit
= GuiData
->CharWidth
;
191 *HeightUnit
= GuiData
->CharHeight
;
193 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
201 AppendMenuItems(HMENU hMenu
,
202 const GUICONSOLE_MENUITEM
*Items
)
205 WCHAR szMenuString
[255];
210 if (Items
[i
].uID
!= (UINT
)-1)
212 if (LoadStringW(ConSrvDllInstance
,
215 ARRAYSIZE(szMenuString
)) > 0)
217 if (Items
[i
].SubMenu
!= NULL
)
219 hSubMenu
= CreatePopupMenu();
220 if (hSubMenu
!= NULL
)
222 AppendMenuItems(hSubMenu
, Items
[i
].SubMenu
);
224 if (!AppendMenuW(hMenu
,
225 MF_STRING
| MF_POPUP
,
229 DestroyMenu(hSubMenu
);
250 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
255 CreateSysMenu(HWND hWnd
)
258 WCHAR szMenuStringBack
[255];
260 HMENU hMenu
= GetSystemMenu(hWnd
, FALSE
);
263 mii
.cbSize
= sizeof(mii
);
264 mii
.fMask
= MIIM_STRING
;
265 mii
.dwTypeData
= szMenuStringBack
;
266 mii
.cch
= sizeof(szMenuStringBack
)/sizeof(WCHAR
);
268 GetMenuItemInfoW(hMenu
, SC_CLOSE
, FALSE
, &mii
);
270 ptrTab
= wcschr(szMenuStringBack
, '\t');
274 mii
.cch
= wcslen(szMenuStringBack
);
276 SetMenuItemInfoW(hMenu
, SC_CLOSE
, FALSE
, &mii
);
279 AppendMenuItems(hMenu
, GuiConsoleMainMenuItems
);
285 SendMenuEvent(PCONSRV_CONSOLE Console
, UINT CmdId
)
289 DPRINT("Menu item ID: %d\n", CmdId
);
291 if (!ConDrvValidateConsoleUnsafe((PCONSOLE
)Console
, CONSOLE_RUNNING
, TRUE
)) return;
293 /* Send a menu event */
294 er
.EventType
= MENU_EVENT
;
295 er
.Event
.MenuEvent
.dwCommandId
= CmdId
;
296 ConioProcessInputEvent(Console
, &er
);
298 LeaveCriticalSection(&Console
->Lock
);
302 Copy(PGUI_CONSOLE_DATA GuiData
);
304 Paste(PGUI_CONSOLE_DATA GuiData
);
306 UpdateSelection(PGUI_CONSOLE_DATA GuiData
,
307 PCOORD SelectionAnchor OPTIONAL
,
311 Mark(PGUI_CONSOLE_DATA GuiData
)
313 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
;
315 /* Clear the old selection */
316 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
318 /* Restart a new selection */
319 GuiData
->dwSelectionCursor
= ActiveBuffer
->ViewOrigin
;
320 UpdateSelection(GuiData
,
321 &GuiData
->dwSelectionCursor
,
322 &GuiData
->dwSelectionCursor
);
326 SelectAll(PGUI_CONSOLE_DATA GuiData
)
328 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
;
329 COORD SelectionAnchor
;
331 /* Clear the old selection */
332 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
335 * The selection area extends to the whole screen buffer's width.
337 SelectionAnchor
.X
= SelectionAnchor
.Y
= 0;
338 GuiData
->dwSelectionCursor
.X
= ActiveBuffer
->ScreenBufferSize
.X
- 1;
341 * Determine whether the selection must extend to just some part
342 * (for text-mode screen buffers) or to all of the screen buffer's
343 * height (for graphics ones).
345 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
348 * We select all the characters from the first line
349 * to the line where the cursor is positioned.
351 GuiData
->dwSelectionCursor
.Y
= ActiveBuffer
->CursorPosition
.Y
;
353 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
356 * We select all the screen buffer area.
358 GuiData
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
361 /* Restart a new selection */
362 GuiData
->Selection
.dwFlags
|= CONSOLE_MOUSE_SELECTION
;
363 UpdateSelection(GuiData
, &SelectionAnchor
, &GuiData
->dwSelectionCursor
);
367 OnCommand(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
370 PCONSRV_CONSOLE Console
= GuiData
->Console
;
373 * In case the selected menu item belongs to the user-reserved menu id range,
374 * send to him a menu event and return directly. The user must handle those
375 * reserved menu commands...
377 if (GuiData
->CmdIdLow
<= (UINT
)wParam
&& (UINT
)wParam
<= GuiData
->CmdIdHigh
)
379 SendMenuEvent(Console
, (UINT
)wParam
);
383 /* ... otherwise, perform actions. */
386 case ID_SYSTEM_EDIT_MARK
:
390 case ID_SYSTEM_EDIT_COPY
:
394 case ID_SYSTEM_EDIT_PASTE
:
398 case ID_SYSTEM_EDIT_SELECTALL
:
402 case ID_SYSTEM_EDIT_SCROLL
:
403 DPRINT1("Scrolling is not handled yet\n");
406 case ID_SYSTEM_EDIT_FIND
:
407 DPRINT1("Finding is not handled yet\n");
410 case ID_SYSTEM_DEFAULTS
:
411 GuiConsoleShowConsoleProperties(GuiData
, TRUE
);
414 case ID_SYSTEM_PROPERTIES
:
415 GuiConsoleShowConsoleProperties(GuiData
, FALSE
);
425 Ret
= DefWindowProcW(GuiData
->hWindow
, WM_SYSCOMMAND
, wParam
, lParam
);
430 static PGUI_CONSOLE_DATA
431 GuiGetGuiData(HWND hWnd
)
433 /* This function ensures that the console pointer is not NULL */
434 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
435 return ( ((GuiData
== NULL
) || (GuiData
->hWindow
== hWnd
&& GuiData
->Console
!= NULL
)) ? GuiData
: NULL
);
439 ResizeConWnd(PGUI_CONSOLE_DATA GuiData
, DWORD WidthUnit
, DWORD HeightUnit
)
441 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
446 Width
= Buff
->ViewSize
.X
* WidthUnit
+
447 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
448 Height
= Buff
->ViewSize
.Y
* HeightUnit
+
449 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
451 /* Set scrollbar sizes */
452 sInfo
.cbSize
= sizeof(SCROLLINFO
);
453 sInfo
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
455 if (Buff
->ScreenBufferSize
.Y
> Buff
->ViewSize
.Y
)
457 sInfo
.nMax
= Buff
->ScreenBufferSize
.Y
- 1;
458 sInfo
.nPage
= Buff
->ViewSize
.Y
;
459 sInfo
.nPos
= Buff
->ViewOrigin
.Y
;
460 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &sInfo
, TRUE
);
461 Width
+= GetSystemMetrics(SM_CXVSCROLL
);
462 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, TRUE
);
466 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, FALSE
);
469 if (Buff
->ScreenBufferSize
.X
> Buff
->ViewSize
.X
)
471 sInfo
.nMax
= Buff
->ScreenBufferSize
.X
- 1;
472 sInfo
.nPage
= Buff
->ViewSize
.X
;
473 sInfo
.nPos
= Buff
->ViewOrigin
.X
;
474 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &sInfo
, TRUE
);
475 Height
+= GetSystemMetrics(SM_CYHSCROLL
);
476 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, TRUE
);
480 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, FALSE
);
483 /* Resize the window */
484 SetWindowPos(GuiData
->hWindow
, NULL
, 0, 0, Width
, Height
,
485 SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
486 // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call
487 // to: InvalidateRect(GuiData->hWindow, NULL, TRUE);
492 DeleteFonts(PGUI_CONSOLE_DATA GuiData
)
495 for (i
= 0; i
< ARRAYSIZE(GuiData
->Font
); ++i
)
497 if (GuiData
->Font
[i
] != NULL
) DeleteObject(GuiData
->Font
[i
]);
498 GuiData
->Font
[i
] = NULL
;
503 CreateDerivedFont(HFONT OrgFont
,
512 /* Initialize the LOGFONT structure */
513 RtlZeroMemory(&lf
, sizeof(lf
));
515 /* Retrieve the details of the current font */
516 if (GetObject(OrgFont
, sizeof(lf
), &lf
) == 0)
519 /* Change the font attributes */
520 // lf.lfHeight = FontSize.Y;
521 // lf.lfWidth = FontSize.X;
522 lf
.lfWeight
= FontWeight
;
523 // lf.lfItalic = bItalic;
524 lf
.lfUnderline
= bUnderline
;
525 lf
.lfStrikeOut
= bStrikeOut
;
527 /* Build a new font */
528 return CreateFontIndirect(&lf
);
532 InitFonts(PGUI_CONSOLE_DATA GuiData
,
533 LPWSTR FaceName
, // Points to a WCHAR array of LF_FACESIZE elements.
539 HFONT OldFont
, NewFont
;
543 hDC
= GetDC(GuiData
->hWindow
);
546 * Initialize a new NORMAL font and get its metrics.
549 FontSize
.Y
= FontSize
.Y
> 0 ? -MulDiv(FontSize
.Y
, GetDeviceCaps(hDC
, LOGPIXELSY
), 72)
552 NewFont
= CreateFontW(FontSize
.Y
,
564 FIXED_PITCH
| FontFamily
,
568 DPRINT1("InitFonts: CreateFontW failed\n");
569 ReleaseDC(GuiData
->hWindow
, hDC
);
573 OldFont
= SelectObject(hDC
, NewFont
);
576 DPRINT1("InitFonts: SelectObject failed\n");
577 ReleaseDC(GuiData
->hWindow
, hDC
);
578 DeleteObject(NewFont
);
582 if (!GetTextMetricsW(hDC
, &Metrics
))
584 DPRINT1("InitFonts: GetTextMetrics failed\n");
585 SelectObject(hDC
, OldFont
);
586 ReleaseDC(GuiData
->hWindow
, hDC
);
587 DeleteObject(NewFont
);
590 GuiData
->CharWidth
= Metrics
.tmMaxCharWidth
;
591 GuiData
->CharHeight
= Metrics
.tmHeight
+ Metrics
.tmExternalLeading
;
593 /* Measure real char width more precisely if possible */
594 if (GetTextExtentPoint32W(hDC
, L
"R", 1, &CharSize
))
595 GuiData
->CharWidth
= CharSize
.cx
;
597 SelectObject(hDC
, OldFont
);
598 ReleaseDC(GuiData
->hWindow
, hDC
);
601 * Initialization succeeded.
603 // Delete all the old fonts first.
604 DeleteFonts(GuiData
);
605 GuiData
->Font
[FONT_NORMAL
] = NewFont
;
608 * Now build the other fonts (bold, underlined, mixed).
610 GuiData
->Font
[FONT_BOLD
] =
611 CreateDerivedFont(GuiData
->Font
[FONT_NORMAL
],
612 FontWeight
< FW_BOLD
? FW_BOLD
: FontWeight
,
615 GuiData
->Font
[FONT_UNDERLINE
] =
616 CreateDerivedFont(GuiData
->Font
[FONT_NORMAL
],
620 GuiData
->Font
[FONT_BOLD
| FONT_UNDERLINE
] =
621 CreateDerivedFont(GuiData
->Font
[FONT_NORMAL
],
622 FontWeight
< FW_BOLD
? FW_BOLD
: FontWeight
,
629 if (FaceName
!= GuiData
->GuiInfo
.FaceName
)
631 wcsncpy(GuiData
->GuiInfo
.FaceName
, FaceName
, LF_FACESIZE
);
632 GuiData
->GuiInfo
.FaceName
[LF_FACESIZE
- 1] = UNICODE_NULL
;
634 GuiData
->GuiInfo
.FontFamily
= FontFamily
;
635 GuiData
->GuiInfo
.FontSize
= FontSize
;
636 GuiData
->GuiInfo
.FontWeight
= FontWeight
;
643 OnNcCreate(HWND hWnd
, LPCREATESTRUCTW Create
)
645 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)Create
->lpCreateParams
;
646 PCONSRV_CONSOLE Console
;
650 DPRINT1("GuiConsoleNcCreate: No GUI data\n");
654 Console
= GuiData
->Console
;
656 GuiData
->hWindow
= hWnd
;
658 /* Initialize the fonts */
659 if (!InitFonts(GuiData
,
660 GuiData
->GuiInfo
.FaceName
,
661 GuiData
->GuiInfo
.FontFamily
,
662 GuiData
->GuiInfo
.FontSize
,
663 GuiData
->GuiInfo
.FontWeight
))
665 DPRINT1("GuiConsoleNcCreate: InitFonts failed\n");
666 GuiData
->hWindow
= NULL
;
667 NtSetEvent(GuiData
->hGuiInitEvent
, NULL
);
671 /* Initialize the terminal framebuffer */
672 GuiData
->hMemDC
= CreateCompatibleDC(NULL
);
673 GuiData
->hBitmap
= NULL
;
674 GuiData
->hSysPalette
= NULL
; /* Original system palette */
676 /* Update the icons of the window */
677 if (GuiData
->hIcon
!= ghDefaultIcon
)
679 DefWindowProcW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
680 DefWindowProcW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
683 // FIXME: Keep these instructions here ? ///////////////////////////////////
684 Console
->ActiveBuffer
->CursorBlinkOn
= TRUE
;
685 Console
->ActiveBuffer
->ForceCursorOff
= FALSE
;
686 ////////////////////////////////////////////////////////////////////////////
688 SetWindowLongPtrW(GuiData
->hWindow
, GWLP_USERDATA
, (DWORD_PTR
)GuiData
);
690 if (GuiData
->IsWindowVisible
)
692 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
695 // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
696 //CreateSysMenu(GuiData->hWindow);
698 DPRINT("OnNcCreate - setting start event\n");
699 NtSetEvent(GuiData
->hGuiInitEvent
, NULL
);
701 return (BOOL
)DefWindowProcW(GuiData
->hWindow
, WM_NCCREATE
, 0, (LPARAM
)Create
);
706 EnterFullScreen(PGUI_CONSOLE_DATA GuiData
);
708 LeaveFullScreen(PGUI_CONSOLE_DATA GuiData
);
710 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData
, BOOL FullScreen
);
712 GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData
);
715 OnActivate(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
)
717 WORD ActivationState
= LOWORD(wParam
);
719 DPRINT("WM_ACTIVATE - ActivationState = %d\n", ActivationState
);
721 if ( ActivationState
== WA_ACTIVE
||
722 ActivationState
== WA_CLICKACTIVE
)
724 if (GuiData
->GuiInfo
.FullScreen
)
726 EnterFullScreen(GuiData
);
727 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
728 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
731 else // if (ActivationState == WA_INACTIVE)
733 if (GuiData
->GuiInfo
.FullScreen
)
735 SendMessageW(GuiData
->hWindow
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0);
736 LeaveFullScreen(GuiData
);
737 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
738 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
743 * Ignore the next mouse signal when we are going to be enabled again via
744 * the mouse, in order to prevent, e.g. when we are in Edit mode, erroneous
745 * mouse actions from the user that could spoil text selection or copy/pastes.
747 if (ActivationState
== WA_CLICKACTIVE
)
748 GuiData
->IgnoreNextMouseSignal
= TRUE
;
752 OnFocus(PGUI_CONSOLE_DATA GuiData
, BOOL SetFocus
)
754 PCONSRV_CONSOLE Console
= GuiData
->Console
;
757 if (!ConDrvValidateConsoleUnsafe((PCONSOLE
)Console
, CONSOLE_RUNNING
, TRUE
)) return;
759 /* Set console focus state */
760 Console
->HasFocus
= SetFocus
;
763 * Set the priority of the processes of this console
764 * in accordance with the console focus state.
766 ConSrvSetConsoleProcessFocus(Console
, SetFocus
);
768 /* Send a focus event */
769 er
.EventType
= FOCUS_EVENT
;
770 er
.Event
.FocusEvent
.bSetFocus
= SetFocus
;
771 ConioProcessInputEvent(Console
, &er
);
773 LeaveCriticalSection(&Console
->Lock
);
776 DPRINT("TODO: Create console caret\n");
778 DPRINT("TODO: Destroy console caret\n");
782 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
784 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
785 UINT WidthUnit
, HeightUnit
;
787 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
789 Rect
->left
= (SmallRect
->Left
- Buffer
->ViewOrigin
.X
) * WidthUnit
;
790 Rect
->top
= (SmallRect
->Top
- Buffer
->ViewOrigin
.Y
) * HeightUnit
;
791 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ViewOrigin
.X
) * WidthUnit
;
792 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ViewOrigin
.Y
) * HeightUnit
;
796 GetSelectionBeginEnd(PCOORD Begin
, PCOORD End
,
797 PCOORD SelectionAnchor
,
798 PSMALL_RECT SmallRect
)
800 if (Begin
== NULL
|| End
== NULL
) return;
802 *Begin
= *SelectionAnchor
;
803 End
->X
= (SelectionAnchor
->X
== SmallRect
->Left
) ? SmallRect
->Right
804 /* Case X != Left, must be == Right */ : SmallRect
->Left
;
805 End
->Y
= (SelectionAnchor
->Y
== SmallRect
->Top
) ? SmallRect
->Bottom
806 /* Case Y != Top, must be == Bottom */ : SmallRect
->Top
;
808 /* Exchange Begin / End if Begin > End lexicographically */
809 if (Begin
->Y
> End
->Y
|| (Begin
->Y
== End
->Y
&& Begin
->X
> End
->X
))
811 End
->X
= _InterlockedExchange16(&Begin
->X
, End
->X
);
812 End
->Y
= _InterlockedExchange16(&Begin
->Y
, End
->Y
);
817 CreateSelectionRgn(PGUI_CONSOLE_DATA GuiData
,
819 PCOORD SelectionAnchor
,
820 PSMALL_RECT SmallRect
)
825 SmallRectToRect(GuiData
, &rect
, SmallRect
);
826 return CreateRectRgnIndirect(&rect
);
833 GetSelectionBeginEnd(&Begin
, &End
, SelectionAnchor
, SmallRect
);
835 if (Begin
.Y
== End
.Y
)
845 // Debug thingie to see whether I can put this corner case
846 // together with the previous one.
847 if (SmallRect
->Left
!= sr
.Left
||
848 SmallRect
->Top
!= sr
.Top
||
849 SmallRect
->Right
!= sr
.Right
||
850 SmallRect
->Bottom
!= sr
.Bottom
)
853 "SmallRect = (%d, %d, %d, %d)\n"
854 "sr = (%d, %d, %d, %d)\n"
856 SmallRect
->Left
, SmallRect
->Top
, SmallRect
->Right
, SmallRect
->Bottom
,
857 sr
.Left
, sr
.Top
, sr
.Right
, sr
.Bottom
);
860 SmallRectToRect(GuiData
, &r
, &sr
);
861 SelRgn
= CreateRectRgnIndirect(&r
);
865 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
;
868 SMALL_RECT sr1
, sr2
, sr3
;
873 sr1
.Right
= ActiveBuffer
->ScreenBufferSize
.X
- 1;
874 sr1
.Bottom
= Begin
.Y
;
877 sr2
.Top
= Begin
.Y
+ 1;
878 sr2
.Right
= ActiveBuffer
->ScreenBufferSize
.X
- 1;
879 sr2
.Bottom
= End
.Y
- 1;
886 SmallRectToRect(GuiData
, &r1
, &sr1
);
887 SmallRectToRect(GuiData
, &r2
, &sr2
);
888 SmallRectToRect(GuiData
, &r3
, &sr3
);
890 rg1
= CreateRectRgnIndirect(&r1
);
891 rg2
= CreateRectRgnIndirect(&r2
);
892 rg3
= CreateRectRgnIndirect(&r3
);
894 CombineRgn(rg1
, rg1
, rg2
, RGN_XOR
);
895 CombineRgn(rg1
, rg1
, rg3
, RGN_XOR
);
907 PaintSelectionRect(PGUI_CONSOLE_DATA GuiData
, PPAINTSTRUCT pps
)
909 HRGN rgnPaint
= CreateRectRgnIndirect(&pps
->rcPaint
);
910 HRGN rgnSel
= CreateSelectionRgn(GuiData
, GuiData
->LineSelection
,
911 &GuiData
->Selection
.dwSelectionAnchor
,
912 &GuiData
->Selection
.srSelection
);
914 /* Invert the selection */
916 int ErrorCode
= CombineRgn(rgnPaint
, rgnPaint
, rgnSel
, RGN_AND
);
917 if (ErrorCode
!= ERROR
&& ErrorCode
!= NULLREGION
)
919 InvertRgn(pps
->hdc
, rgnPaint
);
922 DeleteObject(rgnSel
);
923 DeleteObject(rgnPaint
);
927 UpdateSelection(PGUI_CONSOLE_DATA GuiData
,
928 PCOORD SelectionAnchor OPTIONAL
,
931 PCONSRV_CONSOLE Console
= GuiData
->Console
;
932 HRGN oldRgn
= CreateSelectionRgn(GuiData
, GuiData
->LineSelection
,
933 &GuiData
->Selection
.dwSelectionAnchor
,
934 &GuiData
->Selection
.srSelection
);
936 /* Update the anchor if needed (use the old one if NULL) */
938 GuiData
->Selection
.dwSelectionAnchor
= *SelectionAnchor
;
946 * Pressing the Control key while selecting text, allows us to enter
947 * into line-selection mode, the selection mode of *nix terminals.
949 BOOL OldLineSel
= GuiData
->LineSelection
;
950 GuiData
->LineSelection
= !!(GetKeyState(VK_CONTROL
) & 0x8000);
952 /* Exchange left/top with right/bottom if required */
953 rc
.Left
= min(GuiData
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
954 rc
.Top
= min(GuiData
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
955 rc
.Right
= max(GuiData
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
956 rc
.Bottom
= max(GuiData
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
958 newRgn
= CreateSelectionRgn(GuiData
, GuiData
->LineSelection
,
959 &GuiData
->Selection
.dwSelectionAnchor
,
962 if (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
964 if (OldLineSel
!= GuiData
->LineSelection
||
965 memcmp(&rc
, &GuiData
->Selection
.srSelection
, sizeof(SMALL_RECT
)) != 0)
967 /* Calculate the region that needs to be updated */
968 if (oldRgn
&& newRgn
&& CombineRgn(newRgn
, newRgn
, oldRgn
, RGN_XOR
) != ERROR
)
970 InvalidateRgn(GuiData
->hWindow
, newRgn
, FALSE
);
976 InvalidateRgn(GuiData
->hWindow
, newRgn
, FALSE
);
979 DeleteObject(newRgn
);
981 GuiData
->Selection
.dwFlags
|= CONSOLE_SELECTION_NOT_EMPTY
;
982 GuiData
->Selection
.srSelection
= rc
;
983 GuiData
->dwSelectionCursor
= *coord
;
985 if ((GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) == 0)
987 LPWSTR SelTypeStr
= NULL
, WindowTitle
= NULL
;
988 SIZE_T SelTypeStrLength
= 0, Length
= 0;
990 /* Clear the old selection */
991 if (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
993 InvalidateRgn(GuiData
->hWindow
, oldRgn
, FALSE
);
997 * When passing a zero-length buffer size, LoadString(...) returns
998 * a read-only pointer buffer to the program's resource string.
1001 LoadStringW(ConSrvDllInstance
,
1002 (GuiData
->Selection
.dwFlags
& CONSOLE_MOUSE_SELECTION
)
1003 ? IDS_SELECT_TITLE
: IDS_MARK_TITLE
,
1004 (LPWSTR
)&SelTypeStr
, 0);
1007 * Prepend the selection type string to the current console title
1008 * if we succeeded in retrieving a valid localized string.
1012 // 3 for " - " and 1 for NULL
1013 Length
= Console
->Title
.Length
+ (SelTypeStrLength
+ 3 + 1) * sizeof(WCHAR
);
1014 WindowTitle
= ConsoleAllocHeap(0, Length
);
1016 wcsncpy(WindowTitle
, SelTypeStr
, SelTypeStrLength
);
1017 WindowTitle
[SelTypeStrLength
] = L
'\0';
1018 wcscat(WindowTitle
, L
" - ");
1019 wcscat(WindowTitle
, Console
->Title
.Buffer
);
1021 SetWindowTextW(GuiData
->hWindow
, WindowTitle
);
1022 ConsoleFreeHeap(WindowTitle
);
1025 GuiData
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
;
1026 ConioPause(Console
, PAUSED_FROM_SELECTION
);
1031 /* Clear the selection */
1032 if (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
1034 InvalidateRgn(GuiData
->hWindow
, oldRgn
, FALSE
);
1037 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
1038 ConioUnpause(Console
, PAUSED_FROM_SELECTION
);
1040 /* Restore the console title */
1041 SetWindowTextW(GuiData
->hWindow
, Console
->Title
.Buffer
);
1044 DeleteObject(oldRgn
);
1049 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
1050 PGUI_CONSOLE_DATA GuiData
,
1052 PRECT rcFramebuffer
);
1054 GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
1055 PGUI_CONSOLE_DATA GuiData
,
1057 PRECT rcFramebuffer
);
1060 OnPaint(PGUI_CONSOLE_DATA GuiData
)
1062 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
;
1066 /* Do nothing if the window is hidden */
1067 if (!GuiData
->IsWindowVisible
) return;
1069 BeginPaint(GuiData
->hWindow
, &ps
);
1070 if (ps
.hdc
!= NULL
&&
1071 ps
.rcPaint
.left
< ps
.rcPaint
.right
&&
1072 ps
.rcPaint
.top
< ps
.rcPaint
.bottom
)
1074 EnterCriticalSection(&GuiData
->Lock
);
1076 /* Compose the current screen-buffer on-memory */
1077 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
1079 GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)ActiveBuffer
,
1080 GuiData
, &ps
.rcPaint
, &rcPaint
);
1082 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
1084 GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)ActiveBuffer
,
1085 GuiData
, &ps
.rcPaint
, &rcPaint
);
1088 /* Send it to screen */
1092 rcPaint
.right
- rcPaint
.left
,
1093 rcPaint
.bottom
- rcPaint
.top
,
1099 /* Draw the selection region if needed */
1100 if (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
1102 PaintSelectionRect(GuiData
, &ps
);
1105 LeaveCriticalSection(&GuiData
->Lock
);
1107 EndPaint(GuiData
->hWindow
, &ps
);
1113 OnPaletteChanged(PGUI_CONSOLE_DATA GuiData
)
1115 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
;
1117 /* Do nothing if the window is hidden */
1118 if (!GuiData
->IsWindowVisible
) return;
1120 // See WM_PALETTECHANGED message
1121 // if ((HWND)wParam == hWnd) break;
1123 // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
1124 if (ActiveBuffer
->PaletteHandle
)
1126 DPRINT("WM_PALETTECHANGED changing palette\n");
1128 /* Specify the use of the system palette for the framebuffer */
1129 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
1131 /* Realize the (logical) palette */
1132 RealizePalette(GuiData
->hMemDC
);
1137 IsSystemKey(WORD VirtualKeyCode
)
1139 switch (VirtualKeyCode
)
1141 /* From MSDN, "Virtual-Key Codes" */
1160 OnKey(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1162 PCONSRV_CONSOLE Console
= GuiData
->Console
;
1163 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
1165 if (!ConDrvValidateConsoleUnsafe((PCONSOLE
)Console
, CONSOLE_RUNNING
, TRUE
)) return;
1167 ActiveBuffer
= GuiData
->ActiveBuffer
;
1169 if (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
)
1171 WORD VirtualKeyCode
= LOWORD(wParam
);
1173 if (msg
!= WM_KEYDOWN
) goto Quit
;
1175 if (VirtualKeyCode
== VK_RETURN
)
1177 /* Copy (and clear) selection if ENTER is pressed */
1181 else if ( VirtualKeyCode
== VK_ESCAPE
||
1182 (VirtualKeyCode
== 'C' && (GetKeyState(VK_CONTROL
) & 0x8000)) )
1184 /* Cancel selection if ESC or Ctrl-C are pressed */
1185 UpdateSelection(GuiData
, NULL
, NULL
);
1189 if ((GuiData
->Selection
.dwFlags
& CONSOLE_MOUSE_SELECTION
) == 0)
1191 /* Keyboard selection mode */
1192 BOOL Interpreted
= FALSE
;
1193 BOOL MajPressed
= !!(GetKeyState(VK_SHIFT
) & 0x8000);
1195 switch (VirtualKeyCode
)
1200 if (GuiData
->dwSelectionCursor
.X
> 0)
1201 GuiData
->dwSelectionCursor
.X
--;
1209 if (GuiData
->dwSelectionCursor
.X
< ActiveBuffer
->ScreenBufferSize
.X
- 1)
1210 GuiData
->dwSelectionCursor
.X
++;
1218 if (GuiData
->dwSelectionCursor
.Y
> 0)
1219 GuiData
->dwSelectionCursor
.Y
--;
1227 if (GuiData
->dwSelectionCursor
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
- 1)
1228 GuiData
->dwSelectionCursor
.Y
++;
1236 GuiData
->dwSelectionCursor
.X
= 0;
1237 GuiData
->dwSelectionCursor
.Y
= 0;
1244 GuiData
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
1251 GuiData
->dwSelectionCursor
.Y
-= ActiveBuffer
->ViewSize
.Y
;
1252 if (GuiData
->dwSelectionCursor
.Y
< 0)
1253 GuiData
->dwSelectionCursor
.Y
= 0;
1261 GuiData
->dwSelectionCursor
.Y
+= ActiveBuffer
->ViewSize
.Y
;
1262 if (GuiData
->dwSelectionCursor
.Y
>= ActiveBuffer
->ScreenBufferSize
.Y
)
1263 GuiData
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
1274 UpdateSelection(GuiData
,
1275 !MajPressed
? &GuiData
->dwSelectionCursor
: NULL
,
1276 &GuiData
->dwSelectionCursor
);
1278 else if (!IsSystemKey(VirtualKeyCode
))
1280 /* Emit an error beep sound */
1281 SendNotifyMessage(GuiData
->hWindow
, PM_CONSOLE_BEEP
, 0, 0);
1288 /* Mouse selection mode */
1290 if (!IsSystemKey(VirtualKeyCode
))
1292 /* Clear the selection and send the key into the input buffer */
1293 UpdateSelection(GuiData
, NULL
, NULL
);
1302 if ((GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) == 0)
1306 Message
.hwnd
= GuiData
->hWindow
;
1307 Message
.message
= msg
;
1308 Message
.wParam
= wParam
;
1309 Message
.lParam
= lParam
;
1311 ConioProcessKey(Console
, &Message
);
1315 LeaveCriticalSection(&Console
->Lock
);
1319 // FIXME: Remove after fixing OnTimer
1321 InvalidateCell(PGUI_CONSOLE_DATA GuiData
,
1325 OnTimer(PGUI_CONSOLE_DATA GuiData
)
1327 PCONSRV_CONSOLE Console
= GuiData
->Console
;
1328 PCONSOLE_SCREEN_BUFFER Buff
;
1330 /* Do nothing if the window is hidden */
1331 if (!GuiData
->IsWindowVisible
) return;
1333 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CURSOR_BLINK_TIME
, NULL
);
1335 if (!ConDrvValidateConsoleUnsafe((PCONSOLE
)Console
, CONSOLE_RUNNING
, TRUE
)) return;
1337 Buff
= GuiData
->ActiveBuffer
;
1339 if (GetType(Buff
) == TEXTMODE_BUFFER
)
1341 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
1342 Buff
->CursorBlinkOn
= !Buff
->CursorBlinkOn
;
1344 if ((GuiData
->OldCursor
.x
!= Buff
->CursorPosition
.X
) ||
1345 (GuiData
->OldCursor
.y
!= Buff
->CursorPosition
.Y
))
1348 int OldScrollX
= -1, OldScrollY
= -1;
1349 int NewScrollX
= -1, NewScrollY
= -1;
1351 xScroll
.cbSize
= sizeof(SCROLLINFO
);
1352 xScroll
.fMask
= SIF_POS
;
1353 // Capture the original position of the scroll bars and save them.
1354 if (GetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
)) OldScrollX
= xScroll
.nPos
;
1355 if (GetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
)) OldScrollY
= xScroll
.nPos
;
1357 // If we successfully got the info for the horizontal scrollbar
1358 if (OldScrollX
>= 0)
1360 if ((Buff
->CursorPosition
.X
< Buff
->ViewOrigin
.X
) ||
1361 (Buff
->CursorPosition
.X
>= (Buff
->ViewOrigin
.X
+ Buff
->ViewSize
.X
)))
1363 // Handle the horizontal scroll bar
1364 if (Buff
->CursorPosition
.X
>= Buff
->ViewSize
.X
)
1365 NewScrollX
= Buff
->CursorPosition
.X
- Buff
->ViewSize
.X
+ 1;
1371 NewScrollX
= OldScrollX
;
1374 // If we successfully got the info for the vertical scrollbar
1375 if (OldScrollY
>= 0)
1377 if ((Buff
->CursorPosition
.Y
< Buff
->ViewOrigin
.Y
) ||
1378 (Buff
->CursorPosition
.Y
>= (Buff
->ViewOrigin
.Y
+ Buff
->ViewSize
.Y
)))
1380 // Handle the vertical scroll bar
1381 if (Buff
->CursorPosition
.Y
>= Buff
->ViewSize
.Y
)
1382 NewScrollY
= Buff
->CursorPosition
.Y
- Buff
->ViewSize
.Y
+ 1;
1388 NewScrollY
= OldScrollY
;
1392 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
1393 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
1394 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
1395 // and their associated scrollbar is left alone.
1396 if ((OldScrollX
!= NewScrollX
) || (OldScrollY
!= NewScrollY
))
1398 Buff
->ViewOrigin
.X
= NewScrollX
;
1399 Buff
->ViewOrigin
.Y
= NewScrollY
;
1400 ScrollWindowEx(GuiData
->hWindow
,
1401 (OldScrollX
- NewScrollX
) * GuiData
->CharWidth
,
1402 (OldScrollY
- NewScrollY
) * GuiData
->CharHeight
,
1408 if (NewScrollX
>= 0)
1410 xScroll
.nPos
= NewScrollX
;
1411 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
, TRUE
);
1413 if (NewScrollY
>= 0)
1415 xScroll
.nPos
= NewScrollY
;
1416 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
, TRUE
);
1418 UpdateWindow(GuiData
->hWindow
);
1419 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
1420 GuiData
->OldCursor
.x
= Buff
->CursorPosition
.X
;
1421 GuiData
->OldCursor
.y
= Buff
->CursorPosition
.Y
;
1425 else /* if (GetType(Buff) == GRAPHICS_BUFFER) */
1429 LeaveCriticalSection(&Console
->Lock
);
1433 OnClose(PGUI_CONSOLE_DATA GuiData
)
1435 PCONSRV_CONSOLE Console
= GuiData
->Console
;
1437 if (!ConDrvValidateConsoleUnsafe((PCONSOLE
)Console
, CONSOLE_RUNNING
, TRUE
))
1440 // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
1443 * FIXME: Windows will wait up to 5 seconds for the thread to exit.
1444 * We shouldn't wait here, though, since the console lock is entered.
1445 * A copy of the thread list probably needs to be made.
1447 ConSrvConsoleProcessCtrlEvent(Console
, 0, CTRL_CLOSE_EVENT
);
1449 LeaveCriticalSection(&Console
->Lock
);
1454 OnNcDestroy(HWND hWnd
)
1456 PGUI_CONSOLE_DATA GuiData
= GuiGetGuiData(hWnd
);
1458 if (GuiData
->IsWindowVisible
)
1460 KillTimer(hWnd
, CONGUI_UPDATE_TIMER
);
1463 GetSystemMenu(hWnd
, TRUE
);
1467 /* Free the terminal framebuffer */
1468 if (GuiData
->hMemDC
) DeleteDC(GuiData
->hMemDC
);
1469 if (GuiData
->hBitmap
) DeleteObject(GuiData
->hBitmap
);
1470 // if (GuiData->hSysPalette) DeleteObject(GuiData->hSysPalette);
1471 DeleteFonts(GuiData
);
1474 /* Free the GuiData registration */
1475 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (DWORD_PTR
)NULL
);
1477 return DefWindowProcW(hWnd
, WM_NCDESTROY
, 0, 0);
1481 PointToCoord(PGUI_CONSOLE_DATA GuiData
, LPARAM lParam
)
1483 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1485 UINT WidthUnit
, HeightUnit
;
1487 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1489 Coord
.X
= Buffer
->ViewOrigin
.X
+ ((SHORT
)LOWORD(lParam
) / (int)WidthUnit
);
1490 Coord
.Y
= Buffer
->ViewOrigin
.Y
+ ((SHORT
)HIWORD(lParam
) / (int)HeightUnit
);
1492 /* Clip coordinate to ensure it's inside buffer */
1495 else if (Coord
.X
>= Buffer
->ScreenBufferSize
.X
)
1496 Coord
.X
= Buffer
->ScreenBufferSize
.X
- 1;
1500 else if (Coord
.Y
>= Buffer
->ScreenBufferSize
.Y
)
1501 Coord
.Y
= Buffer
->ScreenBufferSize
.Y
- 1;
1507 OnMouse(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1510 PCONSRV_CONSOLE Console
= GuiData
->Console
;
1513 * HACK FOR CORE-8394 (Part 2):
1515 * Check whether we should ignore the next mouse move event.
1516 * In either case we reset the HACK flag.
1518 * See Part 1 of this hack below.
1520 if (GuiData
->HackCORE8394IgnoreNextMove
&& msg
== WM_MOUSEMOVE
)
1522 GuiData
->HackCORE8394IgnoreNextMove
= FALSE
;
1525 GuiData
->HackCORE8394IgnoreNextMove
= FALSE
;
1527 // FIXME: It's here that we need to check whether we have focus or not
1528 // and whether we are or not in edit mode, in order to know if we need
1529 // to deal with the mouse.
1531 if (GuiData
->IgnoreNextMouseSignal
)
1533 if (msg
!= WM_LBUTTONDOWN
&&
1534 msg
!= WM_MBUTTONDOWN
&&
1535 msg
!= WM_RBUTTONDOWN
&&
1536 msg
!= WM_XBUTTONDOWN
)
1539 * If this mouse signal is not a button-down action
1540 * then this is the last one being ignored.
1542 GuiData
->IgnoreNextMouseSignal
= FALSE
;
1547 * This mouse signal is a button-down action.
1548 * Ignore it and perform default action.
1555 if (!ConDrvValidateConsoleUnsafe((PCONSOLE
)Console
, CONSOLE_RUNNING
, TRUE
))
1561 if ( (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) ||
1562 (Console
->QuickEdit
) )
1566 case WM_LBUTTONDOWN
:
1568 /* Clear the old selection */
1569 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
1571 /* Restart a new selection */
1572 GuiData
->dwSelectionCursor
= PointToCoord(GuiData
, lParam
);
1573 SetCapture(GuiData
->hWindow
);
1574 GuiData
->Selection
.dwFlags
|= CONSOLE_MOUSE_SELECTION
| CONSOLE_MOUSE_DOWN
;
1575 UpdateSelection(GuiData
,
1576 &GuiData
->dwSelectionCursor
,
1577 &GuiData
->dwSelectionCursor
);
1584 if (!(GuiData
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1586 // GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
1587 GuiData
->Selection
.dwFlags
&= ~CONSOLE_MOUSE_DOWN
;
1588 // UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
1594 case WM_LBUTTONDBLCLK
:
1596 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1598 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1600 #define IS_WORD_SEP(c) \
1601 ((c) == L'\0' || (c) == L' ' || (c) == L'\t' || (c) == L'\r' || (c) == L'\n')
1603 PTEXTMODE_SCREEN_BUFFER TextBuffer
= (PTEXTMODE_SCREEN_BUFFER
)Buffer
;
1605 PCHAR_INFO ptrL
, ptrR
;
1607 /* Starting point */
1608 cL
= cR
= PointToCoord(GuiData
, lParam
);
1609 ptrL
= ptrR
= ConioCoordToPointer(TextBuffer
, cL
.X
, cL
.Y
);
1611 /* Enlarge the selection by checking for whitespace */
1612 while ((0 < cL
.X
) && !IS_WORD_SEP(ptrL
->Char
.UnicodeChar
)
1613 && !IS_WORD_SEP((ptrL
-1)->Char
.UnicodeChar
))
1618 while ((cR
.X
< TextBuffer
->ScreenBufferSize
.X
- 1) &&
1619 !IS_WORD_SEP(ptrR
->Char
.UnicodeChar
) &&
1620 !IS_WORD_SEP((ptrR
+1)->Char
.UnicodeChar
))
1627 * Update the selection started with the single
1628 * left-click that preceded this double-click.
1630 GuiData
->Selection
.dwFlags
|= CONSOLE_MOUSE_SELECTION
| CONSOLE_MOUSE_DOWN
;
1631 UpdateSelection(GuiData
, &cL
, &cR
);
1633 /* Ignore the next mouse move signal */
1634 GuiData
->IgnoreNextMouseSignal
= TRUE
;
1640 case WM_RBUTTONDOWN
:
1641 case WM_RBUTTONDBLCLK
:
1643 if (!(GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
))
1652 /* Ignore the next mouse move signal */
1653 GuiData
->IgnoreNextMouseSignal
= TRUE
;
1659 if (!(wParam
& MK_LBUTTON
)) break;
1660 if (!(GuiData
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1662 // TODO: Scroll buffer to bring SelectionCursor into view
1663 GuiData
->dwSelectionCursor
= PointToCoord(GuiData
, lParam
);
1664 UpdateSelection(GuiData
, NULL
, &GuiData
->dwSelectionCursor
);
1670 Err
= FALSE
; // TRUE;
1674 else if (Console
->InputBuffer
.Mode
& ENABLE_MOUSE_INPUT
)
1677 WORD wKeyState
= GET_KEYSTATE_WPARAM(wParam
);
1678 DWORD dwButtonState
= 0;
1679 DWORD dwControlKeyState
= 0;
1680 DWORD dwEventFlags
= 0;
1684 case WM_LBUTTONDOWN
:
1685 SetCapture(GuiData
->hWindow
);
1686 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1690 case WM_MBUTTONDOWN
:
1691 SetCapture(GuiData
->hWindow
);
1692 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1696 case WM_RBUTTONDOWN
:
1697 SetCapture(GuiData
->hWindow
);
1698 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1702 case WM_XBUTTONDOWN
:
1704 /* Get which X-button was pressed */
1705 WORD wButton
= GET_XBUTTON_WPARAM(wParam
);
1707 /* Check for X-button validity */
1708 if (wButton
& ~(XBUTTON1
| XBUTTON2
))
1710 DPRINT1("X-button 0x%04x invalid\n", wButton
);
1715 SetCapture(GuiData
->hWindow
);
1716 dwButtonState
= (wButton
== XBUTTON1
? FROM_LEFT_3RD_BUTTON_PRESSED
1717 : FROM_LEFT_4TH_BUTTON_PRESSED
);
1742 /* Get which X-button was released */
1743 WORD wButton
= GET_XBUTTON_WPARAM(wParam
);
1745 /* Check for X-button validity */
1746 if (wButton
& ~(XBUTTON1
| XBUTTON2
))
1748 DPRINT1("X-button 0x%04x invalid\n", wButton
);
1749 /* Ok, just release the button anyway... */
1758 case WM_LBUTTONDBLCLK
:
1759 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1760 dwEventFlags
= DOUBLE_CLICK
;
1763 case WM_MBUTTONDBLCLK
:
1764 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1765 dwEventFlags
= DOUBLE_CLICK
;
1768 case WM_RBUTTONDBLCLK
:
1769 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1770 dwEventFlags
= DOUBLE_CLICK
;
1773 case WM_XBUTTONDBLCLK
:
1775 /* Get which X-button was double-clicked */
1776 WORD wButton
= GET_XBUTTON_WPARAM(wParam
);
1778 /* Check for X-button validity */
1779 if (wButton
& ~(XBUTTON1
| XBUTTON2
))
1781 DPRINT1("X-button 0x%04x invalid\n", wButton
);
1786 dwButtonState
= (wButton
== XBUTTON1
? FROM_LEFT_3RD_BUTTON_PRESSED
1787 : FROM_LEFT_4TH_BUTTON_PRESSED
);
1788 dwEventFlags
= DOUBLE_CLICK
;
1794 dwEventFlags
= MOUSE_MOVED
;
1798 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1799 dwEventFlags
= MOUSE_WHEELED
;
1802 case WM_MOUSEHWHEEL
:
1803 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1804 dwEventFlags
= MOUSE_HWHEELED
;
1813 * HACK FOR CORE-8394 (Part 1):
1815 * It appears that depending on which VM ReactOS runs, the next mouse
1816 * signal coming after a button-down action can be a mouse-move (e.g.
1817 * on VBox, whereas on QEMU it is not the case). However it is NOT a
1818 * rule, so that we cannot use the IgnoreNextMouseSignal flag to just
1819 * "ignore" the next mouse event, thinking it would always be a mouse-
1822 * To work around this problem (that should really be fixed in Win32k),
1823 * we use a second flag to ignore this possible next mouse move signal.
1827 case WM_LBUTTONDOWN
:
1828 case WM_MBUTTONDOWN
:
1829 case WM_RBUTTONDOWN
:
1830 case WM_XBUTTONDOWN
:
1831 GuiData
->HackCORE8394IgnoreNextMove
= TRUE
;
1838 if (wKeyState
& MK_LBUTTON
)
1839 dwButtonState
|= FROM_LEFT_1ST_BUTTON_PRESSED
;
1840 if (wKeyState
& MK_MBUTTON
)
1841 dwButtonState
|= FROM_LEFT_2ND_BUTTON_PRESSED
;
1842 if (wKeyState
& MK_RBUTTON
)
1843 dwButtonState
|= RIGHTMOST_BUTTON_PRESSED
;
1844 if (wKeyState
& MK_XBUTTON1
)
1845 dwButtonState
|= FROM_LEFT_3RD_BUTTON_PRESSED
;
1846 if (wKeyState
& MK_XBUTTON2
)
1847 dwButtonState
|= FROM_LEFT_4TH_BUTTON_PRESSED
;
1849 if (GetKeyState(VK_RMENU
) & 0x8000)
1850 dwControlKeyState
|= RIGHT_ALT_PRESSED
;
1851 if (GetKeyState(VK_LMENU
) & 0x8000)
1852 dwControlKeyState
|= LEFT_ALT_PRESSED
;
1853 if (GetKeyState(VK_RCONTROL
) & 0x8000)
1854 dwControlKeyState
|= RIGHT_CTRL_PRESSED
;
1855 if (GetKeyState(VK_LCONTROL
) & 0x8000)
1856 dwControlKeyState
|= LEFT_CTRL_PRESSED
;
1857 if (GetKeyState(VK_SHIFT
) & 0x8000)
1858 dwControlKeyState
|= SHIFT_PRESSED
;
1859 if (GetKeyState(VK_NUMLOCK
) & 0x0001)
1860 dwControlKeyState
|= NUMLOCK_ON
;
1861 if (GetKeyState(VK_SCROLL
) & 0x0001)
1862 dwControlKeyState
|= SCROLLLOCK_ON
;
1863 if (GetKeyState(VK_CAPITAL
) & 0x0001)
1864 dwControlKeyState
|= CAPSLOCK_ON
;
1865 /* See WM_CHAR MSDN documentation for instance */
1866 if (lParam
& 0x01000000)
1867 dwControlKeyState
|= ENHANCED_KEY
;
1869 /* Send a mouse event */
1870 er
.EventType
= MOUSE_EVENT
;
1871 er
.Event
.MouseEvent
.dwMousePosition
= PointToCoord(GuiData
, lParam
);
1872 er
.Event
.MouseEvent
.dwButtonState
= dwButtonState
;
1873 er
.Event
.MouseEvent
.dwControlKeyState
= dwControlKeyState
;
1874 er
.Event
.MouseEvent
.dwEventFlags
= dwEventFlags
;
1876 ConioProcessInputEvent(Console
, &er
);
1884 LeaveCriticalSection(&Console
->Lock
);
1888 return DefWindowProcW(GuiData
->hWindow
, msg
, wParam
, lParam
);
1894 GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
1895 PGUI_CONSOLE_DATA GuiData
);
1897 GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
1898 PGUI_CONSOLE_DATA GuiData
);
1901 Copy(PGUI_CONSOLE_DATA GuiData
)
1903 if (OpenClipboard(GuiData
->hWindow
))
1905 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1907 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1909 GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
, GuiData
);
1911 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1913 GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
, GuiData
);
1919 /* Clear the selection */
1920 UpdateSelection(GuiData
, NULL
, NULL
);
1924 GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
1925 PGUI_CONSOLE_DATA GuiData
);
1927 GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
1928 PGUI_CONSOLE_DATA GuiData
);
1931 Paste(PGUI_CONSOLE_DATA GuiData
)
1933 if (OpenClipboard(GuiData
->hWindow
))
1935 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1937 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1939 GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
, GuiData
);
1941 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1943 GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
, GuiData
);
1951 OnGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData
, PMINMAXINFO minMaxInfo
)
1953 PCONSRV_CONSOLE Console
= GuiData
->Console
;
1954 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
1956 UINT WidthUnit
, HeightUnit
;
1958 if (!ConDrvValidateConsoleUnsafe((PCONSOLE
)Console
, CONSOLE_RUNNING
, TRUE
)) return;
1960 ActiveBuffer
= GuiData
->ActiveBuffer
;
1962 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1964 windx
= CONGUI_MIN_WIDTH
* WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1965 windy
= CONGUI_MIN_HEIGHT
* HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1967 minMaxInfo
->ptMinTrackSize
.x
= windx
;
1968 minMaxInfo
->ptMinTrackSize
.y
= windy
;
1970 windx
= (ActiveBuffer
->ScreenBufferSize
.X
) * WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1971 windy
= (ActiveBuffer
->ScreenBufferSize
.Y
) * HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1973 if (ActiveBuffer
->ViewSize
.X
< ActiveBuffer
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1974 if (ActiveBuffer
->ViewSize
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1976 minMaxInfo
->ptMaxTrackSize
.x
= windx
;
1977 minMaxInfo
->ptMaxTrackSize
.y
= windy
;
1979 LeaveCriticalSection(&Console
->Lock
);
1983 OnSize(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
1985 PCONSRV_CONSOLE Console
= GuiData
->Console
;
1987 /* Do nothing if the window is hidden */
1988 if (!GuiData
->IsWindowVisible
) return;
1990 if (!ConDrvValidateConsoleUnsafe((PCONSOLE
)Console
, CONSOLE_RUNNING
, TRUE
)) return;
1992 if ((GuiData
->WindowSizeLock
== FALSE
) &&
1993 (wParam
== SIZE_RESTORED
|| wParam
== SIZE_MAXIMIZED
|| wParam
== SIZE_MINIMIZED
))
1995 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
1996 DWORD windx
, windy
, charx
, chary
;
1997 UINT WidthUnit
, HeightUnit
;
1999 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
2001 GuiData
->WindowSizeLock
= TRUE
;
2003 windx
= LOWORD(lParam
);
2004 windy
= HIWORD(lParam
);
2006 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
2007 if (Buff
->ViewSize
.X
< Buff
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
2008 if (Buff
->ViewSize
.Y
< Buff
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
2010 charx
= windx
/ (int)WidthUnit
;
2011 chary
= windy
/ (int)HeightUnit
;
2013 // Character alignment (round size up or down)
2014 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
2015 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
2017 // Compensate for added scroll bars in new window
2018 if (charx
< (DWORD
)Buff
->ScreenBufferSize
.X
) windy
-= GetSystemMetrics(SM_CYHSCROLL
); // new window will have a horizontal scroll bar
2019 if (chary
< (DWORD
)Buff
->ScreenBufferSize
.Y
) windx
-= GetSystemMetrics(SM_CXVSCROLL
); // new window will have a vertical scroll bar
2021 charx
= windx
/ (int)WidthUnit
;
2022 chary
= windy
/ (int)HeightUnit
;
2024 // Character alignment (round size up or down)
2025 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
2026 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
2029 if ((charx
!= Buff
->ViewSize
.X
) || (chary
!= Buff
->ViewSize
.Y
))
2031 Buff
->ViewSize
.X
= (charx
<= (DWORD
)Buff
->ScreenBufferSize
.X
) ? charx
: Buff
->ScreenBufferSize
.X
;
2032 Buff
->ViewSize
.Y
= (chary
<= (DWORD
)Buff
->ScreenBufferSize
.Y
) ? chary
: Buff
->ScreenBufferSize
.Y
;
2035 ResizeConWnd(GuiData
, WidthUnit
, HeightUnit
);
2037 // Adjust the start of the visible area if we are attempting to show nonexistent areas
2038 if ((Buff
->ScreenBufferSize
.X
- Buff
->ViewOrigin
.X
) < Buff
->ViewSize
.X
) Buff
->ViewOrigin
.X
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
2039 if ((Buff
->ScreenBufferSize
.Y
- Buff
->ViewOrigin
.Y
) < Buff
->ViewSize
.Y
) Buff
->ViewOrigin
.Y
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
2040 InvalidateRect(GuiData
->hWindow
, NULL
, TRUE
);
2042 GuiData
->WindowSizeLock
= FALSE
;
2045 LeaveCriticalSection(&Console
->Lock
);
2049 OnMove(PGUI_CONSOLE_DATA GuiData
)
2053 // TODO: Simplify the code.
2054 // See: GuiConsoleNotifyWndProc() PM_CREATE_CONSOLE.
2056 /* Retrieve our real position */
2057 GetWindowRect(GuiData
->hWindow
, &rcWnd
);
2058 GuiData
->GuiInfo
.WindowOrigin
.x
= rcWnd
.left
;
2059 GuiData
->GuiInfo
.WindowOrigin
.y
= rcWnd
.top
;
2063 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
2066 GuiConsoleHandleScrollbarMenu(VOID)
2070 hMenu = CreatePopupMenu();
2073 DPRINT("CreatePopupMenu failed\n");
2077 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
2078 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
2079 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
2080 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
2081 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
2082 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
2083 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
2084 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
2085 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
2086 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
2091 OnScroll(PGUI_CONSOLE_DATA GuiData
, UINT uMsg
, WPARAM wParam
)
2093 PCONSRV_CONSOLE Console
= GuiData
->Console
;
2094 PCONSOLE_SCREEN_BUFFER Buff
;
2097 int old_pos
, Maximum
;
2100 if (!ConDrvValidateConsoleUnsafe((PCONSOLE
)Console
, CONSOLE_RUNNING
, TRUE
)) return 0;
2102 Buff
= GuiData
->ActiveBuffer
;
2104 if (uMsg
== WM_HSCROLL
)
2107 Maximum
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
2108 pShowXY
= &Buff
->ViewOrigin
.X
;
2113 Maximum
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
2114 pShowXY
= &Buff
->ViewOrigin
.Y
;
2117 /* set scrollbar sizes */
2118 sInfo
.cbSize
= sizeof(SCROLLINFO
);
2119 sInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
| SIF_TRACKPOS
;
2121 if (!GetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
)) goto Quit
;
2123 old_pos
= sInfo
.nPos
;
2125 switch (LOWORD(wParam
))
2136 sInfo
.nPos
-= sInfo
.nPage
;
2140 sInfo
.nPos
+= sInfo
.nPage
;
2144 sInfo
.nPos
= sInfo
.nTrackPos
;
2145 ConioPause(Console
, PAUSED_FROM_SCROLLBAR
);
2148 case SB_THUMBPOSITION
:
2149 ConioUnpause(Console
, PAUSED_FROM_SCROLLBAR
);
2153 sInfo
.nPos
= sInfo
.nMin
;
2157 sInfo
.nPos
= sInfo
.nMax
;
2164 sInfo
.nPos
= max(sInfo
.nPos
, 0);
2165 sInfo
.nPos
= min(sInfo
.nPos
, Maximum
);
2167 if (old_pos
!= sInfo
.nPos
)
2169 USHORT OldX
= Buff
->ViewOrigin
.X
;
2170 USHORT OldY
= Buff
->ViewOrigin
.Y
;
2171 UINT WidthUnit
, HeightUnit
;
2173 *pShowXY
= sInfo
.nPos
;
2175 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
2177 ScrollWindowEx(GuiData
->hWindow
,
2178 (OldX
- Buff
->ViewOrigin
.X
) * WidthUnit
,
2179 (OldY
- Buff
->ViewOrigin
.Y
) * HeightUnit
,
2186 sInfo
.fMask
= SIF_POS
;
2187 SetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
, TRUE
);
2189 UpdateWindow(GuiData
->hWindow
);
2190 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
2194 LeaveCriticalSection(&Console
->Lock
);
2199 static LRESULT CALLBACK
2200 ConWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
2203 PGUI_CONSOLE_DATA GuiData
= NULL
;
2204 PCONSRV_CONSOLE Console
= NULL
;
2207 * - If it's the first time we create a window for the terminal,
2208 * just initialize it and return.
2210 * - If we are destroying the window, just do it and return.
2212 if (msg
== WM_NCCREATE
)
2214 return (LRESULT
)OnNcCreate(hWnd
, (LPCREATESTRUCTW
)lParam
);
2216 else if (msg
== WM_NCDESTROY
)
2218 return OnNcDestroy(hWnd
);
2222 * Now the terminal window is initialized.
2223 * Get the terminal data via the window's data.
2224 * If there is no data, just go away.
2226 GuiData
= GuiGetGuiData(hWnd
);
2227 if (GuiData
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2229 // TEMPORARY HACK until all of the functions can deal with a NULL GuiData->ActiveBuffer ...
2230 if (GuiData
->ActiveBuffer
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2233 * Just retrieve a pointer to the console in case somebody needs it.
2234 * It is not NULL because it was checked in GuiGetGuiData.
2235 * Each helper function which needs the console has to validate and lock it.
2237 Console
= GuiData
->Console
;
2239 /* We have a console, start message dispatching */
2243 OnActivate(GuiData
, wParam
);
2247 if (OnClose(GuiData
)) goto Default
;
2258 case WM_PALETTECHANGED
:
2260 DPRINT("WM_PALETTECHANGED called\n");
2263 * Protects against infinite loops:
2264 * "... A window that receives this message must not realize
2265 * its palette, unless it determines that wParam does not contain
2266 * its own window handle." (WM_PALETTECHANGED description - MSDN)
2268 * This message is sent to all windows, including the one that
2269 * changed the system palette and caused this message to be sent.
2270 * The wParam of this message contains the handle of the window
2271 * that caused the system palette to change. To avoid an infinite
2272 * loop, care must be taken to check that the wParam of this message
2273 * does not match the window's handle.
2275 if ((HWND
)wParam
== hWnd
) break;
2277 DPRINT("WM_PALETTECHANGED ok\n");
2278 OnPaletteChanged(GuiData
);
2279 DPRINT("WM_PALETTECHANGED quit\n");
2290 case WM_SYSDEADCHAR
:
2292 /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */
2293 if (msg
== WM_SYSKEYDOWN
&& (HIWORD(lParam
) & KF_ALTDOWN
) && wParam
== VK_RETURN
)
2295 /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */
2296 if ((HIWORD(lParam
) & (KF_UP
| KF_REPEAT
)) != KF_REPEAT
)
2297 GuiConsoleSwitchFullScreen(GuiData
);
2301 /* Detect Alt-Esc/Space/Tab presses defer to DefWindowProc */
2302 if ( (HIWORD(lParam
) & KF_ALTDOWN
) && (wParam
== VK_ESCAPE
|| wParam
== VK_SPACE
|| wParam
== VK_TAB
))
2304 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2307 OnKey(GuiData
, msg
, wParam
, lParam
);
2313 /* Do nothing if the window is hidden */
2314 if (!GuiData
->IsWindowVisible
) goto Default
;
2317 * The message was sent because we are manually triggering a change.
2318 * Check whether the mouse is indeed present on this console window
2319 * and take appropriate decisions.
2321 if (wParam
== -1 && lParam
== -1)
2326 /* Get the placement of the mouse */
2327 GetCursorPos(&mouseCoords
);
2329 /* On which window is placed the mouse ? */
2330 hWndHit
= WindowFromPoint(mouseCoords
);
2332 /* It's our window. Perform the hit-test to be used later on. */
2333 if (hWndHit
== hWnd
)
2335 wParam
= (WPARAM
)hWnd
;
2336 lParam
= DefWindowProcW(hWndHit
, WM_NCHITTEST
, 0,
2337 MAKELPARAM(mouseCoords
.x
, mouseCoords
.y
));
2341 /* Set the mouse cursor only when we are in the client area */
2342 if ((HWND
)wParam
== hWnd
&& LOWORD(lParam
) == HTCLIENT
)
2344 if (GuiData
->MouseCursorRefCount
>= 0)
2346 /* Show the cursor */
2347 SetCursor(GuiData
->hCursor
);
2351 /* Hide the cursor if the reference count is negative */
2362 case WM_LBUTTONDOWN
:
2363 case WM_MBUTTONDOWN
:
2364 case WM_RBUTTONDOWN
:
2365 case WM_XBUTTONDOWN
:
2370 case WM_LBUTTONDBLCLK
:
2371 case WM_MBUTTONDBLCLK
:
2372 case WM_RBUTTONDBLCLK
:
2373 case WM_XBUTTONDBLCLK
:
2376 case WM_MOUSEHWHEEL
:
2378 Result
= OnMouse(GuiData
, msg
, wParam
, lParam
);
2385 Result
= OnScroll(GuiData
, msg
, wParam
);
2389 case WM_CONTEXTMENU
:
2391 /* Do nothing if the window is hidden */
2392 if (!GuiData
->IsWindowVisible
) break;
2394 if (DefWindowProcW(hWnd
/*GuiData->hWindow*/, WM_NCHITTEST
, 0, lParam
) == HTCLIENT
)
2396 HMENU hMenu
= CreatePopupMenu();
2399 AppendMenuItems(hMenu
, GuiConsoleEditMenuItems
);
2400 TrackPopupMenuEx(hMenu
,
2402 GET_X_LPARAM(lParam
),
2403 GET_Y_LPARAM(lParam
),
2418 HMENU hMenu
= (HMENU
)wParam
;
2421 /* Enable or disable the Close menu item */
2422 EnableMenuItem(hMenu
, SC_CLOSE
, MF_BYCOMMAND
|
2423 (GuiData
->IsCloseButtonEnabled
? MF_ENABLED
: MF_GRAYED
));
2425 /* Enable or disable the Copy and Paste items */
2426 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_COPY
, MF_BYCOMMAND
|
2427 ((GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
2428 (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
) ? MF_ENABLED
: MF_GRAYED
));
2429 // FIXME: Following whether the active screen buffer is text-mode
2430 // or graphics-mode, search for CF_UNICODETEXT or CF_BITMAP formats.
2431 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_PASTE
, MF_BYCOMMAND
|
2432 (!(GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
2433 IsClipboardFormatAvailable(CF_UNICODETEXT
) ? MF_ENABLED
: MF_GRAYED
));
2436 SendMenuEvent(Console
, WM_INITMENU
);
2442 if (HIWORD(wParam
) == 0xFFFF) // Allow all the menu flags
2444 SendMenuEvent(Console
, WM_MENUSELECT
);
2452 Result
= OnCommand(GuiData
, wParam
, lParam
);
2458 OnFocus(GuiData
, (msg
== WM_SETFOCUS
));
2461 case WM_GETMINMAXINFO
:
2462 OnGetMinMaxInfo(GuiData
, (PMINMAXINFO
)lParam
);
2469 #if 0 // This code is here to prepare & control dynamic console SB resizing.
2472 PRECT dragRect
= (PRECT
)lParam
;
2476 DPRINT1("WMSZ_LEFT\n");
2479 DPRINT1("WMSZ_RIGHT\n");
2482 DPRINT1("WMSZ_TOP\n");
2485 DPRINT1("WMSZ_TOPLEFT\n");
2488 DPRINT1("WMSZ_TOPRIGHT\n");
2491 DPRINT1("WMSZ_BOTTOM\n");
2493 case WMSZ_BOTTOMLEFT
:
2494 DPRINT1("WMSZ_BOTTOMLEFT\n");
2496 case WMSZ_BOTTOMRIGHT
:
2497 DPRINT1("WMSZ_BOTTOMRIGHT\n");
2500 DPRINT1("wParam = %d\n", wParam
);
2503 DPRINT1("dragRect = {.left = %d ; .top = %d ; .right = %d ; .bottom = %d}\n",
2504 dragRect
->left
, dragRect
->top
, dragRect
->right
, dragRect
->bottom
);
2510 OnSize(GuiData
, wParam
, lParam
);
2513 case PM_RESIZE_TERMINAL
:
2515 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
2519 DWORD Width
, Height
;
2520 UINT WidthUnit
, HeightUnit
;
2522 /* Do nothing if the window is hidden */
2523 if (!GuiData
->IsWindowVisible
) break;
2525 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
2527 Width
= Buff
->ScreenBufferSize
.X
* WidthUnit
;
2528 Height
= Buff
->ScreenBufferSize
.Y
* HeightUnit
;
2530 /* Recreate the framebuffer */
2531 hDC
= GetDC(GuiData
->hWindow
);
2532 hnew
= CreateCompatibleBitmap(hDC
, Width
, Height
);
2533 ReleaseDC(GuiData
->hWindow
, hDC
);
2534 hold
= SelectObject(GuiData
->hMemDC
, hnew
);
2535 if (GuiData
->hBitmap
)
2537 if (hold
== GuiData
->hBitmap
) DeleteObject(GuiData
->hBitmap
);
2539 GuiData
->hBitmap
= hnew
;
2541 /* Resize the window to the user's values */
2542 GuiData
->WindowSizeLock
= TRUE
;
2543 ResizeConWnd(GuiData
, WidthUnit
, HeightUnit
);
2544 GuiData
->WindowSizeLock
= FALSE
;
2549 * Undocumented message sent by Windows' console.dll for applying console info.
2550 * See http://www.catch22.net/sites/default/source/files/setconsoleinfo.c
2551 * and http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf
2552 * for more information.
2554 case WM_SETCONSOLEINFO
:
2556 GuiApplyUserSettings(GuiData
, (HANDLE
)wParam
);
2560 case PM_CONSOLE_BEEP
:
2565 // case PM_CONSOLE_SET_TITLE:
2566 // SetWindowTextW(GuiData->hWindow, GuiData->Console->Title.Buffer);
2570 Result
= DefWindowProcW(hWnd
, msg
, wParam
, lParam
);