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 *******************************************************************/
25 // HACK!! Remove it when the hack in GuiWriteStream is fixed
26 #define CONGUI_UPDATE_TIME 0
27 #define CONGUI_UPDATE_TIMER 1
29 #define PM_CREATE_CONSOLE (WM_APP + 1)
30 #define PM_DESTROY_CONSOLE (WM_APP + 2)
33 /* Not defined in any header file */
34 extern VOID NTAPI
PrivateCsrssManualGuiCheck(LONG Check
);
35 // See winsrv/usersrv/init.c line 234
38 /* GLOBALS ********************************************************************/
40 typedef struct _GUI_INIT_INFO
42 PCONSOLE_INFO ConsoleInfo
;
43 PCONSOLE_START_INFO ConsoleStartInfo
;
45 } GUI_INIT_INFO
, *PGUI_INIT_INFO
;
47 static BOOL ConsInitialized
= FALSE
;
48 static HWND NotifyWnd
= NULL
;
50 extern HICON ghDefaultIcon
;
51 extern HICON ghDefaultIconSm
;
52 extern HCURSOR ghDefaultCursor
;
55 SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData
);
57 RegisterConWndClass(IN HINSTANCE hInstance
);
59 UnRegisterConWndClass(HINSTANCE hInstance
);
61 /* FUNCTIONS ******************************************************************/
64 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer
,
65 IN PGUI_CONSOLE_DATA GuiData
,
69 if (Buffer
== NULL
|| GuiData
== NULL
||
70 WidthUnit
== NULL
|| HeightUnit
== NULL
)
75 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
77 *WidthUnit
= GuiData
->CharWidth
;
78 *HeightUnit
= GuiData
->CharHeight
;
80 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
88 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData
)
90 /* Move the window if needed (not positioned by the system) */
91 if (!GuiData
->GuiInfo
.AutoPosition
)
93 SetWindowPos(GuiData
->hWindow
,
95 GuiData
->GuiInfo
.WindowOrigin
.x
,
96 GuiData
->GuiInfo
.WindowOrigin
.y
,
98 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
103 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
105 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
106 UINT WidthUnit
, HeightUnit
;
108 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
110 Rect
->left
= (SmallRect
->Left
- Buffer
->ViewOrigin
.X
) * WidthUnit
;
111 Rect
->top
= (SmallRect
->Top
- Buffer
->ViewOrigin
.Y
) * HeightUnit
;
112 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ViewOrigin
.X
) * WidthUnit
;
113 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ViewOrigin
.Y
) * HeightUnit
;
117 DrawRegion(PGUI_CONSOLE_DATA GuiData
,
122 SmallRectToRect(GuiData
, &RegionRect
, Region
);
123 /* Do not erase the background: it speeds up redrawing and reduce flickering */
124 InvalidateRect(GuiData
->hWindow
, &RegionRect
, FALSE
);
125 /**UpdateWindow(GuiData->hWindow);**/
129 InvalidateCell(PGUI_CONSOLE_DATA GuiData
,
132 SMALL_RECT CellRect
= { x
, y
, x
, y
};
133 DrawRegion(GuiData
, &CellRect
);
137 /******************************************************************************
138 * GUI Terminal Initialization *
139 ******************************************************************************/
142 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData
, BOOL FullScreen
);
144 static LRESULT CALLBACK
145 GuiConsoleNotifyWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
155 SetWindowLongW(hWnd
, GWL_USERDATA
, 0);
159 case PM_CREATE_CONSOLE
:
161 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
162 PCONSOLE Console
= GuiData
->Console
;
165 DPRINT("PM_CREATE_CONSOLE -- creating window\n");
167 NewWindow
= CreateWindowExW(WS_EX_CLIENTEDGE
,
169 Console
->Title
.Buffer
,
170 WS_OVERLAPPEDWINDOW
| WS_HSCROLL
| WS_VSCROLL
,
179 if (NULL
!= NewWindow
)
181 ASSERT(NewWindow
== GuiData
->hWindow
);
183 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
185 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
188 // FIXME: TODO: Move everything there into conwnd.c!OnNcCreate()
191 /* Retrieve our real position */
192 // See conwnd.c!OnMove()
193 GetWindowRect(GuiData
->hWindow
, &rcWnd
);
194 GuiData
->GuiInfo
.WindowOrigin
.x
= rcWnd
.left
;
195 GuiData
->GuiInfo
.WindowOrigin
.y
= rcWnd
.top
;
197 /* Move and resize the window to the user's values */
198 /* CAN WE DEADLOCK ?? */
199 GuiConsoleMoveWindow(GuiData
); // FIXME: This MUST be done via the CreateWindowExW call.
200 SendMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
202 /* Switch to full-screen mode if necessary */
203 // FIXME: Move elsewhere, it cause misdrawings of the window.
204 if (GuiData
->GuiInfo
.FullScreen
) SwitchFullScreen(GuiData
, TRUE
);
206 DPRINT("PM_CREATE_CONSOLE -- showing window\n");
207 // ShowWindow(NewWindow, (int)wParam);
208 ShowWindowAsync(NewWindow
, (int)wParam
);
209 DPRINT("Window showed\n");
212 return (LRESULT
)NewWindow
;
215 case PM_DESTROY_CONSOLE
:
217 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
219 /* Exit the full screen mode if it was already set */
220 // LeaveFullScreen(GuiData);
223 * Window creation is done using a PostMessage(), so it's possible
224 * that the window that we want to destroy doesn't exist yet.
225 * So first empty the message queue.
228 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
230 TranslateMessage(&Msg);
231 DispatchMessageW(&Msg);
233 while (PeekMessageW(&Msg
, NULL
, 0, 0, PM_REMOVE
)) ;
235 if (GuiData
->hWindow
!= NULL
) /* && DestroyWindow(GuiData->hWindow) */
237 DestroyWindow(GuiData
->hWindow
);
239 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
241 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
242 if (0 == WindowCount
)
246 DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
255 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
260 GuiConsoleGuiThread(PVOID Data
)
263 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Data
;
266 * This thread dispatches all the console notifications to the notify window.
267 * It is common for all the console windows.
270 PrivateCsrssManualGuiCheck(+1);
272 NotifyWnd
= CreateWindowW(L
"ConSrvCreateNotify",
283 if (NULL
== NotifyWnd
)
285 PrivateCsrssManualGuiCheck(-1);
286 SetEvent(*GraphicsStartupEvent
);
290 SetEvent(*GraphicsStartupEvent
);
292 while (GetMessageW(&msg
, NULL
, 0, 0))
294 TranslateMessage(&msg
);
295 DispatchMessageW(&msg
);
298 DPRINT("CONSRV: Quit the Gui Thread!!\n");
299 PrivateCsrssManualGuiCheck(-1);
309 /* Exit if we were already initialized */
310 // if (ConsInitialized) return TRUE;
313 * Initialize and register the different window classes, if needed.
315 if (!ConsInitialized
)
317 /* Initialize the notification window class */
318 wc
.cbSize
= sizeof(WNDCLASSEXW
);
319 wc
.lpszClassName
= L
"ConSrvCreateNotify";
320 wc
.lpfnWndProc
= GuiConsoleNotifyWndProc
;
322 wc
.hInstance
= ConSrvDllInstance
;
326 wc
.hbrBackground
= NULL
;
327 wc
.lpszMenuName
= NULL
;
330 if (RegisterClassExW(&wc
) == 0)
332 DPRINT1("Failed to register GUI notify wndproc\n");
336 /* Initialize the console window class */
337 if (!RegisterConWndClass(ConSrvDllInstance
))
340 ConsInitialized
= TRUE
;
344 * Set-up the notification window
346 if (NULL
== NotifyWnd
)
349 HANDLE GraphicsStartupEvent
;
351 GraphicsStartupEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
352 if (NULL
== GraphicsStartupEvent
) return FALSE
;
354 ThreadHandle
= CreateThread(NULL
,
357 (PVOID
)&GraphicsStartupEvent
,
360 if (NULL
== ThreadHandle
)
362 CloseHandle(GraphicsStartupEvent
);
363 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
366 SetThreadPriority(ThreadHandle
, THREAD_PRIORITY_HIGHEST
);
367 CloseHandle(ThreadHandle
);
369 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
370 CloseHandle(GraphicsStartupEvent
);
372 if (NULL
== NotifyWnd
)
374 DPRINT1("CONSRV: Failed to create notification window.\n");
379 // ConsInitialized = TRUE;
386 /******************************************************************************
387 * GUI Console Driver *
388 ******************************************************************************/
391 GuiDeinitFrontEnd(IN OUT PFRONTEND This
);
394 GuiInitFrontEnd(IN OUT PFRONTEND This
,
397 PGUI_INIT_INFO GuiInitInfo
;
398 PCONSOLE_INFO ConsoleInfo
;
399 PCONSOLE_START_INFO ConsoleStartInfo
;
401 PGUI_CONSOLE_DATA GuiData
;
402 GUI_CONSOLE_INFO TermInfo
;
405 LPWSTR IconPath
= NULL
;
408 if (This
== NULL
|| Console
== NULL
|| This
->OldData
== NULL
)
409 return STATUS_INVALID_PARAMETER
;
411 ASSERT(This
->Console
== Console
);
413 GuiInitInfo
= This
->OldData
;
415 if (GuiInitInfo
->ConsoleInfo
== NULL
|| GuiInitInfo
->ConsoleStartInfo
== NULL
)
416 return STATUS_INVALID_PARAMETER
;
418 ConsoleInfo
= GuiInitInfo
->ConsoleInfo
;
419 ConsoleStartInfo
= GuiInitInfo
->ConsoleStartInfo
;
421 IconPath
= ConsoleStartInfo
->IconPath
;
422 IconIndex
= ConsoleStartInfo
->IconIndex
;
425 /* Terminal data allocation */
426 GuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_CONSOLE_DATA
));
429 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
430 return STATUS_UNSUCCESSFUL
;
432 ///// /* HACK */ Console->TermIFace.Data = (PVOID)GuiData; /* HACK */
433 GuiData
->Console
= Console
;
434 GuiData
->ActiveBuffer
= Console
->ActiveBuffer
;
435 GuiData
->hWindow
= NULL
;
437 /* The console can be resized */
438 Console
->FixedSize
= FALSE
;
440 InitializeCriticalSection(&GuiData
->Lock
);
444 * Load terminal settings
447 /* 1. Load the default settings */
448 GuiConsoleGetDefaultSettings(&TermInfo
, GuiInitInfo
->ProcessId
);
450 /* 3. Load the remaining console settings via the registry. */
451 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
453 /* Load the terminal infos from the registry. */
454 GuiConsoleReadUserSettings(&TermInfo
,
455 ConsoleInfo
->ConsoleTitle
,
456 GuiInitInfo
->ProcessId
);
459 * Now, update them with the properties the user might gave to us
460 * via the STARTUPINFO structure before calling CreateProcess
461 * (and which was transmitted via the ConsoleStartInfo structure).
462 * We therefore overwrite the values read in the registry.
464 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
466 TermInfo
.ShowWindow
= ConsoleStartInfo
->wShowWindow
;
468 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
470 TermInfo
.AutoPosition
= FALSE
;
471 TermInfo
.WindowOrigin
.x
= ConsoleStartInfo
->dwWindowOrigin
.X
;
472 TermInfo
.WindowOrigin
.y
= ConsoleStartInfo
->dwWindowOrigin
.Y
;
474 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
476 TermInfo
.FullScreen
= TRUE
;
485 Length
= min(wcslen(TermInfo
.FaceName
) + 1, LF_FACESIZE
); // wcsnlen
486 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
487 GuiData
->GuiInfo
.FaceName
[Length
] = L
'\0';
488 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
489 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
490 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
491 GuiData
->GuiInfo
.UseRasterFonts
= TermInfo
.UseRasterFonts
;
492 GuiData
->GuiInfo
.FullScreen
= TermInfo
.FullScreen
;
493 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
494 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
495 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
497 /* Initialize the icon handles to their default values */
498 GuiData
->hIcon
= ghDefaultIcon
;
499 GuiData
->hIconSm
= ghDefaultIconSm
;
501 /* Get the associated icon, if any */
502 if (IconPath
== NULL
|| IconPath
[0] == L
'\0')
504 IconPath
= ConsoleStartInfo
->AppPath
;
507 DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath
? IconPath
: L
"n/a"), IconIndex
);
508 if (IconPath
&& IconPath
[0] != L
'\0')
510 HICON hIcon
= NULL
, hIconSm
= NULL
;
511 PrivateExtractIconExW(IconPath
,
516 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon
, hIconSm
);
517 if (hIcon
!= NULL
) GuiData
->hIcon
= hIcon
;
518 if (hIconSm
!= NULL
) GuiData
->hIconSm
= hIconSm
;
520 ASSERT(GuiData
->hIcon
&& GuiData
->hIconSm
);
522 /* Mouse is shown by default with its default cursor shape */
523 GuiData
->hCursor
= ghDefaultCursor
;
524 GuiData
->MouseCursorRefCount
= 0;
526 /* A priori don't ignore mouse signals */
527 GuiData
->IgnoreNextMouseSignal
= FALSE
;
529 /* Close button and the corresponding system menu item are enabled by default */
530 GuiData
->IsCloseButtonEnabled
= TRUE
;
532 /* There is no user-reserved menu id range by default */
533 GuiData
->CmdIdLow
= GuiData
->CmdIdHigh
= 0;
535 /* Initialize the selection */
536 RtlZeroMemory(&GuiData
->Selection
, sizeof(CONSOLE_SELECTION_INFO
));
537 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
540 * We need to wait until the GUI has been fully initialized
541 * to retrieve custom settings i.e. WindowSize etc...
542 * Ideally we could use SendNotifyMessage for this but its not
545 GuiData
->hGuiInitEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
547 DPRINT("GUI - Checkpoint\n");
549 /* Create the terminal window */
550 PostMessageW(NotifyWnd
, PM_CREATE_CONSOLE
, GuiData
->GuiInfo
.ShowWindow
, (LPARAM
)GuiData
);
552 /* Wait until initialization has finished */
553 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
554 DPRINT("OK we created the console window\n");
555 CloseHandle(GuiData
->hGuiInitEvent
);
556 GuiData
->hGuiInitEvent
= NULL
;
558 /* Check whether we really succeeded in initializing the terminal window */
559 if (GuiData
->hWindow
== NULL
)
561 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
562 GuiDeinitFrontEnd(This
);
563 return STATUS_UNSUCCESSFUL
;
566 /* Finally, finish to initialize the frontend structure */
567 This
->Data
= GuiData
;
568 if (This
->OldData
) ConsoleFreeHeap(This
->OldData
);
569 This
->OldData
= NULL
;
571 return STATUS_SUCCESS
;
575 GuiDeinitFrontEnd(IN OUT PFRONTEND This
)
577 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
579 SendMessageW(NotifyWnd
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
581 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
582 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
583 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
585 DPRINT("Destroy hIcon\n");
586 DestroyIcon(GuiData
->hIcon
);
588 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
590 DPRINT("Destroy hIconSm\n");
591 DestroyIcon(GuiData
->hIconSm
);
595 DeleteCriticalSection(&GuiData
->Lock
);
596 ConsoleFreeHeap(GuiData
);
598 DPRINT("Quit GuiDeinitFrontEnd\n");
602 GuiDrawRegion(IN OUT PFRONTEND This
,
605 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
606 DrawRegion(GuiData
, Region
);
610 GuiWriteStream(IN OUT PFRONTEND This
,
618 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
619 PCONSOLE_SCREEN_BUFFER Buff
;
620 SHORT CursorEndX
, CursorEndY
;
623 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
) return;
625 Buff
= GuiData
->ActiveBuffer
;
626 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
628 if (0 != ScrolledLines
)
632 ScrollRect
.right
= Buff
->ViewSize
.X
* GuiData
->CharWidth
;
633 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
635 ScrollWindowEx(GuiData
->hWindow
,
637 -(int)(ScrolledLines
* GuiData
->CharHeight
),
645 DrawRegion(GuiData
, Region
);
647 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
648 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
650 InvalidateCell(GuiData
, CursorStartX
, CursorStartY
);
653 CursorEndX
= Buff
->CursorPosition
.X
;
654 CursorEndY
= Buff
->CursorPosition
.Y
;
655 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
656 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
657 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
659 InvalidateCell(GuiData
, CursorEndX
, CursorEndY
);
663 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
664 // repaint the window without having it just freeze up and stay on the screen permanently.
665 Buff
->CursorBlinkOn
= TRUE
;
666 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
670 GuiSetCursorInfo(IN OUT PFRONTEND This
,
671 PCONSOLE_SCREEN_BUFFER Buff
)
673 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
675 if (GuiData
->ActiveBuffer
== Buff
)
677 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
684 GuiSetScreenInfo(IN OUT PFRONTEND This
,
685 PCONSOLE_SCREEN_BUFFER Buff
,
689 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
691 if (GuiData
->ActiveBuffer
== Buff
)
693 /* Redraw char at old position (remove cursor) */
694 InvalidateCell(GuiData
, OldCursorX
, OldCursorY
);
695 /* Redraw char at new position (show cursor) */
696 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
703 GuiResizeTerminal(IN OUT PFRONTEND This
)
705 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
707 /* Resize the window to the user's values */
708 PostMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
712 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This
)
714 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
715 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
718 EnterCriticalSection(&GuiData
->Lock
);
719 GuiData
->WindowSizeLock
= TRUE
;
721 InterlockedExchangePointer(&GuiData
->ActiveBuffer
,
722 ConDrvGetActiveScreenBuffer(GuiData
->Console
));
724 GuiData
->WindowSizeLock
= FALSE
;
725 LeaveCriticalSection(&GuiData
->Lock
);
727 ActiveBuffer
= GuiData
->ActiveBuffer
;
729 /* Change the current palette */
730 if (ActiveBuffer
->PaletteHandle
== NULL
)
732 hPalette
= GuiData
->hSysPalette
;
736 hPalette
= ActiveBuffer
->PaletteHandle
;
739 DPRINT1("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette
);
741 /* Set the new palette for the framebuffer */
742 SelectPalette(GuiData
->hMemDC
, hPalette
, FALSE
);
744 /* Specify the use of the system palette for the framebuffer */
745 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
747 /* Realize the (logical) palette */
748 RealizePalette(GuiData
->hMemDC
);
750 GuiResizeTerminal(This
);
751 // ConioDrawConsole(Console);
755 GuiReleaseScreenBuffer(IN OUT PFRONTEND This
,
756 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer
)
758 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
761 * If we were notified to release a screen buffer that is not actually
762 * ours, then just ignore the notification...
764 if (ScreenBuffer
!= GuiData
->ActiveBuffer
) return;
767 * ... else, we must release our active buffer. Two cases are present:
768 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
769 * active screen buffer, then we can safely switch to it.
770 * - If ScreenBuffer IS the console active screen buffer, we must release
774 /* Release the old active palette and set the default one */
775 if (GetCurrentObject(GuiData
->hMemDC
, OBJ_PAL
) == ScreenBuffer
->PaletteHandle
)
777 /* Set the new palette */
778 SelectPalette(GuiData
->hMemDC
, GuiData
->hSysPalette
, FALSE
);
781 /* Set the adequate active screen buffer */
782 if (ScreenBuffer
!= GuiData
->Console
->ActiveBuffer
)
784 GuiSetActiveScreenBuffer(This
);
788 EnterCriticalSection(&GuiData
->Lock
);
789 GuiData
->WindowSizeLock
= TRUE
;
791 InterlockedExchangePointer(&GuiData
->ActiveBuffer
, NULL
);
793 GuiData
->WindowSizeLock
= FALSE
;
794 LeaveCriticalSection(&GuiData
->Lock
);
799 GuiProcessKeyCallback(IN OUT PFRONTEND This
,
806 if ((ShiftState
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
) || KeyStateMenu
& 0x80) &&
807 (VirtualKeyCode
== VK_ESCAPE
|| VirtualKeyCode
== VK_TAB
|| VirtualKeyCode
== VK_SPACE
))
809 DPRINT1("GuiProcessKeyCallback\n");
810 //DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
818 GuiSetMouseCursor(IN OUT PFRONTEND This
,
819 HCURSOR CursorHandle
);
822 GuiRefreshInternalInfo(IN OUT PFRONTEND This
)
824 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
826 /* Update the console leader information held by the window */
827 SetConWndConsoleLeaderCID(GuiData
);
831 * We reset the cursor here so that, when a console app quits, we reset
832 * the cursor to the default one. It's quite a hack since it doesn't proceed
833 * per - console process... This must be fixed.
835 * See GuiInitConsole(...) for more information.
838 /* Mouse is shown by default with its default cursor shape */
839 GuiData
->MouseCursorRefCount
= 0; // Reinitialize the reference counter
840 GuiSetMouseCursor(This
, NULL
);
844 GuiChangeTitle(IN OUT PFRONTEND This
)
846 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
847 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
848 SetWindowText(GuiData
->hWindow
, GuiData
->Console
->Title
.Buffer
);
852 GuiChangeIcon(IN OUT PFRONTEND This
,
855 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
856 HICON hIcon
, hIconSm
;
858 if (IconHandle
== NULL
)
860 hIcon
= ghDefaultIcon
;
861 hIconSm
= ghDefaultIconSm
;
865 hIcon
= CopyIcon(IconHandle
);
866 hIconSm
= CopyIcon(IconHandle
);
874 if (hIcon
!= GuiData
->hIcon
)
876 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
878 DestroyIcon(GuiData
->hIcon
);
880 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
882 DestroyIcon(GuiData
->hIconSm
);
885 GuiData
->hIcon
= hIcon
;
886 GuiData
->hIconSm
= hIconSm
;
888 DPRINT("Set icons in GuiChangeIcon\n");
889 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
890 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
897 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
899 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
900 return GuiData
->hWindow
;
904 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
907 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
908 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
911 UINT WidthUnit
, HeightUnit
;
915 if (!SystemParametersInfoW(SPI_GETWORKAREA
, 0, &WorkArea
, 0))
917 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
921 ActiveBuffer
= GuiData
->ActiveBuffer
;
924 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
928 /* Default: text mode */
929 WidthUnit
= GuiData
->CharWidth
;
930 HeightUnit
= GuiData
->CharHeight
;
933 width
= WorkArea
.right
;
934 height
= WorkArea
.bottom
;
936 width
-= (2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
)));
937 height
-= (2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
));
939 if (width
< 0) width
= 0;
940 if (height
< 0) height
= 0;
942 pSize
->X
= (SHORT
)(width
/ (int)WidthUnit
) /* HACK */ + 2;
943 pSize
->Y
= (SHORT
)(height
/ (int)HeightUnit
) /* HACK */ + 1;
947 GuiGetSelectionInfo(IN OUT PFRONTEND This
,
948 PCONSOLE_SELECTION_INFO pSelectionInfo
)
950 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
952 if (pSelectionInfo
== NULL
) return FALSE
;
954 ZeroMemory(pSelectionInfo
, sizeof(CONSOLE_SELECTION_INFO
));
955 if (GuiData
->Selection
.dwFlags
!= CONSOLE_NO_SELECTION
)
956 RtlCopyMemory(pSelectionInfo
, &GuiData
->Selection
, sizeof(CONSOLE_SELECTION_INFO
));
962 GuiSetPalette(IN OUT PFRONTEND This
,
963 HPALETTE PaletteHandle
,
966 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
969 // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
970 if (PaletteHandle
== NULL
) return FALSE
;
972 /* Set the new palette for the framebuffer */
973 OldPalette
= SelectPalette(GuiData
->hMemDC
, PaletteHandle
, FALSE
);
974 if (OldPalette
== NULL
) return FALSE
;
976 /* Specify the use of the system palette for the framebuffer */
977 SetSystemPaletteUse(GuiData
->hMemDC
, PaletteUsage
);
979 /* Realize the (logical) palette */
980 RealizePalette(GuiData
->hMemDC
);
982 /* Save the original system palette handle */
983 if (GuiData
->hSysPalette
== NULL
) GuiData
->hSysPalette
= OldPalette
;
989 GuiGetDisplayMode(IN OUT PFRONTEND This
)
991 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
992 ULONG DisplayMode
= 0;
994 if (GuiData
->GuiInfo
.FullScreen
)
995 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
997 DisplayMode
|= CONSOLE_WINDOWED
;
1003 GuiSetDisplayMode(IN OUT PFRONTEND This
,
1006 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1009 if (NewMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
1012 FullScreen
= ((NewMode
& CONSOLE_FULLSCREEN_MODE
) != 0);
1014 if (FullScreen
!= GuiData
->GuiInfo
.FullScreen
)
1016 SwitchFullScreen(GuiData
, FullScreen
);
1023 GuiShowMouseCursor(IN OUT PFRONTEND This
,
1026 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1028 /* Set the reference count */
1029 if (Show
) ++GuiData
->MouseCursorRefCount
;
1030 else --GuiData
->MouseCursorRefCount
;
1032 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
1033 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
1035 return GuiData
->MouseCursorRefCount
;
1039 GuiSetMouseCursor(IN OUT PFRONTEND This
,
1040 HCURSOR CursorHandle
)
1042 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1045 * Set the cursor's handle. If the given handle is NULL,
1046 * then restore the default cursor.
1048 GuiData
->hCursor
= (CursorHandle
? CursorHandle
: ghDefaultCursor
);
1050 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
1051 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
1057 GuiMenuControl(IN OUT PFRONTEND This
,
1061 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1063 GuiData
->CmdIdLow
= CmdIdLow
;
1064 GuiData
->CmdIdHigh
= CmdIdHigh
;
1066 return GetSystemMenu(GuiData
->hWindow
, FALSE
);
1070 GuiSetMenuClose(IN OUT PFRONTEND This
,
1074 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
1075 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
1076 * for more information.
1079 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1080 HMENU hSysMenu
= GetSystemMenu(GuiData
->hWindow
, FALSE
);
1082 if (hSysMenu
== NULL
) return FALSE
;
1084 GuiData
->IsCloseButtonEnabled
= Enable
;
1085 EnableMenuItem(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
| (Enable
? MF_ENABLED
: MF_GRAYED
));
1090 static FRONTEND_VTBL GuiVtbl
=
1099 GuiSetActiveScreenBuffer
,
1100 GuiReleaseScreenBuffer
,
1101 GuiProcessKeyCallback
,
1102 GuiRefreshInternalInfo
,
1105 GuiGetConsoleWindowHandle
,
1106 GuiGetLargestConsoleWindowSize
,
1107 GuiGetSelectionInfo
,
1119 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
1120 IN OUT PCONSOLE_INFO ConsoleInfo
)
1122 #define PATH_SEPARATOR L'\\'
1124 BOOL RetVal
= FALSE
;
1125 HRESULT hRes
= S_OK
;
1126 LPWSTR LinkName
= NULL
;
1129 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
1132 ConsoleStartInfo
->IconPath
[0] = L
'\0';
1133 ConsoleStartInfo
->IconIndex
= 0;
1135 /* 1- Find the last path separator if any */
1136 LinkName
= wcsrchr(ConsoleStartInfo
->ConsoleTitle
, PATH_SEPARATOR
);
1137 if (LinkName
== NULL
)
1139 LinkName
= ConsoleStartInfo
->ConsoleTitle
;
1143 /* Skip the path separator */
1147 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
1148 Length
= wcslen(LinkName
);
1149 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
1152 /* 3- It may be a link. Try to retrieve some properties */
1153 hRes
= CoInitialize(NULL
);
1154 if (SUCCEEDED(hRes
))
1156 /* Get a pointer to the IShellLink interface */
1157 IShellLinkW
* pshl
= NULL
;
1158 hRes
= CoCreateInstance(&CLSID_ShellLink
,
1160 CLSCTX_INPROC_SERVER
,
1163 if (SUCCEEDED(hRes
))
1165 /* Get a pointer to the IPersistFile interface */
1166 IPersistFile
* ppf
= NULL
;
1167 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
1168 if (SUCCEEDED(hRes
))
1170 /* Load the shortcut */
1171 hRes
= IPersistFile_Load(ppf
, ConsoleStartInfo
->ConsoleTitle
, STGM_READ
);
1172 if (SUCCEEDED(hRes
))
1175 * Finally we can get the properties !
1176 * Update the old ones if needed.
1181 /* Reset the name of the console with the name of the shortcut */
1182 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
1183 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
1184 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
1185 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
1187 /* Get the window showing command */
1188 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
1189 if (SUCCEEDED(hRes
)) ConsoleStartInfo
->wShowWindow
= (WORD
)ShowCmd
;
1191 /* Get the hotkey */
1192 // hRes = pshl->GetHotkey(&ShowCmd);
1193 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
1195 /* Get the icon location, if any */
1197 hRes
= IShellLinkW_GetIconLocation(pshl
,
1198 ConsoleStartInfo
->IconPath
,
1199 sizeof(ConsoleStartInfo
->IconPath
)/sizeof(ConsoleStartInfo
->IconPath
[0]) - 1, // == MAX_PATH
1200 &ConsoleStartInfo
->IconIndex
);
1201 if (!SUCCEEDED(hRes
))
1203 ConsoleStartInfo
->IconPath
[0] = L
'\0';
1204 ConsoleStartInfo
->IconIndex
= 0;
1207 // FIXME: Since we still don't load console properties from the shortcut,
1208 // return false. When this will be done, we will return true instead.
1211 IPersistFile_Release(ppf
);
1213 IShellLinkW_Release(pshl
);
1222 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
1223 IN OUT PCONSOLE_INFO ConsoleInfo
,
1224 IN OUT PVOID ExtraConsoleInfo
,
1227 PCONSOLE_START_INFO ConsoleStartInfo
= ExtraConsoleInfo
;
1228 PGUI_INIT_INFO GuiInitInfo
;
1230 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
|| ConsoleStartInfo
== NULL
)
1231 return STATUS_INVALID_PARAMETER
;
1233 /* Initialize GUI terminal emulator common functionalities */
1234 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
1237 * Load per-application terminal settings.
1239 * Check whether the process creating the console was launched via
1240 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
1241 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
1243 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
)
1245 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo
, ConsoleInfo
))
1247 ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
1252 * Initialize a private initialization info structure for later use.
1253 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
1255 GuiInitInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_INIT_INFO
));
1256 if (GuiInitInfo
== NULL
) return STATUS_NO_MEMORY
;
1258 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
1259 GuiInitInfo
->ConsoleInfo
= ConsoleInfo
;
1260 GuiInitInfo
->ConsoleStartInfo
= ConsoleStartInfo
;
1261 GuiInitInfo
->ProcessId
= ProcessId
;
1263 /* Finally, initialize the frontend structure */
1264 FrontEnd
->Vtbl
= &GuiVtbl
;
1265 FrontEnd
->Data
= NULL
;
1266 FrontEnd
->OldData
= GuiInitInfo
;
1268 return STATUS_SUCCESS
;
1272 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
1274 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
1276 if (FrontEnd
->Data
) GuiDeinitFrontEnd(FrontEnd
);
1277 if (FrontEnd
->OldData
) ConsoleFreeHeap(FrontEnd
->OldData
);
1279 return STATUS_SUCCESS
;