2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/frontends/gui/guiterm.c
5 * PURPOSE: GUI Terminal Front-End
6 * PROGRAMMERS: Gé van Geldorp
9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
12 /* INCLUDES *******************************************************************/
15 #define NONAMELESSUNION
18 #include "include/conio.h"
19 #include "include/console.h"
20 #include "include/settings.h"
21 #include "conoutput.h"
23 #include "guisettings.h"
34 /* GUI Console Window Class name */
35 #define GUI_CONSOLE_WINDOW_CLASS L"ConsoleWindowClass"
40 #define PM_CREATE_CONSOLE (WM_APP + 1)
41 #define PM_DESTROY_CONSOLE (WM_APP + 2)
42 #define PM_RESIZE_TERMINAL (WM_APP + 3)
43 #define PM_CONSOLE_BEEP (WM_APP + 4)
44 #define PM_CONSOLE_SET_TITLE (WM_APP + 5)
47 /* Not defined in any header file */
48 extern VOID WINAPI
PrivateCsrssManualGuiCheck(LONG Check
);
49 // See winsrv/usersrv/init.c line 234
52 /* GLOBALS ********************************************************************/
54 typedef struct _GUI_INIT_INFO
56 PCONSOLE_INFO ConsoleInfo
;
57 PCONSOLE_START_INFO ConsoleStartInfo
;
59 } GUI_INIT_INFO
, *PGUI_INIT_INFO
;
61 /**************************************************************\
62 \** Define the Console Leader Process for the console window **/
63 #define GWLP_CONSOLEWND_ALLOC (2 * sizeof(LONG_PTR))
64 #define GWLP_CONSOLE_LEADER_PID 0
65 #define GWLP_CONSOLE_LEADER_TID 4
67 #define SetConsoleWndConsoleLeaderCID(GuiData) \
69 PCONSOLE_PROCESS_DATA ProcessData; \
70 CLIENT_ID ConsoleLeaderCID; \
71 ProcessData = CONTAINING_RECORD((GuiData)->Console->ProcessList.Blink, \
72 CONSOLE_PROCESS_DATA, \
74 ConsoleLeaderCID = ProcessData->Process->ClientId; \
75 SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_PID, (LONG_PTR)(ConsoleLeaderCID.UniqueProcess)); \
76 SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_TID, (LONG_PTR)(ConsoleLeaderCID.UniqueThread )); \
78 /**************************************************************/
80 static BOOL ConsInitialized
= FALSE
;
81 static HICON ghDefaultIcon
= NULL
;
82 static HICON ghDefaultIconSm
= NULL
;
83 static HCURSOR ghDefaultCursor
= NULL
;
84 static HWND NotifyWnd
= NULL
;
86 typedef struct _GUICONSOLE_MENUITEM
89 const struct _GUICONSOLE_MENUITEM
*SubMenu
;
91 } GUICONSOLE_MENUITEM
, *PGUICONSOLE_MENUITEM
;
93 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems
[] =
95 { IDS_MARK
, NULL
, ID_SYSTEM_EDIT_MARK
},
96 { IDS_COPY
, NULL
, ID_SYSTEM_EDIT_COPY
},
97 { IDS_PASTE
, NULL
, ID_SYSTEM_EDIT_PASTE
},
98 { IDS_SELECTALL
, NULL
, ID_SYSTEM_EDIT_SELECTALL
},
99 { IDS_SCROLL
, NULL
, ID_SYSTEM_EDIT_SCROLL
},
100 { IDS_FIND
, NULL
, ID_SYSTEM_EDIT_FIND
},
102 { 0, NULL
, 0 } /* End of list */
105 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems
[] =
107 { IDS_EDIT
, GuiConsoleEditMenuItems
, 0 },
108 { IDS_DEFAULTS
, NULL
, ID_SYSTEM_DEFAULTS
},
109 { IDS_PROPERTIES
, NULL
, ID_SYSTEM_PROPERTIES
},
111 { 0, NULL
, 0 } /* End of list */
115 * Default 16-color palette for foreground and background
116 * (corresponding flags in comments).
118 const COLORREF s_Colors
[16] =
120 RGB(0, 0, 0), // (Black)
121 RGB(0, 0, 128), // BLUE
122 RGB(0, 128, 0), // GREEN
123 RGB(0, 128, 128), // BLUE | GREEN
124 RGB(128, 0, 0), // RED
125 RGB(128, 0, 128), // BLUE | RED
126 RGB(128, 128, 0), // GREEN | RED
127 RGB(192, 192, 192), // BLUE | GREEN | RED
129 RGB(128, 128, 128), // (Grey) INTENSITY
130 RGB(0, 0, 255), // BLUE | INTENSITY
131 RGB(0, 255, 0), // GREEN | INTENSITY
132 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
133 RGB(255, 0, 0), // RED | INTENSITY
134 RGB(255, 0, 255), // BLUE | RED | INTENSITY
135 RGB(255, 255, 0), // GREEN | RED | INTENSITY
136 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
139 /* FUNCTIONS ******************************************************************/
142 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer
,
143 IN PGUI_CONSOLE_DATA GuiData
,
145 OUT PUINT HeightUnit
)
147 if (Buffer
== NULL
|| GuiData
== NULL
||
148 WidthUnit
== NULL
|| HeightUnit
== NULL
)
153 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
155 *WidthUnit
= GuiData
->CharWidth
;
156 *HeightUnit
= GuiData
->CharHeight
;
158 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
168 GuiConsoleAppendMenuItems(HMENU hMenu
,
169 const GUICONSOLE_MENUITEM
*Items
)
172 WCHAR szMenuString
[255];
177 if (Items
[i
].uID
!= (UINT
)-1)
179 if (LoadStringW(ConSrvDllInstance
,
182 sizeof(szMenuString
) / sizeof(szMenuString
[0])) > 0)
184 if (Items
[i
].SubMenu
!= NULL
)
186 hSubMenu
= CreatePopupMenu();
187 if (hSubMenu
!= NULL
)
189 GuiConsoleAppendMenuItems(hSubMenu
,
192 if (!AppendMenuW(hMenu
,
193 MF_STRING
| MF_POPUP
,
197 DestroyMenu(hSubMenu
);
218 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
222 GuiConsoleCreateSysMenu(HWND hWnd
)
224 HMENU hMenu
= GetSystemMenu(hWnd
, FALSE
);
227 GuiConsoleAppendMenuItems(hMenu
, GuiConsoleMainMenuItems
);
233 GuiSendMenuEvent(PCONSOLE Console
, UINT CmdId
)
237 er
.EventType
= MENU_EVENT
;
238 er
.Event
.MenuEvent
.dwCommandId
= CmdId
;
240 ConioProcessInputEvent(Console
, &er
);
244 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData
);
246 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData
);
248 GuiConsoleUpdateSelection(PCONSOLE Console
, PCOORD coord
);
250 GuiDrawRegion(IN OUT PFRONTEND This
, SMALL_RECT
* Region
);
252 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData
);
256 GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
259 PCONSOLE Console
= GuiData
->Console
;
260 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
262 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
267 ActiveBuffer
= ConDrvGetActiveScreenBuffer(Console
);
270 * In case the selected menu item belongs to the user-reserved menu id range,
271 * send to him a menu event and return directly. The user must handle those
272 * reserved menu commands...
274 if (GuiData
->cmdIdLow
<= (UINT
)wParam
&& (UINT
)wParam
<= GuiData
->cmdIdHigh
)
276 GuiSendMenuEvent(Console
, (UINT
)wParam
);
280 /* ... otherwise, perform actions. */
283 case ID_SYSTEM_EDIT_MARK
:
285 LPWSTR WindowTitle
= NULL
;
288 Console
->dwSelectionCursor
.X
= ActiveBuffer
->ViewOrigin
.X
;
289 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ViewOrigin
.Y
;
290 Console
->Selection
.dwSelectionAnchor
= Console
->dwSelectionCursor
;
291 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
;
292 GuiConsoleUpdateSelection(Console
, &Console
->Selection
.dwSelectionAnchor
);
294 Length
= Console
->Title
.Length
+ sizeof(L
"Mark - ")/sizeof(WCHAR
) + 1;
295 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
296 wcscpy(WindowTitle
, L
"Mark - ");
297 wcscat(WindowTitle
, Console
->Title
.Buffer
);
298 SetWindowText(GuiData
->hWindow
, WindowTitle
);
299 ConsoleFreeHeap(WindowTitle
);
304 case ID_SYSTEM_EDIT_COPY
:
305 GuiConsoleCopy(GuiData
);
308 case ID_SYSTEM_EDIT_PASTE
:
309 GuiConsolePaste(GuiData
);
312 case ID_SYSTEM_EDIT_SELECTALL
:
314 LPWSTR WindowTitle
= NULL
;
318 * We select all the characters from line 1 to
319 * the line where the cursor is positioned.
321 Console
->Selection
.dwSelectionAnchor
.X
= 0;
322 Console
->Selection
.dwSelectionAnchor
.Y
= 0;
323 Console
->dwSelectionCursor
.X
= ActiveBuffer
->ViewSize
.X
- 1;
324 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->CursorPosition
.Y
;
325 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
| CONSOLE_MOUSE_SELECTION
;
326 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
328 Length
= Console
->Title
.Length
+ sizeof(L
"Selection - ")/sizeof(WCHAR
) + 1;
329 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
330 wcscpy(WindowTitle
, L
"Selection - ");
331 wcscat(WindowTitle
, Console
->Title
.Buffer
);
332 SetWindowText(GuiData
->hWindow
, WindowTitle
);
333 ConsoleFreeHeap(WindowTitle
);
338 case ID_SYSTEM_EDIT_SCROLL
:
339 DPRINT1("Scrolling is not handled yet\n");
342 case ID_SYSTEM_EDIT_FIND
:
343 DPRINT1("Finding is not handled yet\n");
346 case ID_SYSTEM_DEFAULTS
:
347 GuiConsoleShowConsoleProperties(GuiData
, TRUE
);
350 case ID_SYSTEM_PROPERTIES
:
351 GuiConsoleShowConsoleProperties(GuiData
, FALSE
);
360 LeaveCriticalSection(&Console
->Lock
);
363 Ret
= DefWindowProcW(GuiData
->hWindow
, WM_SYSCOMMAND
, wParam
, lParam
);
368 static PGUI_CONSOLE_DATA
369 GuiGetGuiData(HWND hWnd
)
371 /* This function ensures that the console pointer is not NULL */
372 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
373 return ( ((GuiData
== NULL
) || (GuiData
->hWindow
== hWnd
&& GuiData
->Console
!= NULL
)) ? GuiData
: NULL
);
377 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData
)
379 /* Move the window if needed (not positioned by the system) */
380 if (!GuiData
->GuiInfo
.AutoPosition
)
382 SetWindowPos(GuiData
->hWindow
,
384 GuiData
->GuiInfo
.WindowOrigin
.x
,
385 GuiData
->GuiInfo
.WindowOrigin
.y
,
388 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
393 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData
)
395 PCONSOLE Console
= GuiData
->Console
;
396 PCONSOLE_SCREEN_BUFFER Buff
= ConDrvGetActiveScreenBuffer(Console
);
400 UINT WidthUnit
, HeightUnit
;
402 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
404 Width
= Buff
->ViewSize
.X
* WidthUnit
+
405 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
406 Height
= Buff
->ViewSize
.Y
* HeightUnit
+
407 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
409 /* Set scrollbar sizes */
410 sInfo
.cbSize
= sizeof(SCROLLINFO
);
411 sInfo
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
413 if (Buff
->ScreenBufferSize
.Y
> Buff
->ViewSize
.Y
)
415 sInfo
.nMax
= Buff
->ScreenBufferSize
.Y
- 1;
416 sInfo
.nPage
= Buff
->ViewSize
.Y
;
417 sInfo
.nPos
= Buff
->ViewOrigin
.Y
;
418 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &sInfo
, TRUE
);
419 Width
+= GetSystemMetrics(SM_CXVSCROLL
);
420 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, TRUE
);
424 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, FALSE
);
427 if (Buff
->ScreenBufferSize
.X
> Buff
->ViewSize
.X
)
429 sInfo
.nMax
= Buff
->ScreenBufferSize
.X
- 1;
430 sInfo
.nPage
= Buff
->ViewSize
.X
;
431 sInfo
.nPos
= Buff
->ViewOrigin
.X
;
432 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &sInfo
, TRUE
);
433 Height
+= GetSystemMetrics(SM_CYHSCROLL
);
434 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, TRUE
);
438 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, FALSE
);
441 /* Resize the window */
442 SetWindowPos(GuiData
->hWindow
, NULL
, 0, 0, Width
, Height
,
443 SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
444 // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call
445 // to: InvalidateRect(GuiData->hWindow, NULL, TRUE);
449 GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData
)
451 PCONSOLE Console
= GuiData
->Console
;
452 // DEVMODE dmScreenSettings;
454 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
456 /* Switch to full-screen or to windowed mode */
457 GuiData
->GuiInfo
.FullScreen
= !GuiData
->GuiInfo
.FullScreen
;
458 DPRINT1("GuiConsoleSwitchFullScreen - Switch to %s ...\n",
459 (GuiData
->GuiInfo
.FullScreen
? "full-screen" : "windowed mode"));
461 // TODO: Change window appearance.
463 // http://stackoverflow.com/questions/2382464/win32-full-screen-and-hiding-taskbar
464 // http://stackoverflow.com/questions/3549148/fullscreen-management-with-winapi
465 // http://blogs.msdn.com/b/oldnewthing/archive/2010/04/12/9994016.aspx
466 // http://stackoverflow.com/questions/1400654/how-do-i-put-my-opengl-app-into-fullscreen-mode
467 // http://nehe.gamedev.net/tutorial/creating_an_opengl_window_win32/13001/
469 if (GuiData
->GuiInfo
.FullScreen
)
471 memset(&dmScreenSettings
, 0, sizeof(dmScreenSettings
));
472 dmScreenSettings
.dmSize
= sizeof(dmScreenSettings
);
473 dmScreenSettings
.dmDisplayFixedOutput
= DMDFO_CENTER
; // DMDFO_STRETCH // DMDFO_DEFAULT
474 dmScreenSettings
.dmPelsWidth
= 640; // Console->ActiveBuffer->ViewSize.X * GuiData->CharWidth;
475 dmScreenSettings
.dmPelsHeight
= 480; // Console->ActiveBuffer->ViewSize.Y * GuiData->CharHeight;
476 dmScreenSettings
.dmBitsPerPel
= 32;
477 dmScreenSettings
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
478 ChangeDisplaySettings(&dmScreenSettings
, CDS_FULLSCREEN
);
485 LeaveCriticalSection(&Console
->Lock
);
489 GuiConsoleHandleNcCreate(HWND hWnd
, LPCREATESTRUCTW Create
)
491 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)Create
->lpCreateParams
;
498 DPRINT("GuiConsoleHandleNcCreate\n");
502 DPRINT1("GuiConsoleNcCreate: No GUI data\n");
506 Console
= GuiData
->Console
;
508 GuiData
->hWindow
= hWnd
;
510 GuiData
->Font
= CreateFontW(LOWORD(GuiData
->GuiInfo
.FontSize
),
511 0, // HIWORD(GuiData->GuiInfo.FontSize),
514 GuiData
->GuiInfo
.FontWeight
,
521 NONANTIALIASED_QUALITY
,
522 FIXED_PITCH
| GuiData
->GuiInfo
.FontFamily
/* FF_DONTCARE */,
523 GuiData
->GuiInfo
.FaceName
);
525 if (NULL
== GuiData
->Font
)
527 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
528 GuiData
->hWindow
= NULL
;
529 SetEvent(GuiData
->hGuiInitEvent
);
532 Dc
= GetDC(GuiData
->hWindow
);
535 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
536 DeleteObject(GuiData
->Font
);
537 GuiData
->hWindow
= NULL
;
538 SetEvent(GuiData
->hGuiInitEvent
);
541 OldFont
= SelectObject(Dc
, GuiData
->Font
);
544 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
545 ReleaseDC(GuiData
->hWindow
, Dc
);
546 DeleteObject(GuiData
->Font
);
547 GuiData
->hWindow
= NULL
;
548 SetEvent(GuiData
->hGuiInitEvent
);
551 if (!GetTextMetricsW(Dc
, &Metrics
))
553 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
554 SelectObject(Dc
, OldFont
);
555 ReleaseDC(GuiData
->hWindow
, Dc
);
556 DeleteObject(GuiData
->Font
);
557 GuiData
->hWindow
= NULL
;
558 SetEvent(GuiData
->hGuiInitEvent
);
561 GuiData
->CharWidth
= Metrics
.tmMaxCharWidth
;
562 GuiData
->CharHeight
= Metrics
.tmHeight
+ Metrics
.tmExternalLeading
;
564 /* Measure real char width more precisely if possible. */
565 if (GetTextExtentPoint32W(Dc
, L
"R", 1, &CharSize
))
566 GuiData
->CharWidth
= CharSize
.cx
;
568 SelectObject(Dc
, OldFont
);
570 ReleaseDC(GuiData
->hWindow
, Dc
);
572 // FIXME: Keep these instructions here ? ///////////////////////////////////
573 Console
->ActiveBuffer
->CursorBlinkOn
= TRUE
;
574 Console
->ActiveBuffer
->ForceCursorOff
= FALSE
;
575 ////////////////////////////////////////////////////////////////////////////
577 SetWindowLongPtrW(GuiData
->hWindow
, GWLP_USERDATA
, (DWORD_PTR
)GuiData
);
579 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
580 GuiConsoleCreateSysMenu(GuiData
->hWindow
);
582 DPRINT("GuiConsoleHandleNcCreate - setting start event\n");
583 SetEvent(GuiData
->hGuiInitEvent
);
585 return (BOOL
)DefWindowProcW(GuiData
->hWindow
, WM_NCCREATE
, 0, (LPARAM
)Create
);
589 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
591 PCONSOLE Console
= GuiData
->Console
;
592 PCONSOLE_SCREEN_BUFFER Buffer
= ConDrvGetActiveScreenBuffer(Console
);
593 UINT WidthUnit
, HeightUnit
;
595 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
597 Rect
->left
= (SmallRect
->Left
- Buffer
->ViewOrigin
.X
) * WidthUnit
;
598 Rect
->top
= (SmallRect
->Top
- Buffer
->ViewOrigin
.Y
) * HeightUnit
;
599 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ViewOrigin
.X
) * WidthUnit
;
600 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ViewOrigin
.Y
) * HeightUnit
;
604 GuiConsoleUpdateSelection(PCONSOLE Console
, PCOORD coord
)
606 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
607 RECT oldRect
, newRect
;
609 SmallRectToRect(GuiData
, &oldRect
, &Console
->Selection
.srSelection
);
614 /* exchange left/top with right/bottom if required */
615 rc
.Left
= min(Console
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
616 rc
.Top
= min(Console
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
617 rc
.Right
= max(Console
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
618 rc
.Bottom
= max(Console
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
620 SmallRectToRect(GuiData
, &newRect
, &rc
);
622 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
624 if (memcmp(&rc
, &Console
->Selection
.srSelection
, sizeof(SMALL_RECT
)) != 0)
628 /* calculate the region that needs to be updated */
629 if ((rgn1
= CreateRectRgnIndirect(&oldRect
)))
631 if ((rgn2
= CreateRectRgnIndirect(&newRect
)))
633 if (CombineRgn(rgn1
, rgn2
, rgn1
, RGN_XOR
) != ERROR
)
635 InvalidateRgn(GuiData
->hWindow
, rgn1
, FALSE
);
645 InvalidateRect(GuiData
->hWindow
, &newRect
, FALSE
);
647 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_NOT_EMPTY
;
648 Console
->Selection
.srSelection
= rc
;
649 Console
->dwSelectionCursor
= *coord
;
650 ConioPause(Console
, PAUSED_FROM_SELECTION
);
654 /* clear the selection */
655 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
657 InvalidateRect(GuiData
->hWindow
, &oldRect
, FALSE
);
659 Console
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
660 ConioUnpause(Console
, PAUSED_FROM_SELECTION
);
666 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
667 PGUI_CONSOLE_DATA GuiData
,
671 GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
672 PGUI_CONSOLE_DATA GuiData
,
677 GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData
)
680 PCONSOLE Console
= GuiData
->Console
;
681 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
685 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
690 ActiveBuffer
= ConDrvGetActiveScreenBuffer(Console
);
692 hDC
= BeginPaint(GuiData
->hWindow
, &ps
);
694 ps
.rcPaint
.left
< ps
.rcPaint
.right
&&
695 ps
.rcPaint
.top
< ps
.rcPaint
.bottom
)
697 EnterCriticalSection(&GuiData
->Lock
);
699 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
701 GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)ActiveBuffer
,
702 GuiData
, hDC
, &ps
.rcPaint
);
704 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
706 GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)ActiveBuffer
,
707 GuiData
, hDC
, &ps
.rcPaint
);
710 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
713 SmallRectToRect(GuiData
, &rc
, &Console
->Selection
.srSelection
);
715 /* invert the selection */
716 if (IntersectRect(&rc
, &ps
.rcPaint
, &rc
))
727 LeaveCriticalSection(&GuiData
->Lock
);
729 EndPaint(GuiData
->hWindow
, &ps
);
733 LeaveCriticalSection(&Console
->Lock
);
735 DefWindowProcW(GuiData
->hWindow
, WM_PAINT
, 0, 0);
741 IsSystemKey(WORD VirtualKeyCode
)
743 switch (VirtualKeyCode
)
745 /* From MSDN, "Virtual-Key Codes" */
764 GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
766 PCONSOLE Console
= GuiData
->Console
;
767 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
769 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
771 ActiveBuffer
= ConDrvGetActiveScreenBuffer(Console
);
773 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
)
775 WORD VirtualKeyCode
= LOWORD(wParam
);
777 if (msg
!= WM_KEYDOWN
) goto Quit
;
779 if (VirtualKeyCode
== VK_RETURN
)
781 /* Copy (and clear) selection if ENTER is pressed */
782 GuiConsoleCopy(GuiData
);
785 else if ( VirtualKeyCode
== VK_ESCAPE
||
786 (VirtualKeyCode
== 'C' && GetKeyState(VK_CONTROL
) & 0x8000) )
788 /* Cancel selection if ESC or Ctrl-C are pressed */
789 GuiConsoleUpdateSelection(Console
, NULL
);
790 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
795 if ((Console
->Selection
.dwFlags
& CONSOLE_MOUSE_SELECTION
) == 0)
797 /* Keyboard selection mode */
798 BOOL Interpreted
= FALSE
;
799 BOOL MajPressed
= (GetKeyState(VK_SHIFT
) & 0x8000);
801 switch (VirtualKeyCode
)
806 if (Console
->dwSelectionCursor
.X
> 0)
807 Console
->dwSelectionCursor
.X
--;
815 if (Console
->dwSelectionCursor
.X
< ActiveBuffer
->ScreenBufferSize
.X
- 1)
816 Console
->dwSelectionCursor
.X
++;
824 if (Console
->dwSelectionCursor
.Y
> 0)
825 Console
->dwSelectionCursor
.Y
--;
833 if (Console
->dwSelectionCursor
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
- 1)
834 Console
->dwSelectionCursor
.Y
++;
842 Console
->dwSelectionCursor
.X
= 0;
843 Console
->dwSelectionCursor
.Y
= 0;
850 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
857 Console
->dwSelectionCursor
.Y
-= ActiveBuffer
->ViewSize
.Y
;
858 if (Console
->dwSelectionCursor
.Y
< 0)
859 Console
->dwSelectionCursor
.Y
= 0;
867 Console
->dwSelectionCursor
.Y
+= ActiveBuffer
->ViewSize
.Y
;
868 if (Console
->dwSelectionCursor
.Y
>= ActiveBuffer
->ScreenBufferSize
.Y
)
869 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
881 Console
->Selection
.dwSelectionAnchor
= Console
->dwSelectionCursor
;
883 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
885 else if (!IsSystemKey(VirtualKeyCode
))
887 /* Emit an error beep sound */
888 SendNotifyMessage(GuiData
->hWindow
, PM_CONSOLE_BEEP
, 0, 0);
895 /* Mouse selection mode */
897 if (!IsSystemKey(VirtualKeyCode
))
899 /* Clear the selection and send the key into the input buffer */
900 GuiConsoleUpdateSelection(Console
, NULL
);
901 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
910 if ((Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) == 0)
914 Message
.hwnd
= GuiData
->hWindow
;
915 Message
.message
= msg
;
916 Message
.wParam
= wParam
;
917 Message
.lParam
= lParam
;
919 ConioProcessKey(Console
, &Message
);
923 LeaveCriticalSection(&Console
->Lock
);
927 GuiInvalidateCell(IN OUT PFRONTEND This
, SHORT x
, SHORT y
)
929 SMALL_RECT CellRect
= { x
, y
, x
, y
};
930 GuiDrawRegion(This
, &CellRect
);
934 GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData
)
936 PCONSOLE Console
= GuiData
->Console
;
937 PCONSOLE_SCREEN_BUFFER Buff
;
939 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CURSOR_BLINK_TIME
, NULL
);
941 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
943 Buff
= ConDrvGetActiveScreenBuffer(Console
);
945 if (GetType(Buff
) == TEXTMODE_BUFFER
)
947 GuiInvalidateCell(&Console
->TermIFace
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
948 Buff
->CursorBlinkOn
= !Buff
->CursorBlinkOn
;
950 if ((GuiData
->OldCursor
.x
!= Buff
->CursorPosition
.X
) || (GuiData
->OldCursor
.y
!= Buff
->CursorPosition
.Y
))
953 int OldScrollX
= -1, OldScrollY
= -1;
954 int NewScrollX
= -1, NewScrollY
= -1;
956 xScroll
.cbSize
= sizeof(SCROLLINFO
);
957 xScroll
.fMask
= SIF_POS
;
958 // Capture the original position of the scroll bars and save them.
959 if (GetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
)) OldScrollX
= xScroll
.nPos
;
960 if (GetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
)) OldScrollY
= xScroll
.nPos
;
962 // If we successfully got the info for the horizontal scrollbar
965 if ((Buff
->CursorPosition
.X
< Buff
->ViewOrigin
.X
) || (Buff
->CursorPosition
.X
>= (Buff
->ViewOrigin
.X
+ Buff
->ViewSize
.X
)))
967 // Handle the horizontal scroll bar
968 if (Buff
->CursorPosition
.X
>= Buff
->ViewSize
.X
) NewScrollX
= Buff
->CursorPosition
.X
- Buff
->ViewSize
.X
+ 1;
973 NewScrollX
= OldScrollX
;
976 // If we successfully got the info for the vertical scrollbar
979 if ((Buff
->CursorPosition
.Y
< Buff
->ViewOrigin
.Y
) || (Buff
->CursorPosition
.Y
>= (Buff
->ViewOrigin
.Y
+ Buff
->ViewSize
.Y
)))
981 // Handle the vertical scroll bar
982 if (Buff
->CursorPosition
.Y
>= Buff
->ViewSize
.Y
) NewScrollY
= Buff
->CursorPosition
.Y
- Buff
->ViewSize
.Y
+ 1;
987 NewScrollY
= OldScrollY
;
991 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
992 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
993 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
994 // and their associated scrollbar is left alone.
995 if ((OldScrollX
!= NewScrollX
) || (OldScrollY
!= NewScrollY
))
997 Buff
->ViewOrigin
.X
= NewScrollX
;
998 Buff
->ViewOrigin
.Y
= NewScrollY
;
999 ScrollWindowEx(GuiData
->hWindow
,
1000 (OldScrollX
- NewScrollX
) * GuiData
->CharWidth
,
1001 (OldScrollY
- NewScrollY
) * GuiData
->CharHeight
,
1007 if (NewScrollX
>= 0)
1009 xScroll
.nPos
= NewScrollX
;
1010 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
, TRUE
);
1012 if (NewScrollY
>= 0)
1014 xScroll
.nPos
= NewScrollY
;
1015 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
, TRUE
);
1017 UpdateWindow(GuiData
->hWindow
);
1018 GuiData
->OldCursor
.x
= Buff
->CursorPosition
.X
;
1019 GuiData
->OldCursor
.y
= Buff
->CursorPosition
.Y
;
1023 else /* if (GetType(Buff) == GRAPHICS_BUFFER) */
1027 LeaveCriticalSection(&Console
->Lock
);
1031 GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData
)
1033 PCONSOLE Console
= GuiData
->Console
;
1035 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1038 // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
1041 * FIXME: Windows will wait up to 5 seconds for the thread to exit.
1042 * We shouldn't wait here, though, since the console lock is entered.
1043 * A copy of the thread list probably needs to be made.
1045 ConDrvConsoleProcessCtrlEvent(Console
, 0, CTRL_CLOSE_EVENT
);
1047 LeaveCriticalSection(&Console
->Lock
);
1052 GuiConsoleHandleNcDestroy(HWND hWnd
)
1054 KillTimer(hWnd
, CONGUI_UPDATE_TIMER
);
1055 GetSystemMenu(hWnd
, TRUE
);
1057 /* Free the GuiData registration */
1058 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (DWORD_PTR
)NULL
);
1060 return DefWindowProcW(hWnd
, WM_NCDESTROY
, 0, 0);
1064 PointToCoord(PGUI_CONSOLE_DATA GuiData
, LPARAM lParam
)
1066 PCONSOLE Console
= GuiData
->Console
;
1067 PCONSOLE_SCREEN_BUFFER Buffer
= ConDrvGetActiveScreenBuffer(Console
);
1069 UINT WidthUnit
, HeightUnit
;
1071 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1073 Coord
.X
= Buffer
->ViewOrigin
.X
+ ((SHORT
)LOWORD(lParam
) / (int)WidthUnit
);
1074 Coord
.Y
= Buffer
->ViewOrigin
.Y
+ ((SHORT
)HIWORD(lParam
) / (int)HeightUnit
);
1076 /* Clip coordinate to ensure it's inside buffer */
1079 else if (Coord
.X
>= Buffer
->ScreenBufferSize
.X
)
1080 Coord
.X
= Buffer
->ScreenBufferSize
.X
- 1;
1084 else if (Coord
.Y
>= Buffer
->ScreenBufferSize
.Y
)
1085 Coord
.Y
= Buffer
->ScreenBufferSize
.Y
- 1;
1091 GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1094 PCONSOLE Console
= GuiData
->Console
;
1096 if (GuiData
->IgnoreNextMouseSignal
)
1098 if (msg
!= WM_LBUTTONDOWN
&&
1099 msg
!= WM_MBUTTONDOWN
&&
1100 msg
!= WM_RBUTTONDOWN
)
1103 * If this mouse signal is not a button-down action,
1104 * then it is the last signal being ignored.
1106 GuiData
->IgnoreNextMouseSignal
= FALSE
;
1111 * This mouse signal is a button-down action.
1112 * Ignore it and perform default action.
1119 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1125 if ( (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) ||
1126 (Console
->QuickEdit
) )
1130 case WM_LBUTTONDOWN
:
1132 LPWSTR WindowTitle
= NULL
;
1135 Console
->Selection
.dwSelectionAnchor
= PointToCoord(GuiData
, lParam
);
1136 SetCapture(GuiData
->hWindow
);
1137 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
| CONSOLE_MOUSE_SELECTION
| CONSOLE_MOUSE_DOWN
;
1138 GuiConsoleUpdateSelection(Console
, &Console
->Selection
.dwSelectionAnchor
);
1140 Length
= Console
->Title
.Length
+ sizeof(L
"Selection - ")/sizeof(WCHAR
) + 1;
1141 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
1142 wcscpy(WindowTitle
, L
"Selection - ");
1143 wcscat(WindowTitle
, Console
->Title
.Buffer
);
1144 SetWindowText(GuiData
->hWindow
, WindowTitle
);
1145 ConsoleFreeHeap(WindowTitle
);
1154 if (!(Console
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1156 c
= PointToCoord(GuiData
, lParam
);
1157 Console
->Selection
.dwFlags
&= ~CONSOLE_MOUSE_DOWN
;
1158 GuiConsoleUpdateSelection(Console
, &c
);
1164 case WM_LBUTTONDBLCLK
:
1166 DPRINT1("Handle left-double-click for selecting a word\n");
1170 case WM_RBUTTONDOWN
:
1171 case WM_RBUTTONDBLCLK
:
1173 if (!(Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
))
1175 GuiConsolePaste(GuiData
);
1179 GuiConsoleCopy(GuiData
);
1182 GuiData
->IgnoreNextMouseSignal
= TRUE
;
1190 if (!(wParam
& MK_LBUTTON
)) break;
1191 if (!(Console
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1193 c
= PointToCoord(GuiData
, lParam
); /* TODO: Scroll buffer to bring c into view */
1194 GuiConsoleUpdateSelection(Console
, &c
);
1200 Err
= FALSE
; // TRUE;
1204 else if (Console
->InputBuffer
.Mode
& ENABLE_MOUSE_INPUT
)
1207 WORD wKeyState
= GET_KEYSTATE_WPARAM(wParam
);
1208 DWORD dwButtonState
= 0;
1209 DWORD dwControlKeyState
= 0;
1210 DWORD dwEventFlags
= 0;
1214 case WM_LBUTTONDOWN
:
1215 SetCapture(GuiData
->hWindow
);
1216 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1220 case WM_MBUTTONDOWN
:
1221 SetCapture(GuiData
->hWindow
);
1222 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1226 case WM_RBUTTONDOWN
:
1227 SetCapture(GuiData
->hWindow
);
1228 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1250 case WM_LBUTTONDBLCLK
:
1251 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1252 dwEventFlags
= DOUBLE_CLICK
;
1255 case WM_MBUTTONDBLCLK
:
1256 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1257 dwEventFlags
= DOUBLE_CLICK
;
1260 case WM_RBUTTONDBLCLK
:
1261 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1262 dwEventFlags
= DOUBLE_CLICK
;
1267 dwEventFlags
= MOUSE_MOVED
;
1271 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1272 dwEventFlags
= MOUSE_WHEELED
;
1275 case WM_MOUSEHWHEEL
:
1276 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1277 dwEventFlags
= MOUSE_HWHEELED
;
1287 if (wKeyState
& MK_LBUTTON
)
1288 dwButtonState
|= FROM_LEFT_1ST_BUTTON_PRESSED
;
1289 if (wKeyState
& MK_MBUTTON
)
1290 dwButtonState
|= FROM_LEFT_2ND_BUTTON_PRESSED
;
1291 if (wKeyState
& MK_RBUTTON
)
1292 dwButtonState
|= RIGHTMOST_BUTTON_PRESSED
;
1294 if (GetKeyState(VK_RMENU
) & 0x8000)
1295 dwControlKeyState
|= RIGHT_ALT_PRESSED
;
1296 if (GetKeyState(VK_LMENU
) & 0x8000)
1297 dwControlKeyState
|= LEFT_ALT_PRESSED
;
1298 if (GetKeyState(VK_RCONTROL
) & 0x8000)
1299 dwControlKeyState
|= RIGHT_CTRL_PRESSED
;
1300 if (GetKeyState(VK_LCONTROL
) & 0x8000)
1301 dwControlKeyState
|= LEFT_CTRL_PRESSED
;
1302 if (GetKeyState(VK_SHIFT
) & 0x8000)
1303 dwControlKeyState
|= SHIFT_PRESSED
;
1304 if (GetKeyState(VK_NUMLOCK
) & 0x0001)
1305 dwControlKeyState
|= NUMLOCK_ON
;
1306 if (GetKeyState(VK_SCROLL
) & 0x0001)
1307 dwControlKeyState
|= SCROLLLOCK_ON
;
1308 if (GetKeyState(VK_CAPITAL
) & 0x0001)
1309 dwControlKeyState
|= CAPSLOCK_ON
;
1310 /* See WM_CHAR MSDN documentation for instance */
1311 if (lParam
& 0x01000000)
1312 dwControlKeyState
|= ENHANCED_KEY
;
1314 er
.EventType
= MOUSE_EVENT
;
1315 er
.Event
.MouseEvent
.dwMousePosition
= PointToCoord(GuiData
, lParam
);
1316 er
.Event
.MouseEvent
.dwButtonState
= dwButtonState
;
1317 er
.Event
.MouseEvent
.dwControlKeyState
= dwControlKeyState
;
1318 er
.Event
.MouseEvent
.dwEventFlags
= dwEventFlags
;
1320 ConioProcessInputEvent(Console
, &er
);
1328 LeaveCriticalSection(&Console
->Lock
);
1332 return DefWindowProcW(GuiData
->hWindow
, msg
, wParam
, lParam
);
1337 VOID
GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
);
1338 VOID
GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
);
1341 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData
)
1343 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1345 PCONSOLE Console
= GuiData
->Console
;
1346 PCONSOLE_SCREEN_BUFFER Buffer
= ConDrvGetActiveScreenBuffer(Console
);
1348 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1350 GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
);
1352 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1354 GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
);
1359 /* Clear the selection */
1360 GuiConsoleUpdateSelection(Console
, NULL
);
1361 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
1365 VOID
GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
);
1366 VOID
GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
);
1369 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData
)
1371 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1373 PCONSOLE Console
= GuiData
->Console
;
1374 PCONSOLE_SCREEN_BUFFER Buffer
= ConDrvGetActiveScreenBuffer(Console
);
1376 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1378 GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
);
1380 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1382 GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
);
1390 GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData
, PMINMAXINFO minMaxInfo
)
1392 PCONSOLE Console
= GuiData
->Console
;
1393 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
1395 UINT WidthUnit
, HeightUnit
;
1397 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1399 ActiveBuffer
= ConDrvGetActiveScreenBuffer(Console
);
1401 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1403 windx
= CONGUI_MIN_WIDTH
* WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1404 windy
= CONGUI_MIN_HEIGHT
* HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1406 minMaxInfo
->ptMinTrackSize
.x
= windx
;
1407 minMaxInfo
->ptMinTrackSize
.y
= windy
;
1409 windx
= (ActiveBuffer
->ScreenBufferSize
.X
) * WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1410 windy
= (ActiveBuffer
->ScreenBufferSize
.Y
) * HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1412 if (ActiveBuffer
->ViewSize
.X
< ActiveBuffer
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1413 if (ActiveBuffer
->ViewSize
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1415 minMaxInfo
->ptMaxTrackSize
.x
= windx
;
1416 minMaxInfo
->ptMaxTrackSize
.y
= windy
;
1418 LeaveCriticalSection(&Console
->Lock
);
1422 GuiConsoleResize(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
1424 PCONSOLE Console
= GuiData
->Console
;
1426 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1428 if ((GuiData
->WindowSizeLock
== FALSE
) &&
1429 (wParam
== SIZE_RESTORED
|| wParam
== SIZE_MAXIMIZED
|| wParam
== SIZE_MINIMIZED
))
1431 PCONSOLE_SCREEN_BUFFER Buff
= ConDrvGetActiveScreenBuffer(Console
);
1432 DWORD windx
, windy
, charx
, chary
;
1433 UINT WidthUnit
, HeightUnit
;
1435 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1437 GuiData
->WindowSizeLock
= TRUE
;
1439 windx
= LOWORD(lParam
);
1440 windy
= HIWORD(lParam
);
1442 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
1443 if (Buff
->ViewSize
.X
< Buff
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1444 if (Buff
->ViewSize
.Y
< Buff
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1446 charx
= windx
/ (int)WidthUnit
;
1447 chary
= windy
/ (int)HeightUnit
;
1449 // Character alignment (round size up or down)
1450 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
1451 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
1453 // Compensate for added scroll bars in new window
1454 if (charx
< Buff
->ScreenBufferSize
.X
) windy
-= GetSystemMetrics(SM_CYHSCROLL
); // new window will have a horizontal scroll bar
1455 if (chary
< Buff
->ScreenBufferSize
.Y
) windx
-= GetSystemMetrics(SM_CXVSCROLL
); // new window will have a vertical scroll bar
1457 charx
= windx
/ (int)WidthUnit
;
1458 chary
= windy
/ (int)HeightUnit
;
1460 // Character alignment (round size up or down)
1461 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
1462 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
1465 if ((charx
!= Buff
->ViewSize
.X
) || (chary
!= Buff
->ViewSize
.Y
))
1467 Buff
->ViewSize
.X
= (charx
<= Buff
->ScreenBufferSize
.X
) ? charx
: Buff
->ScreenBufferSize
.X
;
1468 Buff
->ViewSize
.Y
= (chary
<= Buff
->ScreenBufferSize
.Y
) ? chary
: Buff
->ScreenBufferSize
.Y
;
1471 GuiConsoleResizeWindow(GuiData
);
1473 // Adjust the start of the visible area if we are attempting to show nonexistent areas
1474 if ((Buff
->ScreenBufferSize
.X
- Buff
->ViewOrigin
.X
) < Buff
->ViewSize
.X
) Buff
->ViewOrigin
.X
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
1475 if ((Buff
->ScreenBufferSize
.Y
- Buff
->ViewOrigin
.Y
) < Buff
->ViewSize
.Y
) Buff
->ViewOrigin
.Y
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
1476 InvalidateRect(GuiData
->hWindow
, NULL
, TRUE
);
1478 GuiData
->WindowSizeLock
= FALSE
;
1481 LeaveCriticalSection(&Console
->Lock
);
1485 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
1489 GuiConsoleHandleScrollbarMenu(VOID)
1493 hMenu = CreatePopupMenu();
1496 DPRINT("CreatePopupMenu failed\n");
1500 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1501 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1502 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1503 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1504 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1505 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1506 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1507 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1508 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1509 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1514 GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData
, UINT uMsg
, WPARAM wParam
)
1516 PCONSOLE Console
= GuiData
->Console
;
1517 PCONSOLE_SCREEN_BUFFER Buff
;
1520 int old_pos
, Maximum
;
1523 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return 0;
1525 Buff
= ConDrvGetActiveScreenBuffer(Console
);
1527 if (uMsg
== WM_HSCROLL
)
1530 Maximum
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
1531 pShowXY
= &Buff
->ViewOrigin
.X
;
1536 Maximum
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
1537 pShowXY
= &Buff
->ViewOrigin
.Y
;
1540 /* set scrollbar sizes */
1541 sInfo
.cbSize
= sizeof(SCROLLINFO
);
1542 sInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
| SIF_TRACKPOS
;
1544 if (!GetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
)) goto Quit
;
1546 old_pos
= sInfo
.nPos
;
1548 switch (LOWORD(wParam
))
1559 sInfo
.nPos
-= sInfo
.nPage
;
1563 sInfo
.nPos
+= sInfo
.nPage
;
1567 sInfo
.nPos
= sInfo
.nTrackPos
;
1568 ConioPause(Console
, PAUSED_FROM_SCROLLBAR
);
1571 case SB_THUMBPOSITION
:
1572 ConioUnpause(Console
, PAUSED_FROM_SCROLLBAR
);
1576 sInfo
.nPos
= sInfo
.nMin
;
1580 sInfo
.nPos
= sInfo
.nMax
;
1587 sInfo
.nPos
= max(sInfo
.nPos
, 0);
1588 sInfo
.nPos
= min(sInfo
.nPos
, Maximum
);
1590 if (old_pos
!= sInfo
.nPos
)
1592 USHORT OldX
= Buff
->ViewOrigin
.X
;
1593 USHORT OldY
= Buff
->ViewOrigin
.Y
;
1594 UINT WidthUnit
, HeightUnit
;
1596 *pShowXY
= sInfo
.nPos
;
1598 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1600 ScrollWindowEx(GuiData
->hWindow
,
1601 (OldX
- Buff
->ViewOrigin
.X
) * WidthUnit
,
1602 (OldY
- Buff
->ViewOrigin
.Y
) * HeightUnit
,
1609 sInfo
.fMask
= SIF_POS
;
1610 SetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
, TRUE
);
1612 UpdateWindow(GuiData
->hWindow
);
1616 LeaveCriticalSection(&Console
->Lock
);
1620 static LRESULT CALLBACK
1621 GuiConsoleWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1624 PGUI_CONSOLE_DATA GuiData
= NULL
;
1625 PCONSOLE Console
= NULL
;
1628 * - If it's the first time we create a window for the terminal,
1629 * just initialize it and return.
1631 * - If we are destroying the window, just do it and return.
1633 if (msg
== WM_NCCREATE
)
1635 return (LRESULT
)GuiConsoleHandleNcCreate(hWnd
, (LPCREATESTRUCTW
)lParam
);
1637 else if (msg
== WM_NCDESTROY
)
1639 return GuiConsoleHandleNcDestroy(hWnd
);
1643 * Now the terminal window is initialized.
1644 * Get the terminal data via the window's data.
1645 * If there is no data, just go away.
1647 GuiData
= GuiGetGuiData(hWnd
);
1648 if (GuiData
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1651 * Just retrieve a pointer to the console in case somebody needs it.
1652 * It is not NULL because it was checked in GuiGetGuiData.
1653 * Each helper function which needs the console has to validate and lock it.
1655 Console
= GuiData
->Console
;
1657 /* We have a console, start message dispatching */
1662 if (LOWORD(wParam
) == WA_CLICKACTIVE
) GuiData
->IgnoreNextMouseSignal
= TRUE
;
1667 if (GuiConsoleHandleClose(GuiData
)) goto Default
;
1671 GuiConsoleHandlePaint(GuiData
);
1681 case WM_SYSDEADCHAR
:
1683 /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */
1684 if (msg
== WM_SYSKEYDOWN
&& (HIWORD(lParam
) & KF_ALTDOWN
) && wParam
== VK_RETURN
)
1686 /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */
1687 if ((HIWORD(lParam
) & (KF_UP
| KF_REPEAT
)) != KF_REPEAT
) GuiConsoleSwitchFullScreen(GuiData
);
1691 GuiConsoleHandleKey(GuiData
, msg
, wParam
, lParam
);
1696 GuiConsoleHandleTimer(GuiData
);
1702 * The message was sent because we are manually triggering a change.
1703 * Check whether the mouse is indeed present on this console window
1704 * and take appropriate decisions.
1706 if (wParam
== -1 && lParam
== -1)
1711 /* Get the placement of the mouse */
1712 GetCursorPos(&mouseCoords
);
1714 /* On which window is placed the mouse ? */
1715 hWndHit
= WindowFromPoint(mouseCoords
);
1717 /* It's our window. Perform the hit-test to be used later on. */
1718 if (hWndHit
== hWnd
)
1720 wParam
= (WPARAM
)hWnd
;
1721 lParam
= DefWindowProcW(hWndHit
, WM_NCHITTEST
, 0,
1722 MAKELPARAM(mouseCoords
.x
, mouseCoords
.y
));
1726 /* Set the mouse cursor only when we are in the client area */
1727 if ((HWND
)wParam
== hWnd
&& LOWORD(lParam
) == HTCLIENT
)
1729 if (GuiData
->MouseCursorRefCount
>= 0)
1731 /* Show the cursor */
1732 SetCursor(GuiData
->hCursor
);
1736 /* Hide the cursor if the reference count is negative */
1747 case WM_LBUTTONDOWN
:
1748 case WM_MBUTTONDOWN
:
1749 case WM_RBUTTONDOWN
:
1753 case WM_LBUTTONDBLCLK
:
1754 case WM_MBUTTONDBLCLK
:
1755 case WM_RBUTTONDBLCLK
:
1758 case WM_MOUSEHWHEEL
:
1760 Result
= GuiConsoleHandleMouse(GuiData
, msg
, wParam
, lParam
);
1767 Result
= GuiConsoleHandleScroll(GuiData
, msg
, wParam
);
1771 case WM_NCRBUTTONDOWN
:
1773 DPRINT1("WM_NCRBUTTONDOWN\n");
1775 * HACK: !! Because, when we deal with WM_RBUTTON* and we do not
1776 * call after that DefWindowProc, on ReactOS, right-clicks on the
1777 * (non-client) application title-bar does not display the system
1778 * menu and does not trigger a WM_NCRBUTTONUP message too.
1779 * See: http://git.reactos.org/?p=reactos.git;a=blob;f=reactos/win32ss/user/user32/windows/defwnd.c;hb=HEAD#l1103
1780 * and line 1135 too.
1782 if (DefWindowProcW(hWnd
, WM_NCHITTEST
, 0, lParam
) == HTCAPTION
)
1784 /* Call DefWindowProcW with the WM_CONTEXTMENU message */
1785 msg
= WM_CONTEXTMENU
;
1789 // case WM_NCRBUTTONUP:
1790 // DPRINT1("WM_NCRBUTTONUP\n");
1793 case WM_CONTEXTMENU
:
1795 if (DefWindowProcW(hWnd
/*GuiData->hWindow*/, WM_NCHITTEST
, 0, lParam
) == HTCLIENT
)
1797 HMENU hMenu
= CreatePopupMenu();
1800 GuiConsoleAppendMenuItems(hMenu
, GuiConsoleEditMenuItems
);
1801 TrackPopupMenuEx(hMenu
,
1803 GET_X_LPARAM(lParam
),
1804 GET_Y_LPARAM(lParam
),
1819 HMENU hMenu
= (HMENU
)wParam
;
1822 /* Enable or disable the Close menu item */
1823 EnableMenuItem(hMenu
, SC_CLOSE
, MF_BYCOMMAND
|
1824 (GuiData
->IsCloseButtonEnabled
? MF_ENABLED
: MF_GRAYED
));
1826 /* Enable or disable the Copy and Paste items */
1827 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_COPY
, MF_BYCOMMAND
|
1828 ((Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
1829 (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
) ? MF_ENABLED
: MF_GRAYED
));
1830 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_PASTE
, MF_BYCOMMAND
|
1831 (!(Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
1832 IsClipboardFormatAvailable(CF_UNICODETEXT
) ? MF_ENABLED
: MF_GRAYED
));
1835 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1837 GuiSendMenuEvent(Console
, WM_INITMENU
);
1838 LeaveCriticalSection(&Console
->Lock
);
1845 if (HIWORD(wParam
) == 0xFFFF) // Allow all the menu flags
1847 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1849 GuiSendMenuEvent(Console
, WM_MENUSELECT
);
1850 LeaveCriticalSection(&Console
->Lock
);
1859 Result
= GuiConsoleHandleSysMenuCommand(GuiData
, wParam
, lParam
);
1866 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1869 er
.EventType
= FOCUS_EVENT
;
1870 er
.Event
.FocusEvent
.bSetFocus
= (msg
== WM_SETFOCUS
);
1871 ConioProcessInputEvent(Console
, &er
);
1873 if (msg
== WM_SETFOCUS
)
1874 DPRINT1("TODO: Create console caret\n");
1875 else // if (msg == WM_KILLFOCUS)
1876 DPRINT1("TODO: Destroy console caret\n");
1878 LeaveCriticalSection(&Console
->Lock
);
1883 case WM_GETMINMAXINFO
:
1884 GuiConsoleGetMinMaxInfo(GuiData
, (PMINMAXINFO
)lParam
);
1888 GuiConsoleResize(GuiData
, wParam
, lParam
);
1891 case PM_RESIZE_TERMINAL
:
1893 /* Resize the window to the user's values */
1894 GuiData
->WindowSizeLock
= TRUE
;
1895 GuiConsoleResizeWindow(GuiData
);
1896 GuiData
->WindowSizeLock
= FALSE
;
1900 case PM_APPLY_CONSOLE_INFO
:
1902 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1904 GuiApplyUserSettings(GuiData
, (HANDLE
)wParam
, (BOOL
)lParam
);
1905 LeaveCriticalSection(&Console
->Lock
);
1910 case PM_CONSOLE_BEEP
:
1911 DPRINT1("Beep !!\n");
1915 // case PM_CONSOLE_SET_TITLE:
1916 // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
1920 Result
= DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1929 /******************************************************************************
1930 * GUI Terminal Initialization *
1931 ******************************************************************************/
1933 static LRESULT CALLBACK
1934 GuiConsoleNotifyWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1944 SetWindowLongW(hWnd
, GWL_USERDATA
, 0);
1948 case PM_CREATE_CONSOLE
:
1950 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
1951 PCONSOLE Console
= GuiData
->Console
;
1953 NewWindow
= CreateWindowExW(WS_EX_CLIENTEDGE
,
1954 GUI_CONSOLE_WINDOW_CLASS
,
1955 Console
->Title
.Buffer
,
1956 WS_OVERLAPPEDWINDOW
| WS_HSCROLL
| WS_VSCROLL
,
1965 if (NULL
!= NewWindow
)
1967 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
1969 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
1971 DPRINT("Set icons via PM_CREATE_CONSOLE\n");
1972 if (GuiData
->hIcon
== NULL
)
1974 DPRINT("Not really /o\\...\n");
1975 GuiData
->hIcon
= ghDefaultIcon
;
1976 GuiData
->hIconSm
= ghDefaultIconSm
;
1978 else if (GuiData
->hIcon
!= ghDefaultIcon
)
1980 DPRINT("Yes \\o/\n");
1981 SendMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
1982 SendMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
1985 /* Move and resize the window to the user's values */
1986 /* CAN WE DEADLOCK ?? */
1987 GuiConsoleMoveWindow(GuiData
);
1988 GuiData
->WindowSizeLock
= TRUE
;
1989 GuiConsoleResizeWindow(GuiData
);
1990 GuiData
->WindowSizeLock
= FALSE
;
1992 // ShowWindow(NewWindow, (int)wParam);
1993 ShowWindowAsync(NewWindow
, (int)wParam
);
1994 DPRINT("Window showed\n");
1997 return (LRESULT
)NewWindow
;
2000 case PM_DESTROY_CONSOLE
:
2002 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
2005 * Window creation is done using a PostMessage(), so it's possible
2006 * that the window that we want to destroy doesn't exist yet.
2007 * So first empty the message queue.
2010 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
2012 TranslateMessage(&Msg);
2013 DispatchMessageW(&Msg);
2015 while (PeekMessageW(&Msg
, NULL
, 0, 0, PM_REMOVE
)) ;
2017 if (GuiData
->hWindow
!= NULL
) /* && DestroyWindow(GuiData->hWindow) */
2019 DestroyWindow(GuiData
->hWindow
);
2021 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
2023 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
2024 if (0 == WindowCount
)
2027 DestroyWindow(hWnd
);
2028 DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
2037 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2042 GuiConsoleGuiThread(PVOID Data
)
2045 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Data
;
2048 * This thread dispatches all the console notifications to the notify window.
2049 * It is common for all the console windows.
2052 PrivateCsrssManualGuiCheck(+1);
2054 NotifyWnd
= CreateWindowW(L
"ConSrvCreateNotify",
2056 WS_OVERLAPPEDWINDOW
,
2065 if (NULL
== NotifyWnd
)
2067 PrivateCsrssManualGuiCheck(-1);
2068 SetEvent(*GraphicsStartupEvent
);
2072 SetEvent(*GraphicsStartupEvent
);
2074 while (GetMessageW(&msg
, NULL
, 0, 0))
2076 TranslateMessage(&msg
);
2077 DispatchMessageW(&msg
);
2080 DPRINT("CONSRV: Quit the Gui Thread!!\n");
2081 PrivateCsrssManualGuiCheck(-1);
2090 ATOM ConsoleClassAtom
;
2092 /* Exit if we were already initialized */
2093 // if (ConsInitialized) return TRUE;
2096 * Initialize and register the different window classes, if needed.
2098 if (!ConsInitialized
)
2100 /* Initialize the notification window class */
2101 wc
.cbSize
= sizeof(WNDCLASSEXW
);
2102 wc
.lpszClassName
= L
"ConSrvCreateNotify";
2103 wc
.lpfnWndProc
= GuiConsoleNotifyWndProc
;
2105 wc
.hInstance
= ConSrvDllInstance
;
2109 wc
.hbrBackground
= NULL
;
2110 wc
.lpszMenuName
= NULL
;
2113 if (RegisterClassExW(&wc
) == 0)
2115 DPRINT1("Failed to register GUI notify wndproc\n");
2119 /* Initialize the console window class */
2120 ghDefaultIcon
= LoadImageW(ConSrvDllInstance
,
2121 MAKEINTRESOURCEW(IDI_TERMINAL
),
2123 GetSystemMetrics(SM_CXICON
),
2124 GetSystemMetrics(SM_CYICON
),
2126 ghDefaultIconSm
= LoadImageW(ConSrvDllInstance
,
2127 MAKEINTRESOURCEW(IDI_TERMINAL
),
2129 GetSystemMetrics(SM_CXSMICON
),
2130 GetSystemMetrics(SM_CYSMICON
),
2132 ghDefaultCursor
= LoadCursorW(NULL
, IDC_ARROW
);
2133 wc
.cbSize
= sizeof(WNDCLASSEXW
);
2134 wc
.lpszClassName
= GUI_CONSOLE_WINDOW_CLASS
;
2135 wc
.lpfnWndProc
= GuiConsoleWndProc
;
2136 wc
.style
= CS_DBLCLKS
/* | CS_HREDRAW | CS_VREDRAW */;
2137 wc
.hInstance
= ConSrvDllInstance
;
2138 wc
.hIcon
= ghDefaultIcon
;
2139 wc
.hIconSm
= ghDefaultIconSm
;
2140 wc
.hCursor
= ghDefaultCursor
;
2141 wc
.hbrBackground
= (HBRUSH
)GetStockObject(BLACK_BRUSH
); // The color of a terminal when it is switch off.
2142 wc
.lpszMenuName
= NULL
;
2144 wc
.cbWndExtra
= GWLP_CONSOLEWND_ALLOC
;
2146 ConsoleClassAtom
= RegisterClassExW(&wc
);
2147 if (ConsoleClassAtom
== 0)
2149 DPRINT1("Failed to register GUI console wndproc\n");
2154 NtUserConsoleControl(GuiConsoleWndClassAtom
, &ConsoleClassAtom
, sizeof(ATOM
));
2157 ConsInitialized
= TRUE
;
2161 * Set-up the notification window
2163 if (NULL
== NotifyWnd
)
2165 HANDLE ThreadHandle
;
2166 HANDLE GraphicsStartupEvent
;
2168 GraphicsStartupEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2169 if (NULL
== GraphicsStartupEvent
) return FALSE
;
2171 ThreadHandle
= CreateThread(NULL
,
2173 GuiConsoleGuiThread
,
2174 (PVOID
)&GraphicsStartupEvent
,
2177 if (NULL
== ThreadHandle
)
2179 CloseHandle(GraphicsStartupEvent
);
2180 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
2183 SetThreadPriority(ThreadHandle
, THREAD_PRIORITY_HIGHEST
);
2184 CloseHandle(ThreadHandle
);
2186 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
2187 CloseHandle(GraphicsStartupEvent
);
2189 if (NULL
== NotifyWnd
)
2191 DPRINT1("CONSRV: Failed to create notification window.\n");
2196 // ConsInitialized = TRUE;
2203 /******************************************************************************
2204 * GUI Console Driver *
2205 ******************************************************************************/
2208 GuiDeinitFrontEnd(IN OUT PFRONTEND This
);
2211 GuiInitFrontEnd(IN OUT PFRONTEND This
,
2212 IN PCONSOLE Console
)
2214 PGUI_INIT_INFO GuiInitInfo
;
2215 PCONSOLE_INFO ConsoleInfo
;
2216 PCONSOLE_START_INFO ConsoleStartInfo
;
2218 PGUI_CONSOLE_DATA GuiData
;
2219 GUI_CONSOLE_INFO TermInfo
;
2222 LPWSTR IconPath
= NULL
;
2225 if (This
== NULL
|| Console
== NULL
|| This
->OldData
== NULL
)
2226 return STATUS_INVALID_PARAMETER
;
2228 ASSERT(This
->Console
== Console
);
2230 GuiInitInfo
= This
->OldData
;
2232 if (GuiInitInfo
->ConsoleInfo
== NULL
|| GuiInitInfo
->ConsoleStartInfo
== NULL
)
2233 return STATUS_INVALID_PARAMETER
;
2235 ConsoleInfo
= GuiInitInfo
->ConsoleInfo
;
2236 ConsoleStartInfo
= GuiInitInfo
->ConsoleStartInfo
;
2238 IconPath
= ConsoleStartInfo
->IconPath
;
2239 IconIndex
= ConsoleStartInfo
->IconIndex
;
2242 /* Terminal data allocation */
2243 GuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_CONSOLE_DATA
));
2246 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
2247 return STATUS_UNSUCCESSFUL
;
2249 /* HACK */ Console
->TermIFace
.Data
= (PVOID
)GuiData
; /* HACK */
2250 GuiData
->Console
= Console
;
2251 GuiData
->hWindow
= NULL
;
2253 /* The console can be resized */
2254 Console
->FixedSize
= FALSE
;
2256 InitializeCriticalSection(&GuiData
->Lock
);
2260 * Load terminal settings
2263 /* 1. Load the default settings */
2264 GuiConsoleGetDefaultSettings(&TermInfo
, GuiInitInfo
->ProcessId
);
2266 /* 3. Load the remaining console settings via the registry. */
2267 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
2269 /* Load the terminal infos from the registry. */
2270 GuiConsoleReadUserSettings(&TermInfo
,
2271 ConsoleInfo
->ConsoleTitle
,
2272 GuiInitInfo
->ProcessId
);
2275 * Now, update them with the properties the user might gave to us
2276 * via the STARTUPINFO structure before calling CreateProcess
2277 * (and which was transmitted via the ConsoleStartInfo structure).
2278 * We therefore overwrite the values read in the registry.
2280 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
2282 TermInfo
.ShowWindow
= ConsoleStartInfo
->ShowWindow
;
2284 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
2286 TermInfo
.AutoPosition
= FALSE
;
2287 TermInfo
.WindowOrigin
= ConsoleStartInfo
->ConsoleWindowOrigin
;
2289 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
2291 TermInfo
.FullScreen
= TRUE
;
2300 Length
= min(wcslen(TermInfo
.FaceName
) + 1, LF_FACESIZE
); // wcsnlen
2301 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
2302 GuiData
->GuiInfo
.FaceName
[Length
] = L
'\0';
2303 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
2304 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
2305 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
2306 GuiData
->GuiInfo
.UseRasterFonts
= TermInfo
.UseRasterFonts
;
2307 GuiData
->GuiInfo
.FullScreen
= TermInfo
.FullScreen
;
2308 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
2309 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
2310 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
2312 /* Initialize the icon handles to their default values */
2313 GuiData
->hIcon
= ghDefaultIcon
;
2314 GuiData
->hIconSm
= ghDefaultIconSm
;
2316 /* Get the associated icon, if any */
2317 if (IconPath
== NULL
|| IconPath
[0] == L
'\0')
2319 IconPath
= ConsoleStartInfo
->AppPath
;
2322 DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath
? IconPath
: L
"n/a"), IconIndex
);
2323 if (IconPath
&& IconPath
[0] != L
'\0')
2325 HICON hIcon
= NULL
, hIconSm
= NULL
;
2326 PrivateExtractIconExW(IconPath
,
2331 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon
, hIconSm
);
2334 DPRINT("Effectively set the icons\n");
2335 GuiData
->hIcon
= hIcon
;
2336 GuiData
->hIconSm
= hIconSm
;
2340 /* Mouse is shown by default with its default cursor shape */
2341 GuiData
->hCursor
= ghDefaultCursor
;
2342 GuiData
->MouseCursorRefCount
= 0;
2344 /* A priori don't ignore mouse signals */
2345 GuiData
->IgnoreNextMouseSignal
= FALSE
;
2347 /* Close button and the corresponding system menu item are enabled by default */
2348 GuiData
->IsCloseButtonEnabled
= TRUE
;
2350 /* There is no user-reserved menu id range by default */
2351 GuiData
->cmdIdLow
= GuiData
->cmdIdHigh
= 0;
2354 * We need to wait until the GUI has been fully initialized
2355 * to retrieve custom settings i.e. WindowSize etc...
2356 * Ideally we could use SendNotifyMessage for this but its not
2359 GuiData
->hGuiInitEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2361 DPRINT("GUI - Checkpoint\n");
2363 /* Create the terminal window */
2364 PostMessageW(NotifyWnd
, PM_CREATE_CONSOLE
, GuiData
->GuiInfo
.ShowWindow
, (LPARAM
)GuiData
);
2366 /* Wait until initialization has finished */
2367 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
2368 DPRINT("OK we created the console window\n");
2369 CloseHandle(GuiData
->hGuiInitEvent
);
2370 GuiData
->hGuiInitEvent
= NULL
;
2372 /* Check whether we really succeeded in initializing the terminal window */
2373 if (GuiData
->hWindow
== NULL
)
2375 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
2376 GuiDeinitFrontEnd(This
);
2377 return STATUS_UNSUCCESSFUL
;
2380 /* Finally, finish to initialize the frontend structure */
2381 This
->Data
= GuiData
;
2382 if (This
->OldData
) ConsoleFreeHeap(This
->OldData
);
2383 This
->OldData
= NULL
;
2385 return STATUS_SUCCESS
;
2389 GuiDeinitFrontEnd(IN OUT PFRONTEND This
)
2391 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2393 SendMessageW(NotifyWnd
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
2395 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
2396 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
2397 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
2399 DPRINT("Destroy hIcon\n");
2400 DestroyIcon(GuiData
->hIcon
);
2402 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
2404 DPRINT("Destroy hIconSm\n");
2405 DestroyIcon(GuiData
->hIconSm
);
2409 DeleteCriticalSection(&GuiData
->Lock
);
2410 ConsoleFreeHeap(GuiData
);
2412 DPRINT("Quit GuiDeinitFrontEnd\n");
2416 GuiDrawRegion(IN OUT PFRONTEND This
,
2419 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2422 SmallRectToRect(GuiData
, &RegionRect
, Region
);
2423 /* Do not erase the background: it speeds up redrawing and reduce flickering */
2424 InvalidateRect(GuiData
->hWindow
, &RegionRect
, FALSE
);
2428 GuiWriteStream(IN OUT PFRONTEND This
,
2436 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2437 PCONSOLE_SCREEN_BUFFER Buff
;
2438 SHORT CursorEndX
, CursorEndY
;
2441 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
) return;
2443 Buff
= ConDrvGetActiveScreenBuffer(GuiData
->Console
);
2444 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
2446 if (0 != ScrolledLines
)
2448 ScrollRect
.left
= 0;
2450 ScrollRect
.right
= Buff
->ViewSize
.X
* GuiData
->CharWidth
;
2451 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
2453 ScrollWindowEx(GuiData
->hWindow
,
2455 -(int)(ScrolledLines
* GuiData
->CharHeight
),
2463 GuiDrawRegion(This
, Region
);
2465 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
2466 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
2468 GuiInvalidateCell(This
, CursorStartX
, CursorStartY
);
2471 CursorEndX
= Buff
->CursorPosition
.X
;
2472 CursorEndY
= Buff
->CursorPosition
.Y
;
2473 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
2474 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
2475 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
2477 GuiInvalidateCell(This
, CursorEndX
, CursorEndY
);
2480 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
2481 // repaint the window without having it just freeze up and stay on the screen permanently.
2482 Buff
->CursorBlinkOn
= TRUE
;
2483 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
2487 GuiSetCursorInfo(IN OUT PFRONTEND This
,
2488 PCONSOLE_SCREEN_BUFFER Buff
)
2490 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2492 if (ConDrvGetActiveScreenBuffer(GuiData
->Console
) == Buff
)
2494 GuiInvalidateCell(This
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
2501 GuiSetScreenInfo(IN OUT PFRONTEND This
,
2502 PCONSOLE_SCREEN_BUFFER Buff
,
2506 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2508 if (ConDrvGetActiveScreenBuffer(GuiData
->Console
) == Buff
)
2510 /* Redraw char at old position (remove cursor) */
2511 GuiInvalidateCell(This
, OldCursorX
, OldCursorY
);
2512 /* Redraw char at new position (show cursor) */
2513 GuiInvalidateCell(This
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
2520 GuiResizeTerminal(IN OUT PFRONTEND This
)
2522 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2524 /* Resize the window to the user's values */
2525 // GuiData->WindowSizeLock = TRUE;
2526 // GuiConsoleResizeWindow(GuiData);
2527 // GuiData->WindowSizeLock = FALSE;
2528 // NOTE: This code ^^ causes deadlocks...
2530 PostMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
2534 GuiProcessKeyCallback(IN OUT PFRONTEND This
,
2538 UINT VirtualKeyCode
,
2541 if ((ShiftState
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
) || KeyStateMenu
& 0x80) &&
2542 (VirtualKeyCode
== VK_ESCAPE
|| VirtualKeyCode
== VK_TAB
|| VirtualKeyCode
== VK_SPACE
))
2544 DefWindowProcW(msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
2552 GuiSetMouseCursor(IN OUT PFRONTEND This
,
2556 GuiRefreshInternalInfo(IN OUT PFRONTEND This
)
2558 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2560 /* Update the console leader information held by the window */
2561 SetConsoleWndConsoleLeaderCID(GuiData
);
2565 * We reset the cursor here so that, when a console app quits, we reset
2566 * the cursor to the default one. It's quite a hack since it doesn't proceed
2567 * per - console process... This must be fixed.
2569 * See GuiInitConsole(...) for more information.
2572 /* Mouse is shown by default with its default cursor shape */
2573 GuiData
->MouseCursorRefCount
= 0; // Reinitialize the reference counter
2574 GuiSetMouseCursor(This
, NULL
);
2578 GuiChangeTitle(IN OUT PFRONTEND This
)
2580 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2581 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
2582 SetWindowText(GuiData
->hWindow
, GuiData
->Console
->Title
.Buffer
);
2586 GuiChangeIcon(IN OUT PFRONTEND This
,
2589 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2590 HICON hIcon
, hIconSm
;
2592 if (hWindowIcon
== NULL
)
2594 hIcon
= ghDefaultIcon
;
2595 hIconSm
= ghDefaultIconSm
;
2599 hIcon
= CopyIcon(hWindowIcon
);
2600 hIconSm
= CopyIcon(hWindowIcon
);
2608 if (hIcon
!= GuiData
->hIcon
)
2610 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
2612 DestroyIcon(GuiData
->hIcon
);
2614 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
2616 DestroyIcon(GuiData
->hIconSm
);
2619 GuiData
->hIcon
= hIcon
;
2620 GuiData
->hIconSm
= hIconSm
;
2622 DPRINT("Set icons in GuiChangeIcon\n");
2623 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
2624 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
2631 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
2633 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2634 return GuiData
->hWindow
;
2638 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
2641 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2642 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
2645 UINT WidthUnit
, HeightUnit
;
2649 if (!SystemParametersInfoW(SPI_GETWORKAREA
, 0, &WorkArea
, 0))
2651 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
2655 ActiveBuffer
= ConDrvGetActiveScreenBuffer(GuiData
->Console
);
2658 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
2662 /* Default: text mode */
2663 WidthUnit
= GuiData
->CharWidth
;
2664 HeightUnit
= GuiData
->CharHeight
;
2667 width
= WorkArea
.right
;
2668 height
= WorkArea
.bottom
;
2670 width
-= (2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
)));
2671 height
-= (2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
));
2673 if (width
< 0) width
= 0;
2674 if (height
< 0) height
= 0;
2676 pSize
->X
= (SHORT
)(width
/ (int)WidthUnit
) /* HACK */ + 2;
2677 pSize
->Y
= (SHORT
)(height
/ (int)HeightUnit
) /* HACK */ + 1;
2681 GuiGetDisplayMode(IN OUT PFRONTEND This
)
2683 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2684 ULONG DisplayMode
= 0;
2686 if (GuiData
->GuiInfo
.FullScreen
)
2687 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
2689 DisplayMode
|= CONSOLE_WINDOWED
;
2695 GuiSetDisplayMode(IN OUT PFRONTEND This
,
2698 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2700 if (NewMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
2703 GuiData
->GuiInfo
.FullScreen
= (NewMode
& CONSOLE_FULLSCREEN_MODE
);
2704 // TODO: Change the display mode
2709 GuiShowMouseCursor(IN OUT PFRONTEND This
,
2712 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2714 /* Set the reference count */
2715 if (Show
) ++GuiData
->MouseCursorRefCount
;
2716 else --GuiData
->MouseCursorRefCount
;
2718 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
2719 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
2721 return GuiData
->MouseCursorRefCount
;
2725 GuiSetMouseCursor(IN OUT PFRONTEND This
,
2728 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2731 * Set the cursor's handle. If the given handle is NULL,
2732 * then restore the default cursor.
2734 GuiData
->hCursor
= (hCursor
? hCursor
: ghDefaultCursor
);
2736 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
2737 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
2743 GuiMenuControl(IN OUT PFRONTEND This
,
2747 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2749 GuiData
->cmdIdLow
= cmdIdLow
;
2750 GuiData
->cmdIdHigh
= cmdIdHigh
;
2752 return GetSystemMenu(GuiData
->hWindow
, FALSE
);
2756 GuiSetMenuClose(IN OUT PFRONTEND This
,
2760 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
2761 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
2762 * for more information.
2765 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2766 HMENU hSysMenu
= GetSystemMenu(GuiData
->hWindow
, FALSE
);
2768 if (hSysMenu
== NULL
) return FALSE
;
2770 GuiData
->IsCloseButtonEnabled
= Enable
;
2771 EnableMenuItem(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
| (Enable
? MF_ENABLED
: MF_GRAYED
));
2776 static FRONTEND_VTBL GuiVtbl
=
2785 GuiProcessKeyCallback
,
2786 GuiRefreshInternalInfo
,
2789 GuiGetConsoleWindowHandle
,
2790 GuiGetLargestConsoleWindowSize
,
2801 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
2802 IN OUT PCONSOLE_INFO ConsoleInfo
)
2804 #define PATH_SEPARATOR L'\\'
2806 BOOL RetVal
= FALSE
;
2807 HRESULT hRes
= S_OK
;
2808 LPWSTR LinkName
= NULL
;
2811 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
2814 ConsoleStartInfo
->IconPath
[0] = L
'\0';
2815 ConsoleStartInfo
->IconIndex
= 0;
2817 /* 1- Find the last path separator if any */
2818 LinkName
= wcsrchr(ConsoleStartInfo
->ConsoleTitle
, PATH_SEPARATOR
);
2819 if (LinkName
== NULL
)
2821 LinkName
= ConsoleStartInfo
->ConsoleTitle
;
2825 /* Skip the path separator */
2829 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
2830 Length
= wcslen(LinkName
);
2831 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
2834 /* 3- It may be a link. Try to retrieve some properties */
2835 hRes
= CoInitialize(NULL
);
2836 if (SUCCEEDED(hRes
))
2838 /* Get a pointer to the IShellLink interface */
2839 IShellLinkW
* pshl
= NULL
;
2840 hRes
= CoCreateInstance(&CLSID_ShellLink
,
2842 CLSCTX_INPROC_SERVER
,
2845 if (SUCCEEDED(hRes
))
2847 /* Get a pointer to the IPersistFile interface */
2848 IPersistFile
* ppf
= NULL
;
2849 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
2850 if (SUCCEEDED(hRes
))
2852 /* Load the shortcut */
2853 hRes
= IPersistFile_Load(ppf
, ConsoleStartInfo
->ConsoleTitle
, STGM_READ
);
2854 if (SUCCEEDED(hRes
))
2857 * Finally we can get the properties !
2858 * Update the old ones if needed.
2863 /* Reset the name of the console with the name of the shortcut */
2864 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
2865 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
2866 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
2867 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
2869 /* Get the window showing command */
2870 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
2871 if (SUCCEEDED(hRes
)) ConsoleStartInfo
->ShowWindow
= (WORD
)ShowCmd
;
2873 /* Get the hotkey */
2874 // hRes = pshl->GetHotkey(&ShowCmd);
2875 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
2877 /* Get the icon location, if any */
2879 hRes
= IShellLinkW_GetIconLocation(pshl
,
2880 ConsoleStartInfo
->IconPath
,
2881 sizeof(ConsoleStartInfo
->IconPath
)/sizeof(ConsoleStartInfo
->IconPath
[0]) - 1, // == MAX_PATH
2882 &ConsoleStartInfo
->IconIndex
);
2883 if (!SUCCEEDED(hRes
))
2885 ConsoleStartInfo
->IconPath
[0] = L
'\0';
2886 ConsoleStartInfo
->IconIndex
= 0;
2889 // FIXME: Since we still don't load console properties from the shortcut,
2890 // return false. When this will be done, we will return true instead.
2893 IPersistFile_Release(ppf
);
2895 IShellLinkW_Release(pshl
);
2904 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
2905 IN OUT PCONSOLE_INFO ConsoleInfo
,
2906 IN OUT PVOID ExtraConsoleInfo
,
2909 PCONSOLE_START_INFO ConsoleStartInfo
= ExtraConsoleInfo
;
2910 PGUI_INIT_INFO GuiInitInfo
;
2912 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
|| ConsoleStartInfo
== NULL
)
2913 return STATUS_INVALID_PARAMETER
;
2915 /* Initialize GUI terminal emulator common functionalities */
2916 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
2919 * Load per-application terminal settings.
2921 * Check whether the process creating the console was launched via
2922 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
2923 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
2925 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
)
2927 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo
, ConsoleInfo
))
2929 ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
2934 * Initialize a private initialization info structure for later use.
2935 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
2937 GuiInitInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_INIT_INFO
));
2938 if (GuiInitInfo
== NULL
) return STATUS_NO_MEMORY
;
2940 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
2941 GuiInitInfo
->ConsoleInfo
= ConsoleInfo
;
2942 GuiInitInfo
->ConsoleStartInfo
= ConsoleStartInfo
;
2943 GuiInitInfo
->ProcessId
= ProcessId
;
2945 /* Finally, initialize the frontend structure */
2946 FrontEnd
->Vtbl
= &GuiVtbl
;
2947 FrontEnd
->Data
= NULL
;
2948 FrontEnd
->OldData
= GuiInitInfo
;
2950 return STATUS_SUCCESS
;
2954 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
2956 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
2958 if (FrontEnd
->Data
) GuiDeinitFrontEnd(FrontEnd
);
2959 if (FrontEnd
->OldData
) ConsoleFreeHeap(FrontEnd
->OldData
);
2961 return STATUS_SUCCESS
;