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 CreateSysMenu(HWND hWnd
);
145 static LRESULT CALLBACK
146 GuiConsoleNotifyWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
156 SetWindowLongW(hWnd
, GWL_USERDATA
, 0);
160 case PM_CREATE_CONSOLE
:
162 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
163 PCONSOLE Console
= GuiData
->Console
;
166 DPRINT("PM_CREATE_CONSOLE -- creating window\n");
168 NewWindow
= CreateWindowExW(WS_EX_CLIENTEDGE
,
170 Console
->Title
.Buffer
,
171 WS_OVERLAPPEDWINDOW
| WS_HSCROLL
| WS_VSCROLL
,
180 if (NULL
!= NewWindow
)
182 ASSERT(NewWindow
== GuiData
->hWindow
);
184 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
186 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
189 // FIXME: TODO: Move everything there into conwnd.c!OnNcCreate()
192 /* Retrieve our real position */
193 // See conwnd.c!OnMove()
194 GetWindowRect(GuiData
->hWindow
, &rcWnd
);
195 GuiData
->GuiInfo
.WindowOrigin
.x
= rcWnd
.left
;
196 GuiData
->GuiInfo
.WindowOrigin
.y
= rcWnd
.top
;
198 /* Move and resize the window to the user's values */
199 /* CAN WE DEADLOCK ?? */
200 GuiConsoleMoveWindow(GuiData
); // FIXME: This MUST be done via the CreateWindowExW call.
201 SendMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
203 // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
204 CreateSysMenu(GuiData
->hWindow
);
206 /* Switch to full-screen mode if necessary */
207 // FIXME: Move elsewhere, it cause misdrawings of the window.
208 if (GuiData
->GuiInfo
.FullScreen
) SwitchFullScreen(GuiData
, TRUE
);
210 DPRINT("PM_CREATE_CONSOLE -- showing window\n");
211 // ShowWindow(NewWindow, (int)wParam);
212 ShowWindowAsync(NewWindow
, (int)wParam
);
213 DPRINT("Window showed\n");
216 return (LRESULT
)NewWindow
;
219 case PM_DESTROY_CONSOLE
:
221 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
223 /* Exit the full screen mode if it was already set */
224 // LeaveFullScreen(GuiData);
227 * Window creation is done using a PostMessage(), so it's possible
228 * that the window that we want to destroy doesn't exist yet.
229 * So first empty the message queue.
232 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
234 TranslateMessage(&Msg);
235 DispatchMessageW(&Msg);
237 while (PeekMessageW(&Msg
, NULL
, 0, 0, PM_REMOVE
)) ;
239 if (GuiData
->hWindow
!= NULL
) /* && DestroyWindow(GuiData->hWindow) */
241 DestroyWindow(GuiData
->hWindow
);
243 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
245 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
246 if (0 == WindowCount
)
250 DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
259 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
264 GuiConsoleGuiThread(PVOID Data
)
267 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Data
;
270 * This thread dispatches all the console notifications to the notify window.
271 * It is common for all the console windows.
274 PrivateCsrssManualGuiCheck(+1);
276 NotifyWnd
= CreateWindowW(L
"ConSrvCreateNotify",
287 if (NULL
== NotifyWnd
)
289 PrivateCsrssManualGuiCheck(-1);
290 SetEvent(*GraphicsStartupEvent
);
294 SetEvent(*GraphicsStartupEvent
);
296 while (GetMessageW(&msg
, NULL
, 0, 0))
298 TranslateMessage(&msg
);
299 DispatchMessageW(&msg
);
302 DPRINT("CONSRV: Quit the Gui Thread!!\n");
303 PrivateCsrssManualGuiCheck(-1);
313 /* Exit if we were already initialized */
314 // if (ConsInitialized) return TRUE;
317 * Initialize and register the different window classes, if needed.
319 if (!ConsInitialized
)
321 /* Initialize the notification window class */
322 wc
.cbSize
= sizeof(WNDCLASSEXW
);
323 wc
.lpszClassName
= L
"ConSrvCreateNotify";
324 wc
.lpfnWndProc
= GuiConsoleNotifyWndProc
;
326 wc
.hInstance
= ConSrvDllInstance
;
330 wc
.hbrBackground
= NULL
;
331 wc
.lpszMenuName
= NULL
;
334 if (RegisterClassExW(&wc
) == 0)
336 DPRINT1("Failed to register GUI notify wndproc\n");
340 /* Initialize the console window class */
341 if (!RegisterConWndClass(ConSrvDllInstance
))
344 ConsInitialized
= TRUE
;
348 * Set-up the notification window
350 if (NULL
== NotifyWnd
)
353 HANDLE GraphicsStartupEvent
;
355 GraphicsStartupEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
356 if (NULL
== GraphicsStartupEvent
) return FALSE
;
358 ThreadHandle
= CreateThread(NULL
,
361 (PVOID
)&GraphicsStartupEvent
,
364 if (NULL
== ThreadHandle
)
366 CloseHandle(GraphicsStartupEvent
);
367 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
370 SetThreadPriority(ThreadHandle
, THREAD_PRIORITY_HIGHEST
);
371 CloseHandle(ThreadHandle
);
373 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
374 CloseHandle(GraphicsStartupEvent
);
376 if (NULL
== NotifyWnd
)
378 DPRINT1("CONSRV: Failed to create notification window.\n");
383 // ConsInitialized = TRUE;
390 /******************************************************************************
391 * GUI Console Driver *
392 ******************************************************************************/
395 GuiDeinitFrontEnd(IN OUT PFRONTEND This
);
398 GuiInitFrontEnd(IN OUT PFRONTEND This
,
401 PGUI_INIT_INFO GuiInitInfo
;
402 PCONSOLE_INFO ConsoleInfo
;
403 PCONSOLE_START_INFO ConsoleStartInfo
;
405 PGUI_CONSOLE_DATA GuiData
;
406 GUI_CONSOLE_INFO TermInfo
;
409 LPWSTR IconPath
= NULL
;
412 if (This
== NULL
|| Console
== NULL
|| This
->OldData
== NULL
)
413 return STATUS_INVALID_PARAMETER
;
415 ASSERT(This
->Console
== Console
);
417 GuiInitInfo
= This
->OldData
;
419 if (GuiInitInfo
->ConsoleInfo
== NULL
|| GuiInitInfo
->ConsoleStartInfo
== NULL
)
420 return STATUS_INVALID_PARAMETER
;
422 ConsoleInfo
= GuiInitInfo
->ConsoleInfo
;
423 ConsoleStartInfo
= GuiInitInfo
->ConsoleStartInfo
;
425 IconPath
= ConsoleStartInfo
->IconPath
;
426 IconIndex
= ConsoleStartInfo
->IconIndex
;
429 /* Terminal data allocation */
430 GuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_CONSOLE_DATA
));
433 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
434 return STATUS_UNSUCCESSFUL
;
436 ///// /* HACK */ Console->FrontEndIFace.Data = (PVOID)GuiData; /* HACK */
437 GuiData
->Console
= Console
;
438 GuiData
->ActiveBuffer
= Console
->ActiveBuffer
;
439 GuiData
->hWindow
= NULL
;
441 /* The console can be resized */
442 Console
->FixedSize
= FALSE
;
444 InitializeCriticalSection(&GuiData
->Lock
);
448 * Load terminal settings
451 /* 1. Load the default settings */
452 GuiConsoleGetDefaultSettings(&TermInfo
, GuiInitInfo
->ProcessId
);
454 /* 3. Load the remaining console settings via the registry. */
455 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
457 /* Load the terminal infos from the registry. */
458 GuiConsoleReadUserSettings(&TermInfo
,
459 ConsoleInfo
->ConsoleTitle
,
460 GuiInitInfo
->ProcessId
);
463 * Now, update them with the properties the user might gave to us
464 * via the STARTUPINFO structure before calling CreateProcess
465 * (and which was transmitted via the ConsoleStartInfo structure).
466 * We therefore overwrite the values read in the registry.
468 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
470 TermInfo
.ShowWindow
= ConsoleStartInfo
->wShowWindow
;
472 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
474 TermInfo
.AutoPosition
= FALSE
;
475 TermInfo
.WindowOrigin
.x
= ConsoleStartInfo
->dwWindowOrigin
.X
;
476 TermInfo
.WindowOrigin
.y
= ConsoleStartInfo
->dwWindowOrigin
.Y
;
478 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
480 TermInfo
.FullScreen
= TRUE
;
489 Length
= min(wcslen(TermInfo
.FaceName
) + 1, LF_FACESIZE
); // wcsnlen
490 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
491 GuiData
->GuiInfo
.FaceName
[Length
] = L
'\0';
492 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
493 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
494 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
495 GuiData
->GuiInfo
.UseRasterFonts
= TermInfo
.UseRasterFonts
;
496 GuiData
->GuiInfo
.FullScreen
= TermInfo
.FullScreen
;
497 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
498 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
499 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
501 /* Initialize the icon handles to their default values */
502 GuiData
->hIcon
= ghDefaultIcon
;
503 GuiData
->hIconSm
= ghDefaultIconSm
;
505 /* Get the associated icon, if any */
506 if (IconPath
== NULL
|| IconPath
[0] == L
'\0')
508 IconPath
= ConsoleStartInfo
->AppPath
;
511 DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath
? IconPath
: L
"n/a"), IconIndex
);
512 if (IconPath
&& IconPath
[0] != L
'\0')
514 HICON hIcon
= NULL
, hIconSm
= NULL
;
515 PrivateExtractIconExW(IconPath
,
520 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon
, hIconSm
);
521 if (hIcon
!= NULL
) GuiData
->hIcon
= hIcon
;
522 if (hIconSm
!= NULL
) GuiData
->hIconSm
= hIconSm
;
524 ASSERT(GuiData
->hIcon
&& GuiData
->hIconSm
);
526 /* Mouse is shown by default with its default cursor shape */
527 GuiData
->hCursor
= ghDefaultCursor
;
528 GuiData
->MouseCursorRefCount
= 0;
530 /* A priori don't ignore mouse signals */
531 GuiData
->IgnoreNextMouseSignal
= FALSE
;
533 /* Close button and the corresponding system menu item are enabled by default */
534 GuiData
->IsCloseButtonEnabled
= TRUE
;
536 /* There is no user-reserved menu id range by default */
537 GuiData
->CmdIdLow
= GuiData
->CmdIdHigh
= 0;
539 /* Initialize the selection */
540 RtlZeroMemory(&GuiData
->Selection
, sizeof(GuiData
->Selection
));
541 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
542 RtlZeroMemory(&GuiData
->dwSelectionCursor
, sizeof(GuiData
->dwSelectionCursor
));
543 GuiData
->LineSelection
= FALSE
; // Default to block selection
544 // TODO: Retrieve the selection mode via the registry.
547 * We need to wait until the GUI has been fully initialized
548 * to retrieve custom settings i.e. WindowSize etc...
549 * Ideally we could use SendNotifyMessage for this but its not
552 GuiData
->hGuiInitEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
554 DPRINT("GUI - Checkpoint\n");
556 /* Create the terminal window */
557 PostMessageW(NotifyWnd
, PM_CREATE_CONSOLE
, GuiData
->GuiInfo
.ShowWindow
, (LPARAM
)GuiData
);
559 /* Wait until initialization has finished */
560 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
561 DPRINT("OK we created the console window\n");
562 CloseHandle(GuiData
->hGuiInitEvent
);
563 GuiData
->hGuiInitEvent
= NULL
;
565 /* Check whether we really succeeded in initializing the terminal window */
566 if (GuiData
->hWindow
== NULL
)
568 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
569 GuiDeinitFrontEnd(This
);
570 return STATUS_UNSUCCESSFUL
;
573 /* Finally, finish to initialize the frontend structure */
574 This
->Data
= GuiData
;
575 if (This
->OldData
) ConsoleFreeHeap(This
->OldData
);
576 This
->OldData
= NULL
;
578 return STATUS_SUCCESS
;
582 GuiDeinitFrontEnd(IN OUT PFRONTEND This
)
584 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
586 SendMessageW(NotifyWnd
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
588 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
589 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
590 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
592 DPRINT("Destroy hIcon\n");
593 DestroyIcon(GuiData
->hIcon
);
595 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
597 DPRINT("Destroy hIconSm\n");
598 DestroyIcon(GuiData
->hIconSm
);
602 DeleteCriticalSection(&GuiData
->Lock
);
603 ConsoleFreeHeap(GuiData
);
605 DPRINT("Quit GuiDeinitFrontEnd\n");
609 GuiDrawRegion(IN OUT PFRONTEND This
,
612 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
613 DrawRegion(GuiData
, Region
);
617 GuiWriteStream(IN OUT PFRONTEND This
,
625 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
626 PCONSOLE_SCREEN_BUFFER Buff
;
627 SHORT CursorEndX
, CursorEndY
;
630 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
) return;
632 Buff
= GuiData
->ActiveBuffer
;
633 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
635 if (0 != ScrolledLines
)
639 ScrollRect
.right
= Buff
->ViewSize
.X
* GuiData
->CharWidth
;
640 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
642 ScrollWindowEx(GuiData
->hWindow
,
644 -(int)(ScrolledLines
* GuiData
->CharHeight
),
652 DrawRegion(GuiData
, Region
);
654 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
655 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
657 InvalidateCell(GuiData
, CursorStartX
, CursorStartY
);
660 CursorEndX
= Buff
->CursorPosition
.X
;
661 CursorEndY
= Buff
->CursorPosition
.Y
;
662 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
663 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
664 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
666 InvalidateCell(GuiData
, CursorEndX
, CursorEndY
);
670 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
671 // repaint the window without having it just freeze up and stay on the screen permanently.
672 Buff
->CursorBlinkOn
= TRUE
;
673 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
677 GuiSetCursorInfo(IN OUT PFRONTEND This
,
678 PCONSOLE_SCREEN_BUFFER Buff
)
680 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
682 if (GuiData
->ActiveBuffer
== Buff
)
684 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
691 GuiSetScreenInfo(IN OUT PFRONTEND This
,
692 PCONSOLE_SCREEN_BUFFER Buff
,
696 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
698 if (GuiData
->ActiveBuffer
== Buff
)
700 /* Redraw char at old position (remove cursor) */
701 InvalidateCell(GuiData
, OldCursorX
, OldCursorY
);
702 /* Redraw char at new position (show cursor) */
703 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
710 GuiResizeTerminal(IN OUT PFRONTEND This
)
712 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
714 /* Resize the window to the user's values */
715 PostMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
719 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This
)
721 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
722 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
725 EnterCriticalSection(&GuiData
->Lock
);
726 GuiData
->WindowSizeLock
= TRUE
;
728 InterlockedExchangePointer(&GuiData
->ActiveBuffer
,
729 ConDrvGetActiveScreenBuffer(GuiData
->Console
));
731 GuiData
->WindowSizeLock
= FALSE
;
732 LeaveCriticalSection(&GuiData
->Lock
);
734 ActiveBuffer
= GuiData
->ActiveBuffer
;
736 /* Change the current palette */
737 if (ActiveBuffer
->PaletteHandle
== NULL
)
739 hPalette
= GuiData
->hSysPalette
;
743 hPalette
= ActiveBuffer
->PaletteHandle
;
746 DPRINT1("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette
);
748 /* Set the new palette for the framebuffer */
749 SelectPalette(GuiData
->hMemDC
, hPalette
, FALSE
);
751 /* Specify the use of the system palette for the framebuffer */
752 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
754 /* Realize the (logical) palette */
755 RealizePalette(GuiData
->hMemDC
);
757 GuiResizeTerminal(This
);
758 // ConioDrawConsole(Console);
762 GuiReleaseScreenBuffer(IN OUT PFRONTEND This
,
763 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer
)
765 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
768 * If we were notified to release a screen buffer that is not actually
769 * ours, then just ignore the notification...
771 if (ScreenBuffer
!= GuiData
->ActiveBuffer
) return;
774 * ... else, we must release our active buffer. Two cases are present:
775 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
776 * active screen buffer, then we can safely switch to it.
777 * - If ScreenBuffer IS the console active screen buffer, we must release
781 /* Release the old active palette and set the default one */
782 if (GetCurrentObject(GuiData
->hMemDC
, OBJ_PAL
) == ScreenBuffer
->PaletteHandle
)
784 /* Set the new palette */
785 SelectPalette(GuiData
->hMemDC
, GuiData
->hSysPalette
, FALSE
);
788 /* Set the adequate active screen buffer */
789 if (ScreenBuffer
!= GuiData
->Console
->ActiveBuffer
)
791 GuiSetActiveScreenBuffer(This
);
795 EnterCriticalSection(&GuiData
->Lock
);
796 GuiData
->WindowSizeLock
= TRUE
;
798 InterlockedExchangePointer(&GuiData
->ActiveBuffer
, NULL
);
800 GuiData
->WindowSizeLock
= FALSE
;
801 LeaveCriticalSection(&GuiData
->Lock
);
806 GuiSetMouseCursor(IN OUT PFRONTEND This
,
807 HCURSOR CursorHandle
);
810 GuiRefreshInternalInfo(IN OUT PFRONTEND This
)
812 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
814 /* Update the console leader information held by the window */
815 SetConWndConsoleLeaderCID(GuiData
);
819 * We reset the cursor here so that, when a console app quits, we reset
820 * the cursor to the default one. It's quite a hack since it doesn't proceed
821 * per - console process... This must be fixed.
823 * See GuiInitConsole(...) for more information.
826 /* Mouse is shown by default with its default cursor shape */
827 GuiData
->MouseCursorRefCount
= 0; // Reinitialize the reference counter
828 GuiSetMouseCursor(This
, NULL
);
832 GuiChangeTitle(IN OUT PFRONTEND This
)
834 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
835 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
836 SetWindowText(GuiData
->hWindow
, GuiData
->Console
->Title
.Buffer
);
840 GuiChangeIcon(IN OUT PFRONTEND This
,
843 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
844 HICON hIcon
, hIconSm
;
846 if (IconHandle
== NULL
)
848 hIcon
= ghDefaultIcon
;
849 hIconSm
= ghDefaultIconSm
;
853 hIcon
= CopyIcon(IconHandle
);
854 hIconSm
= CopyIcon(IconHandle
);
862 if (hIcon
!= GuiData
->hIcon
)
864 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
866 DestroyIcon(GuiData
->hIcon
);
868 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
870 DestroyIcon(GuiData
->hIconSm
);
873 GuiData
->hIcon
= hIcon
;
874 GuiData
->hIconSm
= hIconSm
;
876 DPRINT("Set icons in GuiChangeIcon\n");
877 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
878 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
885 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
887 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
888 return GuiData
->hWindow
;
892 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
895 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
896 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
899 UINT WidthUnit
, HeightUnit
;
903 if (!SystemParametersInfoW(SPI_GETWORKAREA
, 0, &WorkArea
, 0))
905 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
909 ActiveBuffer
= GuiData
->ActiveBuffer
;
912 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
916 /* Default: text mode */
917 WidthUnit
= GuiData
->CharWidth
;
918 HeightUnit
= GuiData
->CharHeight
;
921 width
= WorkArea
.right
;
922 height
= WorkArea
.bottom
;
924 width
-= (2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
)));
925 height
-= (2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
));
927 if (width
< 0) width
= 0;
928 if (height
< 0) height
= 0;
930 pSize
->X
= (SHORT
)(width
/ (int)WidthUnit
) /* HACK */ + 2;
931 pSize
->Y
= (SHORT
)(height
/ (int)HeightUnit
) /* HACK */ + 1;
935 GuiGetSelectionInfo(IN OUT PFRONTEND This
,
936 PCONSOLE_SELECTION_INFO pSelectionInfo
)
938 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
940 if (pSelectionInfo
== NULL
) return FALSE
;
942 ZeroMemory(pSelectionInfo
, sizeof(CONSOLE_SELECTION_INFO
));
943 if (GuiData
->Selection
.dwFlags
!= CONSOLE_NO_SELECTION
)
944 RtlCopyMemory(pSelectionInfo
, &GuiData
->Selection
, sizeof(CONSOLE_SELECTION_INFO
));
950 GuiSetPalette(IN OUT PFRONTEND This
,
951 HPALETTE PaletteHandle
,
954 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
957 // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
958 if (PaletteHandle
== NULL
) return FALSE
;
960 /* Set the new palette for the framebuffer */
961 OldPalette
= SelectPalette(GuiData
->hMemDC
, PaletteHandle
, FALSE
);
962 if (OldPalette
== NULL
) return FALSE
;
964 /* Specify the use of the system palette for the framebuffer */
965 SetSystemPaletteUse(GuiData
->hMemDC
, PaletteUsage
);
967 /* Realize the (logical) palette */
968 RealizePalette(GuiData
->hMemDC
);
970 /* Save the original system palette handle */
971 if (GuiData
->hSysPalette
== NULL
) GuiData
->hSysPalette
= OldPalette
;
977 GuiGetDisplayMode(IN OUT PFRONTEND This
)
979 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
980 ULONG DisplayMode
= 0;
982 if (GuiData
->GuiInfo
.FullScreen
)
983 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
985 DisplayMode
|= CONSOLE_WINDOWED
;
991 GuiSetDisplayMode(IN OUT PFRONTEND This
,
994 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
997 if (NewMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
1000 FullScreen
= ((NewMode
& CONSOLE_FULLSCREEN_MODE
) != 0);
1002 if (FullScreen
!= GuiData
->GuiInfo
.FullScreen
)
1004 SwitchFullScreen(GuiData
, FullScreen
);
1011 GuiShowMouseCursor(IN OUT PFRONTEND This
,
1014 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1016 /* Set the reference count */
1017 if (Show
) ++GuiData
->MouseCursorRefCount
;
1018 else --GuiData
->MouseCursorRefCount
;
1020 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
1021 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
1023 return GuiData
->MouseCursorRefCount
;
1027 GuiSetMouseCursor(IN OUT PFRONTEND This
,
1028 HCURSOR CursorHandle
)
1030 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1033 * Set the cursor's handle. If the given handle is NULL,
1034 * then restore the default cursor.
1036 GuiData
->hCursor
= (CursorHandle
? CursorHandle
: ghDefaultCursor
);
1038 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
1039 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
1045 GuiMenuControl(IN OUT PFRONTEND This
,
1049 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1051 GuiData
->CmdIdLow
= CmdIdLow
;
1052 GuiData
->CmdIdHigh
= CmdIdHigh
;
1054 return GetSystemMenu(GuiData
->hWindow
, FALSE
);
1058 GuiSetMenuClose(IN OUT PFRONTEND This
,
1062 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
1063 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
1064 * for more information.
1067 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1068 HMENU hSysMenu
= GetSystemMenu(GuiData
->hWindow
, FALSE
);
1070 if (hSysMenu
== NULL
) return FALSE
;
1072 GuiData
->IsCloseButtonEnabled
= Enable
;
1073 EnableMenuItem(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
| (Enable
? MF_ENABLED
: MF_GRAYED
));
1078 static FRONTEND_VTBL GuiVtbl
=
1087 GuiSetActiveScreenBuffer
,
1088 GuiReleaseScreenBuffer
,
1089 GuiRefreshInternalInfo
,
1092 GuiGetConsoleWindowHandle
,
1093 GuiGetLargestConsoleWindowSize
,
1094 GuiGetSelectionInfo
,
1106 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
1107 IN OUT PCONSOLE_INFO ConsoleInfo
)
1109 #define PATH_SEPARATOR L'\\'
1111 BOOL RetVal
= FALSE
;
1112 HRESULT hRes
= S_OK
;
1113 LPWSTR LinkName
= NULL
;
1116 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
1119 ConsoleStartInfo
->IconPath
[0] = L
'\0';
1120 ConsoleStartInfo
->IconIndex
= 0;
1122 /* 1- Find the last path separator if any */
1123 LinkName
= wcsrchr(ConsoleStartInfo
->ConsoleTitle
, PATH_SEPARATOR
);
1124 if (LinkName
== NULL
)
1126 LinkName
= ConsoleStartInfo
->ConsoleTitle
;
1130 /* Skip the path separator */
1134 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
1135 Length
= wcslen(LinkName
);
1136 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
1139 /* 3- It may be a link. Try to retrieve some properties */
1140 hRes
= CoInitialize(NULL
);
1141 if (SUCCEEDED(hRes
))
1143 /* Get a pointer to the IShellLink interface */
1144 IShellLinkW
* pshl
= NULL
;
1145 hRes
= CoCreateInstance(&CLSID_ShellLink
,
1147 CLSCTX_INPROC_SERVER
,
1150 if (SUCCEEDED(hRes
))
1152 /* Get a pointer to the IPersistFile interface */
1153 IPersistFile
* ppf
= NULL
;
1154 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
1155 if (SUCCEEDED(hRes
))
1157 /* Load the shortcut */
1158 hRes
= IPersistFile_Load(ppf
, ConsoleStartInfo
->ConsoleTitle
, STGM_READ
);
1159 if (SUCCEEDED(hRes
))
1162 * Finally we can get the properties !
1163 * Update the old ones if needed.
1168 /* Reset the name of the console with the name of the shortcut */
1169 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
1170 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
1171 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
1172 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
1174 /* Get the window showing command */
1175 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
1176 if (SUCCEEDED(hRes
)) ConsoleStartInfo
->wShowWindow
= (WORD
)ShowCmd
;
1178 /* Get the hotkey */
1179 // hRes = pshl->GetHotkey(&ShowCmd);
1180 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
1182 /* Get the icon location, if any */
1184 hRes
= IShellLinkW_GetIconLocation(pshl
,
1185 ConsoleStartInfo
->IconPath
,
1186 sizeof(ConsoleStartInfo
->IconPath
)/sizeof(ConsoleStartInfo
->IconPath
[0]) - 1, // == MAX_PATH
1187 &ConsoleStartInfo
->IconIndex
);
1188 if (!SUCCEEDED(hRes
))
1190 ConsoleStartInfo
->IconPath
[0] = L
'\0';
1191 ConsoleStartInfo
->IconIndex
= 0;
1194 // FIXME: Since we still don't load console properties from the shortcut,
1195 // return false. When this will be done, we will return true instead.
1198 IPersistFile_Release(ppf
);
1200 IShellLinkW_Release(pshl
);
1209 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
1210 IN OUT PCONSOLE_INFO ConsoleInfo
,
1211 IN OUT PVOID ExtraConsoleInfo
,
1214 PCONSOLE_START_INFO ConsoleStartInfo
= ExtraConsoleInfo
;
1215 PGUI_INIT_INFO GuiInitInfo
;
1217 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
|| ConsoleStartInfo
== NULL
)
1218 return STATUS_INVALID_PARAMETER
;
1220 /* Initialize GUI terminal emulator common functionalities */
1221 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
1224 * Load per-application terminal settings.
1226 * Check whether the process creating the console was launched via
1227 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
1228 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
1230 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
)
1232 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo
, ConsoleInfo
))
1234 ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
1239 * Initialize a private initialization info structure for later use.
1240 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
1242 GuiInitInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_INIT_INFO
));
1243 if (GuiInitInfo
== NULL
) return STATUS_NO_MEMORY
;
1245 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
1246 GuiInitInfo
->ConsoleInfo
= ConsoleInfo
;
1247 GuiInitInfo
->ConsoleStartInfo
= ConsoleStartInfo
;
1248 GuiInitInfo
->ProcessId
= ProcessId
;
1250 /* Finally, initialize the frontend structure */
1251 FrontEnd
->Vtbl
= &GuiVtbl
;
1252 FrontEnd
->Data
= NULL
;
1253 FrontEnd
->OldData
= GuiInitInfo
;
1255 return STATUS_SUCCESS
;
1259 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
1261 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
1263 if (FrontEnd
->Data
) GuiDeinitFrontEnd(FrontEnd
);
1264 if (FrontEnd
->OldData
) ConsoleFreeHeap(FrontEnd
->OldData
);
1266 return STATUS_SUCCESS
;