2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/frontends/gui/guiterm.c
5 * PURPOSE: GUI Terminal Front-End
9 /* INCLUDES *******************************************************************/
16 #include "guisettings.h"
25 // Define wmemset(...)
30 /* GUI Console Window Class name */
31 #define GUI_CONSOLE_WINDOW_CLASS L"ConsoleWindowClass"
36 #define PM_CREATE_CONSOLE (WM_APP + 1)
37 #define PM_DESTROY_CONSOLE (WM_APP + 2)
38 #define PM_CONSOLE_BEEP (WM_APP + 3)
39 #define PM_CONSOLE_SET_TITLE (WM_APP + 4)
42 /* Not defined in any header file */
43 // extern VOID WINAPI PrivateCsrssManualGuiCheck(LONG Check);
44 // From win32ss/user/win32csr/dllmain.c
47 PrivateCsrssManualGuiCheck(LONG Check
)
49 NtUserCallOneParam(Check
, ONEPARAM_ROUTINE_CSRSS_GUICHECK
);
52 /* GLOBALS ********************************************************************/
54 /**************************************************************\
55 \** Define the Console Leader Process for the console window **/
56 #define GWLP_CONSOLEWND_ALLOC (2 * sizeof(LONG_PTR))
57 #define GWLP_CONSOLE_LEADER_PID 0
58 #define GWLP_CONSOLE_LEADER_TID 4
60 #define SetConsoleWndConsoleLeaderCID(GuiData) \
62 PCONSOLE_PROCESS_DATA ProcessData; \
63 CLIENT_ID ConsoleLeaderCID; \
64 ProcessData = CONTAINING_RECORD((GuiData)->Console->ProcessList.Blink, \
65 CONSOLE_PROCESS_DATA, \
67 ConsoleLeaderCID = ProcessData->Process->ClientId; \
68 SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_PID, (LONG_PTR)(ConsoleLeaderCID.UniqueProcess)); \
69 SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_TID, (LONG_PTR)(ConsoleLeaderCID.UniqueThread )); \
71 /**************************************************************/
73 static BOOL ConsInitialized
= FALSE
;
74 static HICON ghDefaultIcon
= NULL
;
75 static HICON ghDefaultIconSm
= NULL
;
76 static HCURSOR ghDefaultCursor
= NULL
;
77 static HWND NotifyWnd
= NULL
;
79 typedef struct _GUICONSOLE_MENUITEM
82 const struct _GUICONSOLE_MENUITEM
*SubMenu
;
84 } GUICONSOLE_MENUITEM
, *PGUICONSOLE_MENUITEM
;
86 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems
[] =
88 { IDS_MARK
, NULL
, ID_SYSTEM_EDIT_MARK
},
89 { IDS_COPY
, NULL
, ID_SYSTEM_EDIT_COPY
},
90 { IDS_PASTE
, NULL
, ID_SYSTEM_EDIT_PASTE
},
91 { IDS_SELECTALL
, NULL
, ID_SYSTEM_EDIT_SELECTALL
},
92 { IDS_SCROLL
, NULL
, ID_SYSTEM_EDIT_SCROLL
},
93 { IDS_FIND
, NULL
, ID_SYSTEM_EDIT_FIND
},
95 { 0, NULL
, 0 } /* End of list */
98 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems
[] =
100 { IDS_EDIT
, GuiConsoleEditMenuItems
, 0 },
101 { IDS_DEFAULTS
, NULL
, ID_SYSTEM_DEFAULTS
},
102 { IDS_PROPERTIES
, NULL
, ID_SYSTEM_PROPERTIES
},
104 { 0, NULL
, 0 } /* End of list */
108 * Default 16-color palette for foreground and background
109 * (corresponding flags in comments).
111 const COLORREF s_Colors
[16] =
113 RGB(0, 0, 0), // (Black)
114 RGB(0, 0, 128), // BLUE
115 RGB(0, 128, 0), // GREEN
116 RGB(0, 128, 128), // BLUE | GREEN
117 RGB(128, 0, 0), // RED
118 RGB(128, 0, 128), // BLUE | RED
119 RGB(128, 128, 0), // GREEN | RED
120 RGB(192, 192, 192), // BLUE | GREEN | RED
122 RGB(128, 128, 128), // (Grey) INTENSITY
123 RGB(0, 0, 255), // BLUE | INTENSITY
124 RGB(0, 255, 0), // GREEN | INTENSITY
125 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
126 RGB(255, 0, 0), // RED | INTENSITY
127 RGB(255, 0, 255), // BLUE | RED | INTENSITY
128 RGB(255, 255, 0), // GREEN | RED | INTENSITY
129 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
132 /* FUNCTIONS ******************************************************************/
135 GuiConsoleAppendMenuItems(HMENU hMenu
,
136 const GUICONSOLE_MENUITEM
*Items
)
139 WCHAR szMenuString
[255];
144 if (Items
[i
].uID
!= (UINT
)-1)
146 if (LoadStringW(ConSrvDllInstance
,
149 sizeof(szMenuString
) / sizeof(szMenuString
[0])) > 0)
151 if (Items
[i
].SubMenu
!= NULL
)
153 hSubMenu
= CreatePopupMenu();
154 if (hSubMenu
!= NULL
)
156 GuiConsoleAppendMenuItems(hSubMenu
,
159 if (!AppendMenuW(hMenu
,
160 MF_STRING
| MF_POPUP
,
164 DestroyMenu(hSubMenu
);
185 } while(!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
189 GuiConsoleCreateSysMenu(HWND hWnd
)
192 hMenu
= GetSystemMenu(hWnd
, FALSE
);
195 GuiConsoleAppendMenuItems(hMenu
, GuiConsoleMainMenuItems
);
202 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData
);
204 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData
);
206 GuiConsoleUpdateSelection(PCONSOLE Console
, PCOORD coord
);
208 GuiDrawRegion(PCONSOLE Console
, SMALL_RECT
* Region
);
209 static NTSTATUS WINAPI
210 GuiResizeBuffer(PCONSOLE Console
, PCONSOLE_SCREEN_BUFFER ScreenBuffer
, COORD Size
);
212 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData
);
216 GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
219 PCONSOLE Console
= GuiData
->Console
;
221 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
229 case ID_SYSTEM_EDIT_MARK
:
231 LPWSTR WindowTitle
= NULL
;
234 Console
->dwSelectionCursor
= (COORD
){0, 0};
235 Console
->Selection
.dwSelectionAnchor
= Console
->dwSelectionCursor
;
236 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
;
237 GuiConsoleUpdateSelection(Console
, &Console
->Selection
.dwSelectionAnchor
);
239 Length
= Console
->Title
.Length
+ sizeof(L
"Mark - ")/sizeof(WCHAR
) + 1;
240 WindowTitle
= RtlAllocateHeap(ConSrvHeap
, 0, Length
* sizeof(WCHAR
));
241 wcscpy(WindowTitle
, L
"Mark - ");
242 wcscat(WindowTitle
, Console
->Title
.Buffer
);
243 SetWindowText(GuiData
->hWindow
, WindowTitle
);
244 RtlFreeHeap(ConSrvHeap
, 0, WindowTitle
);
249 case ID_SYSTEM_EDIT_COPY
:
250 GuiConsoleCopy(GuiData
);
253 case ID_SYSTEM_EDIT_PASTE
:
254 GuiConsolePaste(GuiData
);
257 case ID_SYSTEM_EDIT_SELECTALL
:
259 Console
->Selection
.dwSelectionAnchor
= (COORD
){0, 0};
260 Console
->dwSelectionCursor
.X
= Console
->ConsoleSize
.X
- 1;
261 Console
->dwSelectionCursor
.Y
= Console
->ConsoleSize
.Y
- 1;
262 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
266 case ID_SYSTEM_EDIT_SCROLL
:
267 DPRINT1("Scrolling is not handled yet\n");
270 case ID_SYSTEM_EDIT_FIND
:
271 DPRINT1("Finding is not handled yet\n");
274 case ID_SYSTEM_DEFAULTS
:
275 GuiConsoleShowConsoleProperties(GuiData
, TRUE
);
278 case ID_SYSTEM_PROPERTIES
:
279 GuiConsoleShowConsoleProperties(GuiData
, FALSE
);
287 LeaveCriticalSection(&Console
->Lock
);
291 Ret
= DefWindowProcW(GuiData
->hWindow
, WM_SYSCOMMAND
, wParam
, lParam
);
296 static PGUI_CONSOLE_DATA
297 GuiGetGuiData(HWND hWnd
)
299 /* This function ensures that the console pointer is not NULL */
300 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
301 return ( ((GuiData
== NULL
) || (GuiData
->hWindow
== hWnd
&& GuiData
->Console
!= NULL
)) ? GuiData
: NULL
);
305 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData
)
307 /* Move the window if needed (not positioned by the system) */
308 if (!GuiData
->GuiInfo
.AutoPosition
)
310 SetWindowPos(GuiData
->hWindow
,
312 GuiData
->GuiInfo
.WindowOrigin
.x
,
313 GuiData
->GuiInfo
.WindowOrigin
.y
,
316 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
321 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData
)
323 PCONSOLE Console
= GuiData
->Console
;
326 DWORD Width
= Console
->ConsoleSize
.X
* GuiData
->CharWidth
+
327 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
328 DWORD Height
= Console
->ConsoleSize
.Y
* GuiData
->CharHeight
+
329 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
331 /* Set scrollbar sizes */
332 sInfo
.cbSize
= sizeof(SCROLLINFO
);
333 sInfo
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
335 if (Console
->ActiveBuffer
->ScreenBufferSize
.Y
> Console
->ConsoleSize
.Y
)
337 sInfo
.nMax
= Console
->ActiveBuffer
->ScreenBufferSize
.Y
- 1;
338 sInfo
.nPage
= Console
->ConsoleSize
.Y
;
339 sInfo
.nPos
= Console
->ActiveBuffer
->ShowY
;
340 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &sInfo
, TRUE
);
341 Width
+= GetSystemMetrics(SM_CXVSCROLL
);
342 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, TRUE
);
346 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, FALSE
);
349 if (Console
->ActiveBuffer
->ScreenBufferSize
.X
> Console
->ConsoleSize
.X
)
351 sInfo
.nMax
= Console
->ActiveBuffer
->ScreenBufferSize
.X
- 1;
352 sInfo
.nPage
= Console
->ConsoleSize
.X
;
353 sInfo
.nPos
= Console
->ActiveBuffer
->ShowX
;
354 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &sInfo
, TRUE
);
355 Height
+= GetSystemMetrics(SM_CYHSCROLL
);
356 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, TRUE
);
360 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, FALSE
);
363 /* Resize the window */
364 SetWindowPos(GuiData
->hWindow
, NULL
, 0, 0, Width
, Height
,
365 SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
);
369 GuiConsoleHandleNcCreate(HWND hWnd
, LPCREATESTRUCTW Create
)
371 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)Create
->lpCreateParams
;
378 DPRINT1("GuiConsoleHandleNcCreate\n");
382 DPRINT1("GuiConsoleNcCreate: No GUI data\n");
386 Console
= GuiData
->Console
;
388 GuiData
->hWindow
= hWnd
;
390 GuiData
->Font
= CreateFontW(LOWORD(GuiData
->GuiInfo
.FontSize
),
391 0, // HIWORD(GuiData->GuiInfo.FontSize),
394 GuiData
->GuiInfo
.FontWeight
,
401 NONANTIALIASED_QUALITY
,
402 FIXED_PITCH
| GuiData
->GuiInfo
.FontFamily
/* FF_DONTCARE */,
403 GuiData
->GuiInfo
.FaceName
);
405 if (NULL
== GuiData
->Font
)
407 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
408 GuiData
->hWindow
= NULL
;
409 SetEvent(GuiData
->hGuiInitEvent
);
412 Dc
= GetDC(GuiData
->hWindow
);
415 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
416 DeleteObject(GuiData
->Font
);
417 GuiData
->hWindow
= NULL
;
418 SetEvent(GuiData
->hGuiInitEvent
);
421 OldFont
= SelectObject(Dc
, GuiData
->Font
);
424 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
425 ReleaseDC(GuiData
->hWindow
, Dc
);
426 DeleteObject(GuiData
->Font
);
427 GuiData
->hWindow
= NULL
;
428 SetEvent(GuiData
->hGuiInitEvent
);
431 if (!GetTextMetricsW(Dc
, &Metrics
))
433 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
434 SelectObject(Dc
, OldFont
);
435 ReleaseDC(GuiData
->hWindow
, Dc
);
436 DeleteObject(GuiData
->Font
);
437 GuiData
->hWindow
= NULL
;
438 SetEvent(GuiData
->hGuiInitEvent
);
441 GuiData
->CharWidth
= Metrics
.tmMaxCharWidth
;
442 GuiData
->CharHeight
= Metrics
.tmHeight
+ Metrics
.tmExternalLeading
;
444 /* Measure real char width more precisely if possible. */
445 if (GetTextExtentPoint32W(Dc
, L
"R", 1, &CharSize
))
446 GuiData
->CharWidth
= CharSize
.cx
;
448 SelectObject(Dc
, OldFont
);
450 ReleaseDC(GuiData
->hWindow
, Dc
);
452 // FIXME: Keep these instructions here ? ///////////////////////////////////
453 Console
->ActiveBuffer
->CursorBlinkOn
= TRUE
;
454 Console
->ActiveBuffer
->ForceCursorOff
= FALSE
;
455 ////////////////////////////////////////////////////////////////////////////
457 SetWindowLongPtrW(GuiData
->hWindow
, GWLP_USERDATA
, (DWORD_PTR
)GuiData
);
459 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
460 GuiConsoleCreateSysMenu(GuiData
->hWindow
);
462 DPRINT1("GuiConsoleHandleNcCreate - setting start event\n");
463 SetEvent(GuiData
->hGuiInitEvent
);
465 return (BOOL
)DefWindowProcW(GuiData
->hWindow
, WM_NCCREATE
, 0, (LPARAM
)Create
);
469 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
471 PCONSOLE Console
= GuiData
->Console
;
472 PCONSOLE_SCREEN_BUFFER Buffer
= Console
->ActiveBuffer
;
474 Rect
->left
= (SmallRect
->Left
- Buffer
->ShowX
) * GuiData
->CharWidth
;
475 Rect
->top
= (SmallRect
->Top
- Buffer
->ShowY
) * GuiData
->CharHeight
;
476 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ShowX
) * GuiData
->CharWidth
;
477 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ShowY
) * GuiData
->CharHeight
;
481 GuiConsoleUpdateSelection(PCONSOLE Console
, PCOORD coord
)
483 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
484 RECT oldRect
, newRect
;
486 SmallRectToRect(GuiData
, &oldRect
, &Console
->Selection
.srSelection
);
491 /* exchange left/top with right/bottom if required */
492 rc
.Left
= min(Console
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
493 rc
.Top
= min(Console
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
494 rc
.Right
= max(Console
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
495 rc
.Bottom
= max(Console
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
497 SmallRectToRect(GuiData
, &newRect
, &rc
);
499 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
501 if (memcmp(&rc
, &Console
->Selection
.srSelection
, sizeof(SMALL_RECT
)) != 0)
505 /* calculate the region that needs to be updated */
506 if ((rgn1
= CreateRectRgnIndirect(&oldRect
)))
508 if ((rgn2
= CreateRectRgnIndirect(&newRect
)))
510 if(CombineRgn(rgn1
, rgn2
, rgn1
, RGN_XOR
) != ERROR
)
512 InvalidateRgn(GuiData
->hWindow
, rgn1
, FALSE
);
522 InvalidateRect(GuiData
->hWindow
, &newRect
, FALSE
);
524 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_NOT_EMPTY
;
525 Console
->Selection
.srSelection
= rc
;
526 Console
->dwSelectionCursor
= *coord
;
527 ConioPause(Console
, PAUSED_FROM_SELECTION
);
531 /* clear the selection */
532 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
534 InvalidateRect(GuiData
->hWindow
, &oldRect
, FALSE
);
536 Console
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
537 ConioUnpause(Console
, PAUSED_FROM_SELECTION
);
542 GuiConsolePaint(PCONSOLE Console
,
543 PGUI_CONSOLE_DATA GuiData
,
547 PCONSOLE_SCREEN_BUFFER Buff
;
548 ULONG TopLine
, BottomLine
, LeftChar
, RightChar
;
549 ULONG Line
, Char
, Start
;
552 BYTE LastAttribute
, Attribute
;
553 ULONG CursorX
, CursorY
, CursorHeight
;
554 HBRUSH CursorBrush
, OldBrush
;
557 Buff
= Console
->ActiveBuffer
;
559 TopLine
= rc
->top
/ GuiData
->CharHeight
+ Buff
->ShowY
;
560 BottomLine
= (rc
->bottom
+ (GuiData
->CharHeight
- 1)) / GuiData
->CharHeight
- 1 + Buff
->ShowY
;
561 LeftChar
= rc
->left
/ GuiData
->CharWidth
+ Buff
->ShowX
;
562 RightChar
= (rc
->right
+ (GuiData
->CharWidth
- 1)) / GuiData
->CharWidth
- 1 + Buff
->ShowX
;
563 LastAttribute
= ConioCoordToPointer(Buff
, LeftChar
, TopLine
)[1];
565 SetTextColor(hDC
, RGBFromAttrib(Console
, TextAttribFromAttrib(LastAttribute
)));
566 SetBkColor(hDC
, RGBFromAttrib(Console
, BkgdAttribFromAttrib(LastAttribute
)));
568 if (BottomLine
>= Buff
->ScreenBufferSize
.Y
) BottomLine
= Buff
->ScreenBufferSize
.Y
- 1;
569 if (RightChar
>= Buff
->ScreenBufferSize
.X
) RightChar
= Buff
->ScreenBufferSize
.X
- 1;
571 OldFont
= SelectObject(hDC
, GuiData
->Font
);
573 for (Line
= TopLine
; Line
<= BottomLine
; Line
++)
575 WCHAR LineBuffer
[80];
576 From
= ConioCoordToPointer(Buff
, LeftChar
, Line
);
580 for (Char
= LeftChar
; Char
<= RightChar
; Char
++)
582 if (*(From
+ 1) != LastAttribute
|| (Char
- Start
== sizeof(LineBuffer
) / sizeof(WCHAR
)))
585 (Start
- Buff
->ShowX
) * GuiData
->CharWidth
,
586 (Line
- Buff
->ShowY
) * GuiData
->CharHeight
,
591 Attribute
= *(From
+ 1);
592 if (Attribute
!= LastAttribute
)
594 SetTextColor(hDC
, RGBFromAttrib(Console
, TextAttribFromAttrib(Attribute
)));
595 SetBkColor(hDC
, RGBFromAttrib(Console
, BkgdAttribFromAttrib(Attribute
)));
596 LastAttribute
= Attribute
;
600 MultiByteToWideChar(Console
->OutputCodePage
,
611 (Start
- Buff
->ShowX
) * GuiData
->CharWidth
,
612 (Line
- Buff
->ShowY
) * GuiData
->CharHeight
,
614 RightChar
- Start
+ 1);
617 if (Buff
->CursorInfo
.bVisible
&& Buff
->CursorBlinkOn
&&
618 !Buff
->ForceCursorOff
)
620 CursorX
= Buff
->CursorPosition
.X
;
621 CursorY
= Buff
->CursorPosition
.Y
;
622 if (LeftChar
<= CursorX
&& CursorX
<= RightChar
&&
623 TopLine
<= CursorY
&& CursorY
<= BottomLine
)
625 CursorHeight
= ConioEffectiveCursorSize(Console
, GuiData
->CharHeight
);
626 From
= ConioCoordToPointer(Buff
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
) + 1;
628 if (*From
!= DEFAULT_SCREEN_ATTRIB
)
630 CursorBrush
= CreateSolidBrush(RGBFromAttrib(Console
, *From
));
634 CursorBrush
= CreateSolidBrush(RGBFromAttrib(Console
, Buff
->ScreenDefaultAttrib
));
637 OldBrush
= SelectObject(hDC
, CursorBrush
);
639 (CursorX
- Buff
->ShowX
) * GuiData
->CharWidth
,
640 (CursorY
- Buff
->ShowY
) * GuiData
->CharHeight
+ (GuiData
->CharHeight
- CursorHeight
),
644 SelectObject(hDC
, OldBrush
);
645 DeleteObject(CursorBrush
);
649 SelectObject(hDC
, OldFont
);
653 GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData
)
656 PCONSOLE Console
= GuiData
->Console
;
660 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
666 if (Console
->ActiveBuffer
== NULL
||
667 Console
->ActiveBuffer
->Buffer
== NULL
)
672 hDC
= BeginPaint(GuiData
->hWindow
, &ps
);
674 ps
.rcPaint
.left
< ps
.rcPaint
.right
&&
675 ps
.rcPaint
.top
< ps
.rcPaint
.bottom
)
677 EnterCriticalSection(&GuiData
->Lock
);
679 GuiConsolePaint(Console
,
684 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
687 SmallRectToRect(GuiData
, &rc
, &Console
->Selection
.srSelection
);
689 /* invert the selection */
690 if (IntersectRect(&rc
,
703 LeaveCriticalSection(&GuiData
->Lock
);
705 EndPaint(GuiData
->hWindow
, &ps
);
709 LeaveCriticalSection(&Console
->Lock
);
711 DefWindowProcW(GuiData
->hWindow
, WM_PAINT
, 0, 0);
717 GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
719 PCONSOLE Console
= GuiData
->Console
;
722 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
724 if ( (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
725 ((Console
->Selection
.dwFlags
& CONSOLE_MOUSE_SELECTION
) == 0) &&
726 (Console
->ActiveBuffer
) )
728 BOOL Interpreted
= FALSE
;
730 /* Selection with keyboard */
731 if (msg
== WM_KEYDOWN
)
733 BOOL MajPressed
= (GetKeyState(VK_SHIFT
) & 0x8000);
740 if (Console
->dwSelectionCursor
.X
> 0)
741 Console
->dwSelectionCursor
.X
--;
749 if (Console
->dwSelectionCursor
.X
< Console
->ActiveBuffer
->ScreenBufferSize
.X
- 1)
750 Console
->dwSelectionCursor
.X
++;
758 if (Console
->dwSelectionCursor
.Y
> 0)
759 Console
->dwSelectionCursor
.Y
--;
767 if (Console
->dwSelectionCursor
.Y
< Console
->ActiveBuffer
->ScreenBufferSize
.Y
- 1)
768 Console
->dwSelectionCursor
.Y
++;
776 Console
->dwSelectionCursor
= (COORD
){0, 0};
783 Console
->dwSelectionCursor
.Y
= Console
->ActiveBuffer
->ScreenBufferSize
.Y
- 1;
790 Console
->dwSelectionCursor
.Y
-= Console
->ConsoleSize
.Y
;
791 if (Console
->dwSelectionCursor
.Y
< 0)
792 Console
->dwSelectionCursor
.Y
= 0;
800 Console
->dwSelectionCursor
.Y
+= Console
->ConsoleSize
.Y
;
801 if (Console
->dwSelectionCursor
.Y
>= Console
->ActiveBuffer
->ScreenBufferSize
.Y
)
802 Console
->dwSelectionCursor
.Y
= Console
->ActiveBuffer
->ScreenBufferSize
.Y
- 1;
814 Console
->Selection
.dwSelectionAnchor
= Console
->dwSelectionCursor
;
816 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
822 Message
.hwnd
= GuiData
->hWindow
;
823 Message
.message
= msg
;
824 Message
.wParam
= wParam
;
825 Message
.lParam
= lParam
;
827 if (msg
== WM_KEYDOWN
)
829 /* If we are in selection mode (with mouse), clear the selection */
830 GuiConsoleUpdateSelection(Console
, NULL
);
831 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
834 ConioProcessKey(Console
, &Message
);
837 LeaveCriticalSection(&Console
->Lock
);
841 GuiInvalidateCell(PCONSOLE Console
, UINT x
, UINT y
)
843 SMALL_RECT CellRect
= { x
, y
, x
, y
};
844 GuiDrawRegion(Console
, &CellRect
);
848 GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData
)
850 PCONSOLE Console
= GuiData
->Console
;
851 PCONSOLE_SCREEN_BUFFER Buff
;
853 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CURSOR_BLINK_TIME
, NULL
);
855 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
857 Buff
= Console
->ActiveBuffer
;
858 GuiInvalidateCell(Console
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
859 Buff
->CursorBlinkOn
= !Buff
->CursorBlinkOn
;
861 if((GuiData
->OldCursor
.x
!= Buff
->CursorPosition
.X
) || (GuiData
->OldCursor
.y
!= Buff
->CursorPosition
.Y
))
864 int OldScrollX
= -1, OldScrollY
= -1;
865 int NewScrollX
= -1, NewScrollY
= -1;
867 xScroll
.cbSize
= sizeof(SCROLLINFO
);
868 xScroll
.fMask
= SIF_POS
;
869 // Capture the original position of the scroll bars and save them.
870 if(GetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
))OldScrollX
= xScroll
.nPos
;
871 if(GetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
))OldScrollY
= xScroll
.nPos
;
873 // If we successfully got the info for the horizontal scrollbar
876 if((Buff
->CursorPosition
.X
< Buff
->ShowX
)||(Buff
->CursorPosition
.X
>= (Buff
->ShowX
+ Console
->ConsoleSize
.X
)))
878 // Handle the horizontal scroll bar
879 if(Buff
->CursorPosition
.X
>= Console
->ConsoleSize
.X
) NewScrollX
= Buff
->CursorPosition
.X
- Console
->ConsoleSize
.X
+ 1;
884 NewScrollX
= OldScrollX
;
887 // If we successfully got the info for the vertical scrollbar
890 if((Buff
->CursorPosition
.Y
< Buff
->ShowY
) || (Buff
->CursorPosition
.Y
>= (Buff
->ShowY
+ Console
->ConsoleSize
.Y
)))
892 // Handle the vertical scroll bar
893 if(Buff
->CursorPosition
.Y
>= Console
->ConsoleSize
.Y
) NewScrollY
= Buff
->CursorPosition
.Y
- Console
->ConsoleSize
.Y
+ 1;
898 NewScrollY
= OldScrollY
;
902 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
903 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
904 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
905 // and their associated scrollbar is left alone.
906 if((OldScrollX
!= NewScrollX
) || (OldScrollY
!= NewScrollY
))
908 Buff
->ShowX
= NewScrollX
;
909 Buff
->ShowY
= NewScrollY
;
910 ScrollWindowEx(GuiData
->hWindow
,
911 (OldScrollX
- NewScrollX
) * GuiData
->CharWidth
,
912 (OldScrollY
- NewScrollY
) * GuiData
->CharHeight
,
920 xScroll
.nPos
= NewScrollX
;
921 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
, TRUE
);
925 xScroll
.nPos
= NewScrollY
;
926 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
, TRUE
);
928 UpdateWindow(GuiData
->hWindow
);
929 GuiData
->OldCursor
.x
= Buff
->CursorPosition
.X
;
930 GuiData
->OldCursor
.y
= Buff
->CursorPosition
.Y
;
934 LeaveCriticalSection(&Console
->Lock
);
938 GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData
)
940 PCONSOLE Console
= GuiData
->Console
;
941 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
944 * FIXME: Windows will wait up to 5 seconds for the thread to exit.
945 * We shouldn't wait here, though, since the console lock is entered.
946 * A copy of the thread list probably needs to be made.
948 ConSrvConsoleProcessCtrlEvent(Console
, 0, CTRL_CLOSE_EVENT
);
950 LeaveCriticalSection(&Console
->Lock
);
954 GuiConsoleHandleNcDestroy(HWND hWnd
)
956 // PGUI_CONSOLE_DATA GuiData;
958 KillTimer(hWnd
, CONGUI_UPDATE_TIMER
);
959 GetSystemMenu(hWnd
, TRUE
);
961 /* Free the GuiData registration */
962 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (DWORD_PTR
)NULL
);
963 // GuiData->hWindow = NULL;
966 return DefWindowProcW(hWnd
, WM_NCDESTROY
, 0, 0);
970 PointToCoord(PGUI_CONSOLE_DATA GuiData
, LPARAM lParam
)
972 PCONSOLE Console
= GuiData
->Console
;
973 PCONSOLE_SCREEN_BUFFER Buffer
= Console
->ActiveBuffer
;
976 Coord
.X
= Buffer
->ShowX
+ ((short)LOWORD(lParam
) / (int)GuiData
->CharWidth
);
977 Coord
.Y
= Buffer
->ShowY
+ ((short)HIWORD(lParam
) / (int)GuiData
->CharHeight
);
979 /* Clip coordinate to ensure it's inside buffer */
982 else if (Coord
.X
>= Buffer
->ScreenBufferSize
.X
)
983 Coord
.X
= Buffer
->ScreenBufferSize
.X
- 1;
987 else if (Coord
.Y
>= Buffer
->ScreenBufferSize
.Y
)
988 Coord
.Y
= Buffer
->ScreenBufferSize
.Y
- 1;
994 GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
997 PCONSOLE Console
= GuiData
->Console
;
999 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1005 if ( (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) ||
1006 (Console
->QuickEdit
) )
1010 case WM_LBUTTONDOWN
:
1012 LPWSTR WindowTitle
= NULL
;
1015 Console
->Selection
.dwSelectionAnchor
= PointToCoord(GuiData
, lParam
);
1016 SetCapture(GuiData
->hWindow
);
1017 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
| CONSOLE_MOUSE_SELECTION
| CONSOLE_MOUSE_DOWN
;
1018 GuiConsoleUpdateSelection(Console
, &Console
->Selection
.dwSelectionAnchor
);
1020 Length
= Console
->Title
.Length
+ sizeof(L
"Selection - ")/sizeof(WCHAR
) + 1;
1021 WindowTitle
= RtlAllocateHeap(ConSrvHeap
, 0, Length
* sizeof(WCHAR
));
1022 wcscpy(WindowTitle
, L
"Selection - ");
1023 wcscat(WindowTitle
, Console
->Title
.Buffer
);
1024 SetWindowText(GuiData
->hWindow
, WindowTitle
);
1025 RtlFreeHeap(ConSrvHeap
, 0, WindowTitle
);
1034 if (!(Console
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1036 c
= PointToCoord(GuiData
, lParam
);
1037 Console
->Selection
.dwFlags
&= ~CONSOLE_MOUSE_DOWN
;
1038 GuiConsoleUpdateSelection(Console
, &c
);
1044 case WM_RBUTTONDOWN
:
1046 if (!(Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
))
1048 GuiConsolePaste(GuiData
);
1052 GuiConsoleCopy(GuiData
);
1054 /* Clear the selection */
1055 GuiConsoleUpdateSelection(Console
, NULL
);
1056 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
1066 if (!(wParam
& MK_LBUTTON
)) break;
1067 if (!(Console
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1069 c
= PointToCoord(GuiData
, lParam
); /* TODO: Scroll buffer to bring c into view */
1070 GuiConsoleUpdateSelection(Console
, &c
);
1080 else if (Console
->InputBuffer
.Mode
& ENABLE_MOUSE_INPUT
)
1083 WORD wKeyState
= GET_KEYSTATE_WPARAM(wParam
);
1084 DWORD dwButtonState
= 0;
1085 DWORD dwControlKeyState
= 0;
1086 DWORD dwEventFlags
= 0;
1090 case WM_LBUTTONDOWN
:
1091 SetCapture(GuiData
->hWindow
);
1092 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1096 case WM_MBUTTONDOWN
:
1097 SetCapture(GuiData
->hWindow
);
1098 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1102 case WM_RBUTTONDOWN
:
1103 SetCapture(GuiData
->hWindow
);
1104 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1126 case WM_LBUTTONDBLCLK
:
1127 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1128 dwEventFlags
= DOUBLE_CLICK
;
1131 case WM_MBUTTONDBLCLK
:
1132 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1133 dwEventFlags
= DOUBLE_CLICK
;
1136 case WM_RBUTTONDBLCLK
:
1137 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1138 dwEventFlags
= DOUBLE_CLICK
;
1143 dwEventFlags
= MOUSE_MOVED
;
1147 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1148 dwEventFlags
= MOUSE_WHEELED
;
1151 case WM_MOUSEHWHEEL
:
1152 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1153 dwEventFlags
= MOUSE_HWHEELED
;
1163 if (wKeyState
& MK_LBUTTON
)
1164 dwButtonState
|= FROM_LEFT_1ST_BUTTON_PRESSED
;
1165 if (wKeyState
& MK_MBUTTON
)
1166 dwButtonState
|= FROM_LEFT_2ND_BUTTON_PRESSED
;
1167 if (wKeyState
& MK_RBUTTON
)
1168 dwButtonState
|= RIGHTMOST_BUTTON_PRESSED
;
1170 if (GetKeyState(VK_RMENU
) & 0x8000)
1171 dwControlKeyState
|= RIGHT_ALT_PRESSED
;
1172 if (GetKeyState(VK_LMENU
) & 0x8000)
1173 dwControlKeyState
|= LEFT_ALT_PRESSED
;
1174 if (GetKeyState(VK_RCONTROL
) & 0x8000)
1175 dwControlKeyState
|= RIGHT_CTRL_PRESSED
;
1176 if (GetKeyState(VK_LCONTROL
) & 0x8000)
1177 dwControlKeyState
|= LEFT_CTRL_PRESSED
;
1178 if (GetKeyState(VK_SHIFT
) & 0x8000)
1179 dwControlKeyState
|= SHIFT_PRESSED
;
1180 if (GetKeyState(VK_NUMLOCK
) & 0x0001)
1181 dwControlKeyState
|= NUMLOCK_ON
;
1182 if (GetKeyState(VK_SCROLL
) & 0x0001)
1183 dwControlKeyState
|= SCROLLLOCK_ON
;
1184 if (GetKeyState(VK_CAPITAL
) & 0x0001)
1185 dwControlKeyState
|= CAPSLOCK_ON
;
1186 /* See WM_CHAR MSDN documentation for instance */
1187 if (lParam
& 0x01000000)
1188 dwControlKeyState
|= ENHANCED_KEY
;
1190 er
.EventType
= MOUSE_EVENT
;
1191 er
.Event
.MouseEvent
.dwMousePosition
= PointToCoord(GuiData
, lParam
);
1192 er
.Event
.MouseEvent
.dwButtonState
= dwButtonState
;
1193 er
.Event
.MouseEvent
.dwControlKeyState
= dwControlKeyState
;
1194 er
.Event
.MouseEvent
.dwEventFlags
= dwEventFlags
;
1196 ConioProcessInputEvent(Console
, &er
);
1204 LeaveCriticalSection(&Console
->Lock
);
1208 return DefWindowProcW(GuiData
->hWindow
, msg
, wParam
, lParam
);
1214 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData
)
1216 PCONSOLE Console
= GuiData
->Console
;
1218 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1223 ULONG selWidth
, selHeight
;
1224 ULONG xPos
, yPos
, size
;
1226 selWidth
= Console
->Selection
.srSelection
.Right
- Console
->Selection
.srSelection
.Left
+ 1;
1227 selHeight
= Console
->Selection
.srSelection
.Bottom
- Console
->Selection
.srSelection
.Top
+ 1;
1228 DPRINT("Selection is (%d|%d) to (%d|%d)\n",
1229 Console
->Selection
.srSelection
.Left
,
1230 Console
->Selection
.srSelection
.Top
,
1231 Console
->Selection
.srSelection
.Right
,
1232 Console
->Selection
.srSelection
.Bottom
);
1234 /* Basic size for one line and termination */
1235 size
= selWidth
+ 1;
1238 /* Multiple line selections have to get \r\n appended */
1239 size
+= ((selWidth
+ 2) * (selHeight
- 1));
1242 /* Allocate memory, it will be passed to the system and may not be freed here */
1243 hData
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_ZEROINIT
, size
);
1249 data
= GlobalLock(hData
);
1256 DPRINT("Copying %dx%d selection\n", selWidth
, selHeight
);
1259 for (yPos
= 0; yPos
< selHeight
; yPos
++)
1261 ptr
= ConioCoordToPointer(Console
->ActiveBuffer
,
1262 Console
->Selection
.srSelection
.Left
,
1263 yPos
+ Console
->Selection
.srSelection
.Top
);
1264 /* Copy only the characters, leave attributes alone */
1265 for (xPos
= 0; xPos
< selWidth
; xPos
++)
1267 dstPos
[xPos
] = ptr
[xPos
* 2];
1270 if (yPos
!= (selHeight
- 1))
1272 strcat(data
, "\r\n");
1277 DPRINT("Setting data <%s> to clipboard\n", data
);
1278 GlobalUnlock(hData
);
1281 SetClipboardData(CF_TEXT
, hData
);
1287 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData
)
1289 PCONSOLE Console
= GuiData
->Console
;
1291 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1297 hData
= GetClipboardData(CF_TEXT
);
1304 str
= GlobalLock(hData
);
1310 DPRINT("Got data <%s> from clipboard\n", str
);
1313 // TODO: Push the text into the input buffer.
1314 ConioWriteConsole(Console
, Console
->ActiveBuffer
, str
, len
, TRUE
);
1316 GlobalUnlock(hData
);
1322 GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData
, PMINMAXINFO minMaxInfo
)
1324 PCONSOLE Console
= GuiData
->Console
;
1327 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1329 windx
= CONGUI_MIN_WIDTH
* GuiData
->CharWidth
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1330 windy
= CONGUI_MIN_HEIGHT
* GuiData
->CharHeight
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1332 minMaxInfo
->ptMinTrackSize
.x
= windx
;
1333 minMaxInfo
->ptMinTrackSize
.y
= windy
;
1335 windx
= (Console
->ActiveBuffer
->ScreenBufferSize
.X
) * GuiData
->CharWidth
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1336 windy
= (Console
->ActiveBuffer
->ScreenBufferSize
.Y
) * GuiData
->CharHeight
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1338 if(Console
->ConsoleSize
.X
< Console
->ActiveBuffer
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1339 if(Console
->ConsoleSize
.Y
< Console
->ActiveBuffer
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1341 minMaxInfo
->ptMaxTrackSize
.x
= windx
;
1342 minMaxInfo
->ptMaxTrackSize
.y
= windy
;
1344 LeaveCriticalSection(&Console
->Lock
);
1348 GuiConsoleResize(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
1350 PCONSOLE Console
= GuiData
->Console
;
1352 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1354 if ((GuiData
->WindowSizeLock
== FALSE
) &&
1355 (wParam
== SIZE_RESTORED
|| wParam
== SIZE_MAXIMIZED
|| wParam
== SIZE_MINIMIZED
))
1357 PCONSOLE_SCREEN_BUFFER Buff
= Console
->ActiveBuffer
;
1358 DWORD windx
, windy
, charx
, chary
;
1360 GuiData
->WindowSizeLock
= TRUE
;
1362 windx
= LOWORD(lParam
);
1363 windy
= HIWORD(lParam
);
1365 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
1366 if(Console
->ConsoleSize
.X
< Buff
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1367 if(Console
->ConsoleSize
.Y
< Buff
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1369 charx
= windx
/ GuiData
->CharWidth
;
1370 chary
= windy
/ GuiData
->CharHeight
;
1372 // Character alignment (round size up or down)
1373 if((windx
% GuiData
->CharWidth
) >= (GuiData
->CharWidth
/ 2)) ++charx
;
1374 if((windy
% GuiData
->CharHeight
) >= (GuiData
->CharHeight
/ 2)) ++chary
;
1376 // Compensate for added scroll bars in new window
1377 if(charx
< Buff
->ScreenBufferSize
.X
)windy
-= GetSystemMetrics(SM_CYHSCROLL
); // new window will have a horizontal scroll bar
1378 if(chary
< Buff
->ScreenBufferSize
.Y
)windx
-= GetSystemMetrics(SM_CXVSCROLL
); // new window will have a vertical scroll bar
1380 charx
= windx
/ GuiData
->CharWidth
;
1381 chary
= windy
/ GuiData
->CharHeight
;
1383 // Character alignment (round size up or down)
1384 if((windx
% GuiData
->CharWidth
) >= (GuiData
->CharWidth
/ 2)) ++charx
;
1385 if((windy
% GuiData
->CharHeight
) >= (GuiData
->CharHeight
/ 2)) ++chary
;
1388 if((charx
!= Console
->ConsoleSize
.X
) || (chary
!= Console
->ConsoleSize
.Y
))
1390 Console
->ConsoleSize
.X
= (charx
<= Buff
->ScreenBufferSize
.X
) ? charx
: Buff
->ScreenBufferSize
.X
;
1391 Console
->ConsoleSize
.Y
= (chary
<= Buff
->ScreenBufferSize
.Y
) ? chary
: Buff
->ScreenBufferSize
.Y
;
1394 GuiConsoleResizeWindow(GuiData
);
1396 // Adjust the start of the visible area if we are attempting to show nonexistent areas
1397 if((Buff
->ScreenBufferSize
.X
- Buff
->ShowX
) < Console
->ConsoleSize
.X
) Buff
->ShowX
= Buff
->ScreenBufferSize
.X
- Console
->ConsoleSize
.X
;
1398 if((Buff
->ScreenBufferSize
.Y
- Buff
->ShowY
) < Console
->ConsoleSize
.Y
) Buff
->ShowY
= Buff
->ScreenBufferSize
.Y
- Console
->ConsoleSize
.Y
;
1399 InvalidateRect(GuiData
->hWindow
, NULL
, TRUE
);
1401 GuiData
->WindowSizeLock
= FALSE
;
1404 LeaveCriticalSection(&Console
->Lock
);
1408 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
1412 GuiConsoleHandleScrollbarMenu(VOID)
1416 hMenu = CreatePopupMenu();
1419 DPRINT("CreatePopupMenu failed\n");
1423 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1424 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1425 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1426 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1427 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1428 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1429 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1430 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1431 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1432 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1437 GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData
, UINT uMsg
, WPARAM wParam
)
1439 PCONSOLE Console
= GuiData
->Console
;
1440 PCONSOLE_SCREEN_BUFFER Buff
;
1443 int old_pos
, Maximum
;
1446 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return 0;
1448 Buff
= Console
->ActiveBuffer
;
1450 if (uMsg
== WM_HSCROLL
)
1453 Maximum
= Buff
->ScreenBufferSize
.X
- Console
->ConsoleSize
.X
;
1454 pShowXY
= &Buff
->ShowX
;
1459 Maximum
= Buff
->ScreenBufferSize
.Y
- Console
->ConsoleSize
.Y
;
1460 pShowXY
= &Buff
->ShowY
;
1463 /* set scrollbar sizes */
1464 sInfo
.cbSize
= sizeof(SCROLLINFO
);
1465 sInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
| SIF_TRACKPOS
;
1467 if (!GetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
)) goto Quit
;
1469 old_pos
= sInfo
.nPos
;
1471 switch (LOWORD(wParam
))
1482 sInfo
.nPos
-= sInfo
.nPage
;
1486 sInfo
.nPos
+= sInfo
.nPage
;
1490 sInfo
.nPos
= sInfo
.nTrackPos
;
1491 ConioPause(Console
, PAUSED_FROM_SCROLLBAR
);
1494 case SB_THUMBPOSITION
:
1495 ConioUnpause(Console
, PAUSED_FROM_SCROLLBAR
);
1499 sInfo
.nPos
= sInfo
.nMin
;
1503 sInfo
.nPos
= sInfo
.nMax
;
1510 sInfo
.nPos
= max(sInfo
.nPos
, 0);
1511 sInfo
.nPos
= min(sInfo
.nPos
, Maximum
);
1513 if (old_pos
!= sInfo
.nPos
)
1515 USHORT OldX
= Buff
->ShowX
;
1516 USHORT OldY
= Buff
->ShowY
;
1517 *pShowXY
= sInfo
.nPos
;
1519 ScrollWindowEx(GuiData
->hWindow
,
1520 (OldX
- Buff
->ShowX
) * GuiData
->CharWidth
,
1521 (OldY
- Buff
->ShowY
) * GuiData
->CharHeight
,
1528 sInfo
.fMask
= SIF_POS
;
1529 SetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
, TRUE
);
1531 UpdateWindow(GuiData
->hWindow
);
1535 LeaveCriticalSection(&Console
->Lock
);
1539 static LRESULT CALLBACK
1540 GuiConsoleWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1543 PGUI_CONSOLE_DATA GuiData
= NULL
;
1544 PCONSOLE Console
= NULL
;
1547 * - If it's the first time we create a window for the terminal,
1548 * just initialize it and return.
1550 * - If we are destroying the window, just do it and return.
1552 if (msg
== WM_NCCREATE
)
1554 return (LRESULT
)GuiConsoleHandleNcCreate(hWnd
, (LPCREATESTRUCTW
)lParam
);
1556 else if (msg
== WM_NCDESTROY
)
1558 return GuiConsoleHandleNcDestroy(hWnd
);
1562 * Now the terminal window is initialized.
1563 * Get the terminal data via the window's data.
1564 * If there is no data, just go away.
1566 GuiData
= GuiGetGuiData(hWnd
);
1567 if (GuiData
== NULL
) return 0;
1570 * Each helper function which needs the console
1571 * has to validate and lock it.
1574 /* We have a console, start message dispatching */
1578 GuiConsoleHandleClose(GuiData
);
1582 GuiConsoleHandlePaint(GuiData
);
1591 GuiConsoleHandleKey(GuiData
, msg
, wParam
, lParam
);
1596 GuiConsoleHandleTimer(GuiData
);
1599 case WM_LBUTTONDOWN
:
1600 case WM_MBUTTONDOWN
:
1601 case WM_RBUTTONDOWN
:
1605 case WM_LBUTTONDBLCLK
:
1606 case WM_MBUTTONDBLCLK
:
1607 case WM_RBUTTONDBLCLK
:
1610 case WM_MOUSEHWHEEL
:
1612 Result
= GuiConsoleHandleMouse(GuiData
, msg
, wParam
, lParam
);
1616 case WM_NCRBUTTONDOWN
:
1618 DPRINT("WM_NCRBUTTONDOWN\n");
1620 * HACK: !! Because, when we deal with WM_RBUTTON* and we do not
1621 * call after that DefWindowProc, on ReactOS, right-clicks on the
1622 * (non-client) application title-bar does not display the system
1623 * menu and does not trigger a WM_NCRBUTTONUP message too.
1624 * See: http://git.reactos.org/?p=reactos.git;a=blob;f=reactos/win32ss/user/user32/windows/defwnd.c;hb=HEAD#l1103
1625 * and line 1135 too.
1627 if (DefWindowProcW(hWnd
, WM_NCHITTEST
, 0, lParam
) == HTCAPTION
)
1628 return DefWindowProcW(hWnd
, WM_CONTEXTMENU
, wParam
, lParam
);
1632 // case WM_NCRBUTTONUP:
1633 // DPRINT1("WM_NCRBUTTONUP\n");
1636 case WM_CONTEXTMENU
:
1638 if (DefWindowProcW(hWnd
/*GuiData->hWindow*/, WM_NCHITTEST
, 0, lParam
) == HTCLIENT
)
1640 HMENU hMenu
= CreatePopupMenu();
1643 GuiConsoleAppendMenuItems(hMenu
, GuiConsoleEditMenuItems
);
1644 TrackPopupMenuEx(hMenu
,
1646 GET_X_LPARAM(lParam
),
1647 GET_Y_LPARAM(lParam
),
1663 Result
= GuiConsoleHandleSysMenuCommand(GuiData
, wParam
, lParam
);
1670 Result
= GuiConsoleHandleScroll(GuiData
, msg
, wParam
);
1677 Console
= GuiData
->Console
; // Not NULL because checked in GuiGetGuiData.
1678 if (ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1681 er
.EventType
= FOCUS_EVENT
;
1682 er
.Event
.FocusEvent
.bSetFocus
= (msg
== WM_SETFOCUS
);
1683 ConioProcessInputEvent(Console
, &er
);
1685 LeaveCriticalSection(&Console
->Lock
);
1690 case WM_GETMINMAXINFO
:
1691 GuiConsoleGetMinMaxInfo(GuiData
, (PMINMAXINFO
)lParam
);
1695 GuiConsoleResize(GuiData
, wParam
, lParam
);
1698 case PM_APPLY_CONSOLE_INFO
:
1700 Console
= GuiData
->Console
; // Not NULL because checked in GuiGetGuiData.
1701 if (ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1703 GuiApplyUserSettings(GuiData
, (HANDLE
)wParam
, (BOOL
)lParam
);
1704 LeaveCriticalSection(&Console
->Lock
);
1709 case PM_CONSOLE_BEEP
:
1710 DPRINT1("Beep !!\n");
1714 // case PM_CONSOLE_SET_TITLE:
1715 // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
1719 Result
= DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1728 /******************************************************************************
1729 * GUI Terminal Initialization *
1730 ******************************************************************************/
1732 static LRESULT CALLBACK
1733 GuiConsoleNotifyWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1743 SetWindowLongW(hWnd
, GWL_USERDATA
, 0);
1747 case PM_CREATE_CONSOLE
:
1749 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
1750 PCONSOLE Console
= GuiData
->Console
;
1752 NewWindow
= CreateWindowExW(WS_EX_CLIENTEDGE
,
1753 GUI_CONSOLE_WINDOW_CLASS
,
1754 Console
->Title
.Buffer
,
1755 WS_OVERLAPPEDWINDOW
| WS_HSCROLL
| WS_VSCROLL
,
1764 if (NULL
!= NewWindow
)
1766 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
1768 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
1770 DPRINT1("Set icons via PM_CREATE_CONSOLE\n");
1771 if (GuiData
->hIcon
== NULL
)
1773 DPRINT1("Not really /o\\...\n");
1774 GuiData
->hIcon
= ghDefaultIcon
;
1775 GuiData
->hIconSm
= ghDefaultIconSm
;
1777 else if (GuiData
->hIcon
!= ghDefaultIcon
)
1779 DPRINT1("Yes \\o/\n");
1780 SendMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
1781 SendMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
1784 /* Move and resize the window to the user's values */
1785 /* CAN WE DEADLOCK ?? */
1786 GuiConsoleMoveWindow(GuiData
);
1787 GuiData
->WindowSizeLock
= TRUE
;
1788 GuiConsoleResizeWindow(GuiData
);
1789 GuiData
->WindowSizeLock
= FALSE
;
1791 // ShowWindow(NewWindow, (int)wParam);
1792 ShowWindowAsync(NewWindow
, (int)wParam
);
1793 DPRINT1("Window showed\n");
1796 return (LRESULT
)NewWindow
;
1799 case PM_DESTROY_CONSOLE
:
1801 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
1804 * Window creation is done using a PostMessage(), so it's possible
1805 * that the window that we want to destroy doesn't exist yet.
1806 * So first empty the message queue.
1809 while(PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
1811 TranslateMessage(&Msg);
1812 DispatchMessageW(&Msg);
1814 while (PeekMessageW(&Msg
, NULL
, 0, 0, PM_REMOVE
)) ;
1816 if (GuiData
->hWindow
!= NULL
) /* && DestroyWindow(GuiData->hWindow) */
1818 DestroyWindow(GuiData
->hWindow
);
1820 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
1822 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
1823 if (0 == WindowCount
)
1826 DestroyWindow(hWnd
);
1827 DPRINT1("CONSRV: Going to quit the Gui Thread!!\n");
1836 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1841 GuiConsoleGuiThread(PVOID Data
)
1844 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Data
;
1847 * This thread dispatches all the console notifications to the notify window.
1848 * It is common for all the console windows.
1851 PrivateCsrssManualGuiCheck(+1);
1853 NotifyWnd
= CreateWindowW(L
"ConSrvCreateNotify",
1855 WS_OVERLAPPEDWINDOW
,
1864 if (NULL
== NotifyWnd
)
1866 PrivateCsrssManualGuiCheck(-1);
1867 SetEvent(*GraphicsStartupEvent
);
1871 SetEvent(*GraphicsStartupEvent
);
1873 while(GetMessageW(&msg
, NULL
, 0, 0))
1875 TranslateMessage(&msg
);
1876 DispatchMessageW(&msg
);
1879 DPRINT1("CONSRV: Quit the Gui Thread!!\n");
1880 PrivateCsrssManualGuiCheck(-1);
1889 ATOM ConsoleClassAtom
;
1891 /* Exit if we were already initialized */
1892 // if (ConsInitialized) return TRUE;
1895 * Initialize and register the different window classes, if needed.
1897 if (!ConsInitialized
)
1899 /* Initialize the notification window class */
1900 wc
.cbSize
= sizeof(WNDCLASSEXW
);
1901 wc
.lpszClassName
= L
"ConSrvCreateNotify";
1902 wc
.lpfnWndProc
= GuiConsoleNotifyWndProc
;
1904 wc
.hInstance
= ConSrvDllInstance
;
1908 wc
.hbrBackground
= NULL
;
1909 wc
.lpszMenuName
= NULL
;
1912 if (RegisterClassExW(&wc
) == 0)
1914 DPRINT1("Failed to register GUI notify wndproc\n");
1918 /* Initialize the console window class */
1919 ghDefaultIcon
= LoadImageW(ConSrvDllInstance
, MAKEINTRESOURCEW(IDI_CONSOLE
), IMAGE_ICON
,
1920 GetSystemMetrics(SM_CXICON
), GetSystemMetrics(SM_CYICON
),
1922 ghDefaultIconSm
= LoadImageW(ConSrvDllInstance
, MAKEINTRESOURCEW(IDI_CONSOLE
), IMAGE_ICON
,
1923 GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
),
1925 ghDefaultCursor
= LoadCursorW(NULL
, IDC_ARROW
);
1926 wc
.cbSize
= sizeof(WNDCLASSEXW
);
1927 wc
.lpszClassName
= GUI_CONSOLE_WINDOW_CLASS
;
1928 wc
.lpfnWndProc
= GuiConsoleWndProc
;
1929 wc
.style
= CS_DBLCLKS
/* | CS_HREDRAW | CS_VREDRAW */;
1930 wc
.hInstance
= ConSrvDllInstance
;
1931 wc
.hIcon
= ghDefaultIcon
;
1932 wc
.hIconSm
= ghDefaultIconSm
;
1933 wc
.hCursor
= ghDefaultCursor
;
1934 wc
.hbrBackground
= CreateSolidBrush(RGB(0,0,0)); // FIXME: Use defaults from registry.
1935 wc
.lpszMenuName
= NULL
;
1937 wc
.cbWndExtra
= GWLP_CONSOLEWND_ALLOC
;
1939 ConsoleClassAtom
= RegisterClassExW(&wc
);
1940 if (ConsoleClassAtom
== 0)
1942 DPRINT1("Failed to register GUI console wndproc\n");
1947 NtUserConsoleControl(GuiConsoleWndClassAtom
, &ConsoleClassAtom
, sizeof(ATOM
));
1950 ConsInitialized
= TRUE
;
1954 * Set-up the notification window
1956 if (NULL
== NotifyWnd
)
1958 HANDLE ThreadHandle
;
1959 HANDLE GraphicsStartupEvent
;
1961 GraphicsStartupEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1962 if (NULL
== GraphicsStartupEvent
) return FALSE
;
1964 ThreadHandle
= CreateThread(NULL
,
1966 GuiConsoleGuiThread
,
1967 (PVOID
)&GraphicsStartupEvent
,
1970 if (NULL
== ThreadHandle
)
1972 CloseHandle(GraphicsStartupEvent
);
1973 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
1976 SetThreadPriority(ThreadHandle
, THREAD_PRIORITY_HIGHEST
);
1977 CloseHandle(ThreadHandle
);
1979 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
1980 CloseHandle(GraphicsStartupEvent
);
1982 if (NULL
== NotifyWnd
)
1984 DPRINT1("CONSRV: Failed to create notification window.\n");
1989 // ConsInitialized = TRUE;
1996 /******************************************************************************
1997 * GUI Console Driver *
1998 ******************************************************************************/
2001 GuiCleanupConsole(PCONSOLE Console
)
2003 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
2005 SendMessageW(NotifyWnd
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
2007 DPRINT1("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
2008 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
2009 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
2011 DPRINT1("Destroy hIcon\n");
2012 DestroyIcon(GuiData
->hIcon
);
2014 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
2016 DPRINT1("Destroy hIconSm\n");
2017 DestroyIcon(GuiData
->hIconSm
);
2020 Console
->TermIFace
.Data
= NULL
;
2021 DeleteCriticalSection(&GuiData
->Lock
);
2022 RtlFreeHeap(ConSrvHeap
, 0, GuiData
);
2024 DPRINT1("Quit GuiCleanupConsole\n");
2028 GuiWriteStream(PCONSOLE Console
, SMALL_RECT
* Region
, LONG CursorStartX
, LONG CursorStartY
,
2029 UINT ScrolledLines
, CHAR
*Buffer
, UINT Length
)
2031 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
2032 PCONSOLE_SCREEN_BUFFER Buff
= Console
->ActiveBuffer
;
2033 LONG CursorEndX
, CursorEndY
;
2036 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
)
2041 if (0 != ScrolledLines
)
2043 ScrollRect
.left
= 0;
2045 ScrollRect
.right
= Console
->ConsoleSize
.X
* GuiData
->CharWidth
;
2046 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
2048 ScrollWindowEx(GuiData
->hWindow
,
2050 -(ScrolledLines
* GuiData
->CharHeight
),
2058 GuiDrawRegion(Console
, Region
);
2060 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
2061 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
2063 GuiInvalidateCell(Console
, CursorStartX
, CursorStartY
);
2066 CursorEndX
= Buff
->CursorPosition
.X
;
2067 CursorEndY
= Buff
->CursorPosition
.Y
;
2068 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
2069 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
2070 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
2072 GuiInvalidateCell(Console
, CursorEndX
, CursorEndY
);
2075 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
2076 // repaint the window without having it just freeze up and stay on the screen permanently.
2077 Buff
->CursorBlinkOn
= TRUE
;
2078 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
2082 GuiDrawRegion(PCONSOLE Console
, SMALL_RECT
* Region
)
2084 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
2087 SmallRectToRect(GuiData
, &RegionRect
, Region
);
2088 InvalidateRect(GuiData
->hWindow
, &RegionRect
, FALSE
);
2092 GuiSetCursorInfo(PCONSOLE Console
, PCONSOLE_SCREEN_BUFFER Buff
)
2094 if (Console
->ActiveBuffer
== Buff
)
2096 GuiInvalidateCell(Console
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
2103 GuiSetScreenInfo(PCONSOLE Console
, PCONSOLE_SCREEN_BUFFER Buff
, UINT OldCursorX
, UINT OldCursorY
)
2105 if (Console
->ActiveBuffer
== Buff
)
2107 /* Redraw char at old position (removes cursor) */
2108 GuiInvalidateCell(Console
, OldCursorX
, OldCursorY
);
2109 /* Redraw char at new position (shows cursor) */
2110 GuiInvalidateCell(Console
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
2117 GuiUpdateScreenInfo(PCONSOLE Console
, PCONSOLE_SCREEN_BUFFER Buff
)
2122 static NTSTATUS WINAPI
2123 GuiResizeBuffer(PCONSOLE Console
, PCONSOLE_SCREEN_BUFFER ScreenBuffer
, COORD Size
)
2131 USHORT value
= MAKEWORD(' ', ScreenBuffer
->ScreenDefaultAttrib
);
2137 /* Buffer size is not allowed to be smaller than window size */
2138 if (Size
.X
< Console
->ConsoleSize
.X
|| Size
.Y
< Console
->ConsoleSize
.Y
)
2139 return STATUS_INVALID_PARAMETER
;
2141 if (Size
.X
== ScreenBuffer
->ScreenBufferSize
.X
&& Size
.Y
== ScreenBuffer
->ScreenBufferSize
.Y
)
2143 // FIXME: Trigger a buffer resize event ??
2144 return STATUS_SUCCESS
;
2147 Buffer
= RtlAllocateHeap(ConSrvHeap
, 0, Size
.X
* Size
.Y
* 2);
2149 return STATUS_NO_MEMORY
;
2151 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer
->ScreenBufferSize
.X
, ScreenBuffer
->ScreenBufferSize
.Y
, Size
.X
, Size
.Y
);
2152 OldBuffer
= ScreenBuffer
->Buffer
;
2154 for (CurrentY
= 0; CurrentY
< ScreenBuffer
->ScreenBufferSize
.Y
&& CurrentY
< Size
.Y
; CurrentY
++)
2156 OldPtr
= ConioCoordToPointer(ScreenBuffer
, 0, CurrentY
);
2157 if (Size
.X
<= ScreenBuffer
->ScreenBufferSize
.X
)
2160 RtlCopyMemory(&Buffer
[Offset
], OldPtr
, Size
.X
* 2);
2161 Offset
+= (Size
.X
* 2);
2166 RtlCopyMemory(&Buffer
[Offset
], OldPtr
, ScreenBuffer
->ScreenBufferSize
.X
* 2);
2167 Offset
+= (ScreenBuffer
->ScreenBufferSize
.X
* 2);
2169 diff
= Size
.X
- ScreenBuffer
->ScreenBufferSize
.X
;
2170 /* zero new part of it */
2172 wmemset((PWCHAR
)&Buffer
[Offset
], value
, diff
);
2174 for (i
= 0; i
< diff
; i
++)
2176 Buffer
[Offset
++] = ' ';
2177 Buffer
[Offset
++] = ScreenBuffer
->ScreenDefaultAttrib
;
2183 if (Size
.Y
> ScreenBuffer
->ScreenBufferSize
.Y
)
2185 diff
= Size
.X
* (Size
.Y
- ScreenBuffer
->ScreenBufferSize
.Y
);
2187 wmemset((PWCHAR
)&Buffer
[Offset
], value
, diff
);
2189 for (i
= 0; i
< diff
; i
++)
2191 Buffer
[Offset
++] = ' ';
2192 Buffer
[Offset
++] = ScreenBuffer
->ScreenDefaultAttrib
;
2197 (void)InterlockedExchangePointer((PVOID
volatile*)&ScreenBuffer
->Buffer
, Buffer
);
2198 RtlFreeHeap(ConSrvHeap
, 0, OldBuffer
);
2199 ScreenBuffer
->ScreenBufferSize
= Size
;
2200 ScreenBuffer
->VirtualY
= 0;
2202 /* Ensure cursor and window are within buffer */
2203 if (ScreenBuffer
->CursorPosition
.X
>= Size
.X
)
2204 ScreenBuffer
->CursorPosition
.X
= Size
.X
- 1;
2205 if (ScreenBuffer
->CursorPosition
.Y
>= Size
.Y
)
2206 ScreenBuffer
->CursorPosition
.Y
= Size
.Y
- 1;
2207 if (ScreenBuffer
->ShowX
> Size
.X
- Console
->ConsoleSize
.X
)
2208 ScreenBuffer
->ShowX
= Size
.X
- Console
->ConsoleSize
.X
;
2209 if (ScreenBuffer
->ShowY
> Size
.Y
- Console
->ConsoleSize
.Y
)
2210 ScreenBuffer
->ShowY
= Size
.Y
- Console
->ConsoleSize
.Y
;
2213 * Trigger a buffer resize event
2215 if (Console
->InputBuffer
.Mode
& ENABLE_WINDOW_INPUT
)
2219 er
.EventType
= WINDOW_BUFFER_SIZE_EVENT
;
2220 er
.Event
.WindowBufferSizeEvent
.dwSize
= ScreenBuffer
->ScreenBufferSize
;
2222 ConioProcessInputEvent(Console
, &er
);
2225 /* TODO: Should update scrollbar, but can't use anything that
2226 * calls SendMessage or it could cause deadlock --> Use PostMessage */
2227 // TODO: Tell the terminal to resize its scrollbars.
2229 return STATUS_SUCCESS
;
2233 GuiResizeTerminal(PCONSOLE Console
)
2235 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
2237 /* Resize the window to the user's values */
2238 GuiData
->WindowSizeLock
= TRUE
;
2239 GuiConsoleResizeWindow(GuiData
);
2240 GuiData
->WindowSizeLock
= FALSE
;
2244 GuiProcessKeyCallback(PCONSOLE Console
, MSG
* msg
, BYTE KeyStateMenu
, DWORD ShiftState
, UINT VirtualKeyCode
, BOOL Down
)
2246 if ((ShiftState
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
) || KeyStateMenu
& 0x80) &&
2247 (VirtualKeyCode
== VK_ESCAPE
|| VirtualKeyCode
== VK_TAB
|| VirtualKeyCode
== VK_SPACE
))
2249 DefWindowProcW(msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
2257 GuiRefreshInternalInfo(PCONSOLE Console
)
2259 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
2261 /* Update the console leader information held by the window */
2262 SetConsoleWndConsoleLeaderCID(GuiData
);
2266 GuiChangeTitle(PCONSOLE Console
)
2268 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
2269 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
2270 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
2274 GuiChangeIcon(PCONSOLE Console
, HICON hWindowIcon
)
2276 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
2277 HICON hIcon
, hIconSm
;
2279 if (hWindowIcon
== NULL
)
2281 hIcon
= ghDefaultIcon
;
2282 hIconSm
= ghDefaultIconSm
;
2286 hIcon
= CopyIcon(hWindowIcon
);
2287 hIconSm
= CopyIcon(hWindowIcon
);
2295 if (hIcon
!= GuiData
->hIcon
)
2297 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
2299 DestroyIcon(GuiData
->hIcon
);
2301 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
2303 DestroyIcon(GuiData
->hIconSm
);
2306 GuiData
->hIcon
= hIcon
;
2307 GuiData
->hIconSm
= hIconSm
;
2309 DPRINT1("Set icons in GuiChangeIcon\n");
2310 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
2311 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
2318 GuiGetConsoleWindowHandle(PCONSOLE Console
)
2320 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
2321 return GuiData
->hWindow
;
2324 static FRONTEND_VTBL GuiVtbl
=
2331 GuiUpdateScreenInfo
,
2334 GuiProcessKeyCallback
,
2335 GuiRefreshInternalInfo
,
2338 GuiGetConsoleWindowHandle
2342 GuiInitConsole(PCONSOLE Console
,
2343 /*IN*/ PCONSOLE_START_INFO ConsoleStartInfo
,
2344 PCONSOLE_INFO ConsoleInfo
,
2349 PGUI_CONSOLE_DATA GuiData
;
2350 GUI_CONSOLE_INFO TermInfo
;
2353 if (Console
== NULL
|| ConsoleInfo
== NULL
)
2354 return STATUS_INVALID_PARAMETER
;
2356 /* Initialize the GUI terminal emulator */
2357 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
2359 /* Initialize the console */
2360 Console
->TermIFace
.Vtbl
= &GuiVtbl
;
2362 GuiData
= RtlAllocateHeap(ConSrvHeap
, HEAP_ZERO_MEMORY
,
2363 sizeof(GUI_CONSOLE_DATA
));
2366 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
2367 return STATUS_UNSUCCESSFUL
;
2369 Console
->TermIFace
.Data
= (PVOID
)GuiData
;
2370 GuiData
->Console
= Console
;
2371 GuiData
->hWindow
= NULL
;
2373 InitializeCriticalSection(&GuiData
->Lock
);
2377 * Load the terminal settings
2380 /***********************************************
2381 * Adapted from ConSrvInitConsole in console.c *
2382 ***********************************************/
2384 /* 1. Load the default settings */
2385 GuiConsoleGetDefaultSettings(&TermInfo
, ProcessId
);
2387 /* 2. Load the remaining console settings via the registry. */
2388 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
2390 /* Load the terminal infos from the registry. */
2391 GuiConsoleReadUserSettings(&TermInfo
, ConsoleInfo
->ConsoleTitle
, ProcessId
);
2394 * Now, update them with the properties the user might gave to us
2395 * via the STARTUPINFO structure before calling CreateProcess
2396 * (and which was transmitted via the ConsoleStartInfo structure).
2397 * We therefore overwrite the values read in the registry.
2399 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
2401 TermInfo
.ShowWindow
= ConsoleStartInfo
->ShowWindow
;
2403 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
2405 TermInfo
.AutoPosition
= FALSE
;
2406 TermInfo
.WindowOrigin
= ConsoleStartInfo
->ConsoleWindowOrigin
;
2409 if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
2411 ConsoleInfo.FullScreen = TRUE;
2418 * Set up the GUI data
2421 Length
= min(wcslen(TermInfo
.FaceName
) + 1, LF_FACESIZE
); // wcsnlen
2422 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
2423 GuiData
->GuiInfo
.FaceName
[Length
] = L
'\0';
2424 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
2425 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
2426 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
2427 GuiData
->GuiInfo
.UseRasterFonts
= TermInfo
.UseRasterFonts
;
2428 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
2429 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
2430 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
2432 /* Initialize the icon handles to their default values */
2433 GuiData
->hIcon
= ghDefaultIcon
;
2434 GuiData
->hIconSm
= ghDefaultIconSm
;
2436 /* Get the associated icon, if any */
2437 if (IconPath
== NULL
|| *IconPath
== L
'\0')
2439 IconPath
= ConsoleStartInfo
->AppPath
;
2442 DPRINT1("IconPath = %S ; IconIndex = %lu\n", (IconPath
? IconPath
: L
"n/a"), IconIndex
);
2445 HICON hIcon
= NULL
, hIconSm
= NULL
;
2446 PrivateExtractIconExW(IconPath
,
2451 DPRINT1("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon
, hIconSm
);
2454 DPRINT1("Effectively set the icons\n");
2455 GuiData
->hIcon
= hIcon
;
2456 GuiData
->hIconSm
= hIconSm
;
2461 * We need to wait until the GUI has been fully initialized
2462 * to retrieve custom settings i.e. WindowSize etc...
2463 * Ideally we could use SendNotifyMessage for this but its not
2466 GuiData
->hGuiInitEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2468 /* Create the terminal window */
2469 PostMessageW(NotifyWnd
, PM_CREATE_CONSOLE
, GuiData
->GuiInfo
.ShowWindow
, (LPARAM
)GuiData
);
2471 /* Wait until initialization has finished */
2472 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
2473 DPRINT1("OK we created the console window\n");
2474 CloseHandle(GuiData
->hGuiInitEvent
);
2475 GuiData
->hGuiInitEvent
= NULL
;
2477 /* Check whether we really succeeded in initializing the terminal window */
2478 if (GuiData
->hWindow
== NULL
)
2480 DPRINT1("GuiInitConsole - We failed at creating a new terminal window\n");
2481 // ConioCleanupConsole(Console);
2482 GuiCleanupConsole(Console
);
2483 return STATUS_UNSUCCESSFUL
;
2486 return STATUS_SUCCESS
;