e371ea484a25f31b55a89b7c584ff125abcde802
[reactos.git] / win32ss / user / winsrv / consrv / frontends / gui / guiterm.c
1 /*
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
7 * Johannes Anderwald
8 * Jeffrey Morlan
9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 */
11
12 /* INCLUDES *******************************************************************/
13
14 #include <consrv.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 #include "guiterm.h"
20 #include "resource.h"
21
22 // HACK!! Remove it when the hack in GuiWriteStream is fixed
23 #define CONGUI_UPDATE_TIME 0
24 #define CONGUI_UPDATE_TIMER 1
25
26 #define PM_CREATE_CONSOLE (WM_APP + 1)
27 #define PM_DESTROY_CONSOLE (WM_APP + 2)
28
29
30 /* GLOBALS ********************************************************************/
31
32 typedef struct _GUI_INIT_INFO
33 {
34 HANDLE GuiThreadStartupEvent;
35 ULONG_PTR InputThreadId;
36 HWINSTA WinSta;
37 HDESK Desktop;
38 HICON hIcon;
39 HICON hIconSm;
40 BOOLEAN IsWindowVisible;
41 GUI_CONSOLE_INFO TermInfo;
42 } GUI_INIT_INFO, *PGUI_INIT_INFO;
43
44 static BOOL ConsInitialized = FALSE;
45
46 extern HICON ghDefaultIcon;
47 extern HICON ghDefaultIconSm;
48 extern HCURSOR ghDefaultCursor;
49
50 VOID
51 SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData);
52 BOOLEAN
53 RegisterConWndClass(IN HINSTANCE hInstance);
54 BOOLEAN
55 UnRegisterConWndClass(HINSTANCE hInstance);
56
57 /* FUNCTIONS ******************************************************************/
58
59 VOID
60 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData)
61 {
62 /* Move the window if needed (not positioned by the system) */
63 if (!GuiData->GuiInfo.AutoPosition)
64 {
65 SetWindowPos(GuiData->hWindow,
66 NULL,
67 GuiData->GuiInfo.WindowOrigin.x,
68 GuiData->GuiInfo.WindowOrigin.y,
69 0, 0,
70 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
71 }
72 }
73
74 static VOID
75 DrawRegion(PGUI_CONSOLE_DATA GuiData,
76 SMALL_RECT* Region)
77 {
78 RECT RegionRect;
79
80 SmallRectToRect(GuiData, &RegionRect, Region);
81 /* Do not erase the background: it speeds up redrawing and reduce flickering */
82 InvalidateRect(GuiData->hWindow, &RegionRect, FALSE);
83 /**UpdateWindow(GuiData->hWindow);**/
84 }
85
86 VOID
87 InvalidateCell(PGUI_CONSOLE_DATA GuiData,
88 SHORT x, SHORT y)
89 {
90 SMALL_RECT CellRect = { x, y, x, y };
91 DrawRegion(GuiData, &CellRect);
92 }
93
94
95 /******************************************************************************
96 * GUI Terminal Initialization *
97 ******************************************************************************/
98
99 VOID
100 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData, BOOL FullScreen);
101 VOID
102 CreateSysMenu(HWND hWnd);
103
104 static ULONG NTAPI
105 GuiConsoleInputThread(PVOID Param)
106 {
107 NTSTATUS Status;
108 PCSR_THREAD pcsrt = NULL;
109 PGUI_INIT_INFO GuiInitInfo = (PGUI_INIT_INFO)Param;
110 DESKTOP_CONSOLE_THREAD DesktopConsoleThreadInfo;
111 ULONG_PTR InputThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
112 HANDLE hThread = NULL;
113
114 LONG WindowCount = 0;
115 MSG msg;
116
117 /*
118 * This thread dispatches all the console notifications to the
119 * notification window. It is common for all the console windows
120 * in a given desktop in a window station.
121 */
122
123 /* Assign this console input thread to this desktop */
124 DesktopConsoleThreadInfo.DesktopHandle = GuiInitInfo->Desktop; // Duplicated desktop handle
125 DesktopConsoleThreadInfo.ThreadId = InputThreadId;
126 Status = NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
127 &DesktopConsoleThreadInfo,
128 sizeof(DesktopConsoleThreadInfo));
129 if (!NT_SUCCESS(Status)) goto Quit;
130
131 /* Connect this CSR thread to the USER subsystem */
132 pcsrt = CsrConnectToUser();
133 if (pcsrt == NULL) goto Quit;
134 hThread = pcsrt->ThreadHandle;
135
136 /* Assign the desktop to this thread */
137 if (!SetThreadDesktop(DesktopConsoleThreadInfo.DesktopHandle)) goto Quit;
138
139 /* The thread has been initialized, set the event */
140 NtSetEvent(GuiInitInfo->GuiThreadStartupEvent, NULL);
141 Status = STATUS_SUCCESS;
142
143 while (GetMessageW(&msg, NULL, 0, 0))
144 {
145 switch (msg.message)
146 {
147 case PM_CREATE_CONSOLE:
148 {
149 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)msg.lParam;
150 PCONSRV_CONSOLE Console = GuiData->Console;
151 HWND NewWindow;
152 RECT rcWnd;
153
154 DPRINT("PM_CREATE_CONSOLE -- creating window\n");
155
156 NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
157 GUI_CONWND_CLASS,
158 Console->Title.Buffer,
159 WS_OVERLAPPEDWINDOW,
160 CW_USEDEFAULT,
161 CW_USEDEFAULT,
162 CW_USEDEFAULT,
163 CW_USEDEFAULT,
164 GuiData->IsWindowVisible ? HWND_DESKTOP : HWND_MESSAGE,
165 NULL,
166 ConSrvDllInstance,
167 (PVOID)GuiData);
168 if (NewWindow == NULL)
169 {
170 DPRINT1("Failed to create a new console window\n");
171 continue;
172 }
173
174 ASSERT(NewWindow == GuiData->hWindow);
175
176 InterlockedIncrement(&WindowCount);
177
178 //
179 // FIXME: TODO: Move everything there into conwnd.c!OnNcCreate()
180 //
181
182 /* Retrieve our real position */
183 // See conwnd.c!OnMove()
184 GetWindowRect(GuiData->hWindow, &rcWnd);
185 GuiData->GuiInfo.WindowOrigin.x = rcWnd.left;
186 GuiData->GuiInfo.WindowOrigin.y = rcWnd.top;
187
188 if (GuiData->IsWindowVisible)
189 {
190 /* Move and resize the window to the user's values */
191 /* CAN WE DEADLOCK ?? */
192 GuiConsoleMoveWindow(GuiData); // FIXME: This MUST be done via the CreateWindowExW call.
193 SendMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
194 }
195
196 // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
197 CreateSysMenu(GuiData->hWindow);
198
199 if (GuiData->IsWindowVisible)
200 {
201 /* Switch to full-screen mode if necessary */
202 // FIXME: Move elsewhere, it cause misdrawings of the window.
203 if (GuiData->GuiInfo.FullScreen) SwitchFullScreen(GuiData, TRUE);
204
205 DPRINT("PM_CREATE_CONSOLE -- showing window\n");
206 // ShowWindow(NewWindow, (int)GuiData->GuiInfo.ShowWindow);
207 ShowWindowAsync(NewWindow, (int)GuiData->GuiInfo.ShowWindow);
208 DPRINT("Window showed\n");
209 }
210 else
211 {
212 DPRINT("PM_CREATE_CONSOLE -- hidden window\n");
213 ShowWindowAsync(NewWindow, SW_HIDE);
214 }
215
216 continue;
217 }
218
219 case PM_DESTROY_CONSOLE:
220 {
221 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)msg.lParam;
222 MSG TempMsg;
223
224 /* Exit the full screen mode if it was already set */
225 // LeaveFullScreen(GuiData);
226
227 /*
228 * Window creation is done using a PostMessage(), so it's possible
229 * that the window that we want to destroy doesn't exist yet.
230 * So first empty the message queue.
231 */
232 while (PeekMessageW(&TempMsg, NULL, 0, 0, PM_REMOVE))
233 {
234 DispatchMessageW(&TempMsg);
235 }
236
237 if (GuiData->hWindow == NULL) continue;
238
239 DestroyWindow(GuiData->hWindow);
240
241 NtSetEvent(GuiData->hGuiTermEvent, NULL);
242
243 if (InterlockedDecrement(&WindowCount) == 0)
244 {
245 DPRINT("CONSRV: Going to quit the Input Thread 0x%p\n", InputThreadId);
246 goto Quit;
247 }
248
249 continue;
250 }
251 }
252
253 TranslateMessage(&msg);
254 DispatchMessageW(&msg);
255 }
256
257 Quit:
258 DPRINT("CONSRV: Quit the Input Thread 0x%p, Status = 0x%08lx\n", InputThreadId, Status);
259
260 /* Remove this console input thread from this desktop */
261 // DesktopConsoleThreadInfo.DesktopHandle;
262 DesktopConsoleThreadInfo.ThreadId = 0;
263 NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
264 &DesktopConsoleThreadInfo,
265 sizeof(DesktopConsoleThreadInfo));
266
267 /* Close the duplicated desktop handle */
268 CloseDesktop(DesktopConsoleThreadInfo.DesktopHandle); // NtUserCloseDesktop
269
270 /* Cleanup CSR thread */
271 if (pcsrt)
272 {
273 if (hThread != pcsrt->ThreadHandle)
274 DPRINT1("WARNING!! hThread (0x%p) != pcsrt->ThreadHandle (0x%p), you may expect crashes soon!!\n", hThread, pcsrt->ThreadHandle);
275
276 CsrDereferenceThread(pcsrt);
277 }
278
279 /* Exit the thread */
280 RtlExitUserThread(Status);
281 return 0;
282 }
283
284 // FIXME: Maybe return a NTSTATUS
285 static BOOL
286 GuiInit(IN PCONSOLE_INIT_INFO ConsoleInitInfo,
287 IN HANDLE ConsoleLeaderProcessHandle,
288 IN OUT PGUI_INIT_INFO GuiInitInfo)
289 {
290 BOOL Success = TRUE;
291 UNICODE_STRING DesktopPath;
292 DESKTOP_CONSOLE_THREAD DesktopConsoleThreadInfo;
293 HWINSTA hWinSta;
294 HDESK hDesk;
295
296 NTSTATUS Status;
297 HANDLE hInputThread;
298 CLIENT_ID ClientId;
299
300 /*
301 * Initialize and register the console window class, if needed.
302 */
303 if (!ConsInitialized)
304 {
305 if (!RegisterConWndClass(ConSrvDllInstance)) return FALSE;
306 ConsInitialized = TRUE;
307 }
308
309 /*
310 * Set-up the console input thread. We have
311 * one console input thread per desktop.
312 */
313
314 if (!CsrImpersonateClient(NULL))
315 // return STATUS_BAD_IMPERSONATION_LEVEL;
316 return FALSE;
317
318 if (ConsoleInitInfo->DesktopLength)
319 {
320 DesktopPath.MaximumLength = ConsoleInitInfo->DesktopLength;
321 DesktopPath.Length = DesktopPath.MaximumLength - sizeof(UNICODE_NULL);
322 DesktopPath.Buffer = ConsoleInitInfo->Desktop;
323 }
324 else
325 {
326 RtlInitUnicodeString(&DesktopPath, L"Default");
327 }
328
329 hDesk = NtUserResolveDesktop(ConsoleLeaderProcessHandle,
330 &DesktopPath,
331 0,
332 &hWinSta);
333 DPRINT("NtUserResolveDesktop(DesktopPath = '%wZ') returned hDesk = 0x%p; hWinSta = 0x%p\n",
334 &DesktopPath, hDesk, hWinSta);
335
336 CsrRevertToSelf();
337
338 if (hDesk == NULL) return FALSE;
339
340 /*
341 * We need to see whether we need to create a
342 * new console input thread for this desktop.
343 */
344 DesktopConsoleThreadInfo.DesktopHandle = hDesk;
345 DesktopConsoleThreadInfo.ThreadId = (ULONG_PTR)INVALID_HANDLE_VALUE; // Special value to say we just want to retrieve the thread ID.
346 NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
347 &DesktopConsoleThreadInfo,
348 sizeof(DesktopConsoleThreadInfo));
349 DPRINT("NtUserConsoleControl returned ThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId);
350
351 /*
352 * Save the opened window station and desktop handles in the initialization
353 * structure. They will be used later on, and released, by the GUI frontend.
354 */
355 GuiInitInfo->WinSta = hWinSta;
356 GuiInitInfo->Desktop = hDesk;
357
358 /* Here GuiInitInfo contains original handles */
359
360 /* If we already have a console input thread on this desktop... */
361 if (DesktopConsoleThreadInfo.ThreadId != 0)
362 {
363 /* ... just use it... */
364 DPRINT("Using input thread InputThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId);
365 GuiInitInfo->InputThreadId = DesktopConsoleThreadInfo.ThreadId;
366 goto Quit;
367 }
368
369 /* ... otherwise create a new one. */
370
371 /* Initialize a startup event for the thread to signal it */
372 Status = NtCreateEvent(&GuiInitInfo->GuiThreadStartupEvent, EVENT_ALL_ACCESS,
373 NULL, SynchronizationEvent, FALSE);
374 if (!NT_SUCCESS(Status))
375 {
376 Success = FALSE;
377 goto Quit;
378 }
379
380 /*
381 * Duplicate the desktop handle for the console input thread internal needs.
382 * If it happens to need also a window station handle in the future, then
383 * it is there that you also need to duplicate the window station handle!
384 *
385 * Note also that we are going to temporarily overwrite the stored handles
386 * in GuiInitInfo because it happens that we use also this structure to give
387 * the duplicated handles to the input thread that is going to initialize.
388 * After the input thread finishes its initialization, we restore the handles
389 * in GuiInitInfo to their old values.
390 */
391 Status = NtDuplicateObject(NtCurrentProcess(),
392 hDesk,
393 NtCurrentProcess(),
394 (PHANDLE)&GuiInitInfo->Desktop,
395 0, 0, DUPLICATE_SAME_ACCESS);
396 if (!NT_SUCCESS(Status))
397 {
398 Success = FALSE;
399 goto Quit;
400 }
401
402 /* Here GuiInitInfo contains duplicated handles */
403
404 Status = RtlCreateUserThread(NtCurrentProcess(),
405 NULL,
406 TRUE, // Start the thread in suspended state
407 0,
408 0,
409 0,
410 (PVOID)GuiConsoleInputThread,
411 (PVOID)GuiInitInfo,
412 &hInputThread,
413 &ClientId);
414 if (NT_SUCCESS(Status))
415 {
416 /* Add it as a static server thread and resume it */
417 CsrAddStaticServerThread(hInputThread, &ClientId, 0);
418 Status = NtResumeThread(hInputThread, NULL);
419 }
420 DPRINT("Thread creation hInputThread = 0x%p, InputThreadId = 0x%p, Status = 0x%08lx\n",
421 hInputThread, ClientId.UniqueThread, Status);
422
423 if (!NT_SUCCESS(Status) || hInputThread == NULL)
424 {
425 /* Close the thread's handle */
426 if (hInputThread) NtClose(hInputThread);
427
428 /* We need to close here the duplicated desktop handle */
429 CloseDesktop(GuiInitInfo->Desktop); // NtUserCloseDesktop
430
431 /* Close the startup event and bail out */
432 NtClose(GuiInitInfo->GuiThreadStartupEvent);
433
434 DPRINT1("CONSRV: Failed to create graphics console thread.\n");
435 Success = FALSE;
436 goto Quit;
437 }
438
439 /* No need to close hInputThread, this is done by CSR automatically */
440
441 /* Wait for the thread to finish its initialization, and close the startup event */
442 NtWaitForSingleObject(GuiInitInfo->GuiThreadStartupEvent, FALSE, NULL);
443 NtClose(GuiInitInfo->GuiThreadStartupEvent);
444
445 /*
446 * Save the input thread ID for later use, and restore the original handles.
447 * The copies are held by the console input thread.
448 */
449 GuiInitInfo->InputThreadId = (ULONG_PTR)ClientId.UniqueThread;
450 GuiInitInfo->WinSta = hWinSta;
451 GuiInitInfo->Desktop = hDesk;
452
453 /* Here GuiInitInfo contains again original handles */
454
455 Quit:
456 if (!Success)
457 {
458 /*
459 * Close the original handles. Do not use the copies in GuiInitInfo
460 * because we may have failed in the middle of the duplicate operation
461 * and the handles stored in GuiInitInfo may have changed.
462 */
463 CloseDesktop(hDesk); // NtUserCloseDesktop
464 CloseWindowStation(hWinSta); // NtUserCloseWindowStation
465 }
466
467 return Success;
468 }
469
470
471 /******************************************************************************
472 * GUI Console Driver *
473 ******************************************************************************/
474
475 static VOID NTAPI
476 GuiDeinitFrontEnd(IN OUT PFRONTEND This);
477
478 static NTSTATUS NTAPI
479 GuiInitFrontEnd(IN OUT PFRONTEND This,
480 IN PCONSRV_CONSOLE Console)
481 {
482 PGUI_INIT_INFO GuiInitInfo;
483 PGUI_CONSOLE_DATA GuiData;
484
485 if (This == NULL || Console == NULL || This->Context2 == NULL)
486 return STATUS_INVALID_PARAMETER;
487
488 ASSERT(This->Console == Console);
489
490 GuiInitInfo = This->Context2;
491
492 /* Terminal data allocation */
493 GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*GuiData));
494 if (!GuiData)
495 {
496 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
497 return STATUS_UNSUCCESSFUL;
498 }
499 /// /* HACK */ Console->FrontEndIFace.Context = (PVOID)GuiData; /* HACK */
500 GuiData->Console = Console;
501 GuiData->ActiveBuffer = Console->ActiveBuffer;
502 GuiData->hWindow = NULL;
503 GuiData->IsWindowVisible = GuiInitInfo->IsWindowVisible;
504
505 /* The console can be resized */
506 Console->FixedSize = FALSE;
507
508 InitializeCriticalSection(&GuiData->Lock);
509
510 /*
511 * Set up GUI data
512 */
513 RtlCopyMemory(&GuiData->GuiInfo, &GuiInitInfo->TermInfo, sizeof(GuiInitInfo->TermInfo));
514
515 /* Initialize the icon handles */
516 if (GuiInitInfo->hIcon != NULL)
517 GuiData->hIcon = GuiInitInfo->hIcon;
518 else
519 GuiData->hIcon = ghDefaultIcon;
520
521 if (GuiInitInfo->hIconSm != NULL)
522 GuiData->hIconSm = GuiInitInfo->hIconSm;
523 else
524 GuiData->hIconSm = ghDefaultIconSm;
525
526 ASSERT(GuiData->hIcon && GuiData->hIconSm);
527
528 /* Mouse is shown by default with its default cursor shape */
529 GuiData->hCursor = ghDefaultCursor;
530 GuiData->MouseCursorRefCount = 0;
531
532 /* A priori don't ignore mouse signals */
533 GuiData->IgnoreNextMouseSignal = FALSE;
534 /* Initialize HACK FOR CORE-8394. See conwnd.c!OnMouse for more details. */
535 GuiData->HackCORE8394IgnoreNextMove = FALSE;
536
537 /* Close button and the corresponding system menu item are enabled by default */
538 GuiData->IsCloseButtonEnabled = TRUE;
539
540 /* There is no user-reserved menu id range by default */
541 GuiData->CmdIdLow = GuiData->CmdIdHigh = 0;
542
543 /* Initialize the selection */
544 RtlZeroMemory(&GuiData->Selection, sizeof(GuiData->Selection));
545 GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
546 RtlZeroMemory(&GuiData->dwSelectionCursor, sizeof(GuiData->dwSelectionCursor));
547 GuiData->LineSelection = FALSE; // Default to block selection
548 // TODO: Retrieve the selection mode via the registry.
549
550 GuiData->InputThreadId = GuiInitInfo->InputThreadId;
551 GuiData->WinSta = GuiInitInfo->WinSta;
552 GuiData->Desktop = GuiInitInfo->Desktop;
553
554 /* Finally, finish to initialize the frontend structure */
555 This->Context = GuiData;
556 ConsoleFreeHeap(This->Context2);
557 This->Context2 = NULL;
558
559 /*
560 * We need to wait until the GUI has been fully initialized
561 * to retrieve custom settings i.e. WindowSize etc...
562 * Ideally we could use SendNotifyMessage for this but its not
563 * yet implemented.
564 */
565 NtCreateEvent(&GuiData->hGuiInitEvent, EVENT_ALL_ACCESS,
566 NULL, SynchronizationEvent, FALSE);
567 NtCreateEvent(&GuiData->hGuiTermEvent, EVENT_ALL_ACCESS,
568 NULL, SynchronizationEvent, FALSE);
569
570 DPRINT("GUI - Checkpoint\n");
571
572 /* Create the terminal window */
573 PostThreadMessageW(GuiData->InputThreadId, PM_CREATE_CONSOLE, 0, (LPARAM)GuiData);
574
575 /* Wait until initialization has finished */
576 NtWaitForSingleObject(GuiData->hGuiInitEvent, FALSE, NULL);
577 DPRINT("OK we created the console window\n");
578 NtClose(GuiData->hGuiInitEvent);
579 GuiData->hGuiInitEvent = NULL;
580
581 /* Check whether we really succeeded in initializing the terminal window */
582 if (GuiData->hWindow == NULL)
583 {
584 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
585 GuiDeinitFrontEnd(This);
586 return STATUS_UNSUCCESSFUL;
587 }
588
589 return STATUS_SUCCESS;
590 }
591
592 static VOID NTAPI
593 GuiDeinitFrontEnd(IN OUT PFRONTEND This)
594 {
595 PGUI_CONSOLE_DATA GuiData = This->Context;
596
597 DPRINT("Send PM_DESTROY_CONSOLE message and wait on hGuiTermEvent...\n");
598 PostThreadMessageW(GuiData->InputThreadId, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
599 NtWaitForSingleObject(GuiData->hGuiTermEvent, FALSE, NULL);
600 DPRINT("hGuiTermEvent set\n");
601 NtClose(GuiData->hGuiTermEvent);
602 GuiData->hGuiTermEvent = NULL;
603
604 CloseDesktop(GuiData->Desktop); // NtUserCloseDesktop
605 CloseWindowStation(GuiData->WinSta); // NtUserCloseWindowStation
606
607 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
608 GuiData->hIcon, ghDefaultIcon, GuiData->hIconSm, ghDefaultIconSm);
609 if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
610 {
611 DPRINT("Destroy hIcon\n");
612 DestroyIcon(GuiData->hIcon);
613 }
614 if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
615 {
616 DPRINT("Destroy hIconSm\n");
617 DestroyIcon(GuiData->hIconSm);
618 }
619
620 This->Context = NULL;
621 DeleteCriticalSection(&GuiData->Lock);
622 ConsoleFreeHeap(GuiData);
623
624 DPRINT("Quit GuiDeinitFrontEnd\n");
625 }
626
627 static VOID NTAPI
628 GuiDrawRegion(IN OUT PFRONTEND This,
629 SMALL_RECT* Region)
630 {
631 PGUI_CONSOLE_DATA GuiData = This->Context;
632
633 /* Do nothing if the window is hidden */
634 if (!GuiData->IsWindowVisible) return;
635
636 DrawRegion(GuiData, Region);
637 }
638
639 static VOID NTAPI
640 GuiWriteStream(IN OUT PFRONTEND This,
641 SMALL_RECT* Region,
642 SHORT CursorStartX,
643 SHORT CursorStartY,
644 UINT ScrolledLines,
645 PWCHAR Buffer,
646 UINT Length)
647 {
648 PGUI_CONSOLE_DATA GuiData = This->Context;
649 PCONSOLE_SCREEN_BUFFER Buff;
650 SHORT CursorEndX, CursorEndY;
651 RECT ScrollRect;
652
653 if (NULL == GuiData || NULL == GuiData->hWindow) return;
654
655 /* Do nothing if the window is hidden */
656 if (!GuiData->IsWindowVisible) return;
657
658 Buff = GuiData->ActiveBuffer;
659 if (GetType(Buff) != TEXTMODE_BUFFER) return;
660
661 if (0 != ScrolledLines)
662 {
663 ScrollRect.left = 0;
664 ScrollRect.top = 0;
665 ScrollRect.right = Buff->ViewSize.X * GuiData->CharWidth;
666 ScrollRect.bottom = Region->Top * GuiData->CharHeight;
667
668 ScrollWindowEx(GuiData->hWindow,
669 0,
670 -(int)(ScrolledLines * GuiData->CharHeight),
671 &ScrollRect,
672 NULL,
673 NULL,
674 NULL,
675 SW_INVALIDATE);
676 }
677
678 DrawRegion(GuiData, Region);
679
680 if (CursorStartX < Region->Left || Region->Right < CursorStartX
681 || CursorStartY < Region->Top || Region->Bottom < CursorStartY)
682 {
683 InvalidateCell(GuiData, CursorStartX, CursorStartY);
684 }
685
686 CursorEndX = Buff->CursorPosition.X;
687 CursorEndY = Buff->CursorPosition.Y;
688 if ((CursorEndX < Region->Left || Region->Right < CursorEndX
689 || CursorEndY < Region->Top || Region->Bottom < CursorEndY)
690 && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
691 {
692 InvalidateCell(GuiData, CursorEndX, CursorEndY);
693 }
694
695 // HACK!!
696 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
697 // repaint the window without having it just freeze up and stay on the screen permanently.
698 Buff->CursorBlinkOn = TRUE;
699 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
700 }
701
702 /* static */ VOID NTAPI
703 GuiRingBell(IN OUT PFRONTEND This)
704 {
705 PGUI_CONSOLE_DATA GuiData = This->Context;
706
707 /* Emit an error beep sound */
708 SendNotifyMessage(GuiData->hWindow, PM_CONSOLE_BEEP, 0, 0);
709 }
710
711 static BOOL NTAPI
712 GuiSetCursorInfo(IN OUT PFRONTEND This,
713 PCONSOLE_SCREEN_BUFFER Buff)
714 {
715 PGUI_CONSOLE_DATA GuiData = This->Context;
716
717 /* Do nothing if the window is hidden */
718 if (!GuiData->IsWindowVisible) return TRUE;
719
720 if (GuiData->ActiveBuffer == Buff)
721 {
722 InvalidateCell(GuiData, Buff->CursorPosition.X, Buff->CursorPosition.Y);
723 }
724
725 return TRUE;
726 }
727
728 static BOOL NTAPI
729 GuiSetScreenInfo(IN OUT PFRONTEND This,
730 PCONSOLE_SCREEN_BUFFER Buff,
731 SHORT OldCursorX,
732 SHORT OldCursorY)
733 {
734 PGUI_CONSOLE_DATA GuiData = This->Context;
735
736 /* Do nothing if the window is hidden */
737 if (!GuiData->IsWindowVisible) return TRUE;
738
739 if (GuiData->ActiveBuffer == Buff)
740 {
741 /* Redraw char at old position (remove cursor) */
742 InvalidateCell(GuiData, OldCursorX, OldCursorY);
743 /* Redraw char at new position (show cursor) */
744 InvalidateCell(GuiData, Buff->CursorPosition.X, Buff->CursorPosition.Y);
745 }
746
747 return TRUE;
748 }
749
750 static VOID NTAPI
751 GuiResizeTerminal(IN OUT PFRONTEND This)
752 {
753 PGUI_CONSOLE_DATA GuiData = This->Context;
754
755 /* Resize the window to the user's values */
756 PostMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
757 }
758
759 static VOID NTAPI
760 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This)
761 {
762 PGUI_CONSOLE_DATA GuiData = This->Context;
763 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
764 HPALETTE hPalette;
765
766 EnterCriticalSection(&GuiData->Lock);
767 GuiData->WindowSizeLock = TRUE;
768
769 InterlockedExchangePointer((PVOID*)&GuiData->ActiveBuffer,
770 ConDrvGetActiveScreenBuffer(GuiData->Console));
771
772 GuiData->WindowSizeLock = FALSE;
773 LeaveCriticalSection(&GuiData->Lock);
774
775 ActiveBuffer = GuiData->ActiveBuffer;
776
777 /* Change the current palette */
778 if (ActiveBuffer->PaletteHandle == NULL)
779 hPalette = GuiData->hSysPalette;
780 else
781 hPalette = ActiveBuffer->PaletteHandle;
782
783 DPRINT("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette);
784
785 /* Set the new palette for the framebuffer */
786 SelectPalette(GuiData->hMemDC, hPalette, FALSE);
787
788 /* Specify the use of the system palette for the framebuffer */
789 SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage);
790
791 /* Realize the (logical) palette */
792 RealizePalette(GuiData->hMemDC);
793
794 GuiResizeTerminal(This);
795 // ConioDrawConsole(Console);
796 }
797
798 static VOID NTAPI
799 GuiReleaseScreenBuffer(IN OUT PFRONTEND This,
800 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer)
801 {
802 PGUI_CONSOLE_DATA GuiData = This->Context;
803
804 /*
805 * If we were notified to release a screen buffer that is not actually
806 * ours, then just ignore the notification...
807 */
808 if (ScreenBuffer != GuiData->ActiveBuffer) return;
809
810 /*
811 * ... else, we must release our active buffer. Two cases are present:
812 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
813 * active screen buffer, then we can safely switch to it.
814 * - If ScreenBuffer IS the console active screen buffer, we must release
815 * it ONLY.
816 */
817
818 /* Release the old active palette and set the default one */
819 if (GetCurrentObject(GuiData->hMemDC, OBJ_PAL) == ScreenBuffer->PaletteHandle)
820 {
821 /* Set the new palette */
822 SelectPalette(GuiData->hMemDC, GuiData->hSysPalette, FALSE);
823 }
824
825 /* Set the adequate active screen buffer */
826 if (ScreenBuffer != GuiData->Console->ActiveBuffer)
827 {
828 GuiSetActiveScreenBuffer(This);
829 }
830 else
831 {
832 EnterCriticalSection(&GuiData->Lock);
833 GuiData->WindowSizeLock = TRUE;
834
835 InterlockedExchangePointer((PVOID*)&GuiData->ActiveBuffer, NULL);
836
837 GuiData->WindowSizeLock = FALSE;
838 LeaveCriticalSection(&GuiData->Lock);
839 }
840 }
841
842 static BOOL NTAPI
843 GuiSetMouseCursor(IN OUT PFRONTEND This,
844 HCURSOR CursorHandle);
845
846 static VOID NTAPI
847 GuiRefreshInternalInfo(IN OUT PFRONTEND This)
848 {
849 PGUI_CONSOLE_DATA GuiData = This->Context;
850
851 /* Update the console leader information held by the window */
852 SetConWndConsoleLeaderCID(GuiData);
853
854 /*
855 * HACK:
856 * We reset the cursor here so that, when a console app quits, we reset
857 * the cursor to the default one. It's quite a hack since it doesn't proceed
858 * per - console process... This must be fixed.
859 *
860 * See GuiInitConsole(...) for more information.
861 */
862
863 /* Mouse is shown by default with its default cursor shape */
864 GuiData->MouseCursorRefCount = 0; // Reinitialize the reference counter
865 GuiSetMouseCursor(This, NULL);
866 }
867
868 static VOID NTAPI
869 GuiChangeTitle(IN OUT PFRONTEND This)
870 {
871 PGUI_CONSOLE_DATA GuiData = This->Context;
872 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
873 SetWindowTextW(GuiData->hWindow, GuiData->Console->Title.Buffer);
874 }
875
876 static BOOL NTAPI
877 GuiChangeIcon(IN OUT PFRONTEND This,
878 HICON IconHandle)
879 {
880 PGUI_CONSOLE_DATA GuiData = This->Context;
881 HICON hIcon, hIconSm;
882
883 if (IconHandle == NULL)
884 {
885 hIcon = ghDefaultIcon;
886 hIconSm = ghDefaultIconSm;
887 }
888 else
889 {
890 hIcon = CopyIcon(IconHandle);
891 hIconSm = CopyIcon(IconHandle);
892 }
893
894 if (hIcon == NULL)
895 return FALSE;
896
897 if (hIcon != GuiData->hIcon)
898 {
899 if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
900 {
901 DestroyIcon(GuiData->hIcon);
902 }
903 if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
904 {
905 DestroyIcon(GuiData->hIconSm);
906 }
907
908 GuiData->hIcon = hIcon;
909 GuiData->hIconSm = hIconSm;
910
911 DPRINT("Set icons in GuiChangeIcon\n");
912 PostMessageW(GuiData->hWindow, WM_SETICON, ICON_BIG , (LPARAM)GuiData->hIcon );
913 PostMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
914 }
915
916 return TRUE;
917 }
918
919 static HWND NTAPI
920 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This)
921 {
922 PGUI_CONSOLE_DATA GuiData = This->Context;
923 return GuiData->hWindow;
924 }
925
926 static VOID NTAPI
927 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
928 PCOORD pSize)
929 {
930 PGUI_CONSOLE_DATA GuiData = This->Context;
931 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
932 HMONITOR hMonitor;
933 MONITORINFO MonitorInfo;
934 LONG Width, Height;
935 UINT WidthUnit, HeightUnit;
936
937 if (!pSize) return;
938
939 /*
940 * Retrieve the monitor that is mostly covered by the current console window;
941 * default to primary monitor otherwise.
942 */
943 MonitorInfo.cbSize = sizeof(MonitorInfo);
944 hMonitor = MonitorFromWindow(GuiData->hWindow, MONITOR_DEFAULTTOPRIMARY);
945 if (hMonitor && GetMonitorInfoW(hMonitor, &MonitorInfo))
946 {
947 /* Retrieve the width and height of the client area of this monitor */
948 Width = MonitorInfo.rcWork.right - MonitorInfo.rcWork.left;
949 Height = MonitorInfo.rcWork.bottom - MonitorInfo.rcWork.top;
950 }
951 else
952 {
953 /*
954 * Retrieve the width and height of the client area for a full-screen
955 * window on the primary display monitor.
956 */
957 Width = GetSystemMetrics(SM_CXFULLSCREEN);
958 Height = GetSystemMetrics(SM_CYFULLSCREEN);
959
960 // RECT WorkArea;
961 // SystemParametersInfoW(SPI_GETWORKAREA, 0, &WorkArea, 0);
962 // Width = WorkArea.right;
963 // Height = WorkArea.bottom;
964 }
965
966 ActiveBuffer = GuiData->ActiveBuffer;
967 #if 0
968 // NOTE: This would be surprising if we wouldn't have an associated buffer...
969 if (ActiveBuffer)
970 #endif
971 GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit);
972 #if 0
973 else
974 /* Default: graphics mode */
975 WidthUnit = HeightUnit = 1;
976 #endif
977
978 Width -= (2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)));
979 Height -= (2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION));
980
981 if (Width < 0) Width = 0;
982 if (Height < 0) Height = 0;
983
984 pSize->X = (SHORT)(Width / (int)WidthUnit ) /* HACK */ + 2;
985 pSize->Y = (SHORT)(Height / (int)HeightUnit) /* HACK */ + 1;
986 }
987
988 static BOOL NTAPI
989 GuiGetSelectionInfo(IN OUT PFRONTEND This,
990 PCONSOLE_SELECTION_INFO pSelectionInfo)
991 {
992 PGUI_CONSOLE_DATA GuiData = This->Context;
993
994 if (pSelectionInfo == NULL) return FALSE;
995
996 ZeroMemory(pSelectionInfo, sizeof(*pSelectionInfo));
997 if (GuiData->Selection.dwFlags != CONSOLE_NO_SELECTION)
998 RtlCopyMemory(pSelectionInfo, &GuiData->Selection, sizeof(*pSelectionInfo));
999
1000 return TRUE;
1001 }
1002
1003 static BOOL NTAPI
1004 GuiSetPalette(IN OUT PFRONTEND This,
1005 HPALETTE PaletteHandle,
1006 UINT PaletteUsage)
1007 {
1008 PGUI_CONSOLE_DATA GuiData = This->Context;
1009 HPALETTE OldPalette;
1010
1011 // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
1012 if (PaletteHandle == NULL) return FALSE;
1013
1014 /* Set the new palette for the framebuffer */
1015 OldPalette = SelectPalette(GuiData->hMemDC, PaletteHandle, FALSE);
1016 if (OldPalette == NULL) return FALSE;
1017
1018 /* Specify the use of the system palette for the framebuffer */
1019 SetSystemPaletteUse(GuiData->hMemDC, PaletteUsage);
1020
1021 /* Realize the (logical) palette */
1022 RealizePalette(GuiData->hMemDC);
1023
1024 /* Save the original system palette handle */
1025 if (GuiData->hSysPalette == NULL) GuiData->hSysPalette = OldPalette;
1026
1027 return TRUE;
1028 }
1029
1030 static ULONG NTAPI
1031 GuiGetDisplayMode(IN OUT PFRONTEND This)
1032 {
1033 PGUI_CONSOLE_DATA GuiData = This->Context;
1034 ULONG DisplayMode = 0;
1035
1036 if (GuiData->GuiInfo.FullScreen)
1037 DisplayMode |= CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN
1038 else
1039 DisplayMode |= CONSOLE_WINDOWED;
1040
1041 return DisplayMode;
1042 }
1043
1044 static BOOL NTAPI
1045 GuiSetDisplayMode(IN OUT PFRONTEND This,
1046 ULONG NewMode)
1047 {
1048 PGUI_CONSOLE_DATA GuiData = This->Context;
1049 BOOL FullScreen;
1050
1051 if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
1052 return FALSE;
1053
1054 /* Do nothing if the window is hidden */
1055 if (!GuiData->IsWindowVisible) return TRUE;
1056
1057 FullScreen = ((NewMode & CONSOLE_FULLSCREEN_MODE) != 0);
1058
1059 if (FullScreen != GuiData->GuiInfo.FullScreen)
1060 {
1061 SwitchFullScreen(GuiData, FullScreen);
1062 }
1063
1064 return TRUE;
1065 }
1066
1067 static INT NTAPI
1068 GuiShowMouseCursor(IN OUT PFRONTEND This,
1069 BOOL Show)
1070 {
1071 PGUI_CONSOLE_DATA GuiData = This->Context;
1072
1073 if (GuiData->IsWindowVisible)
1074 {
1075 /* Set the reference count */
1076 if (Show) ++GuiData->MouseCursorRefCount;
1077 else --GuiData->MouseCursorRefCount;
1078
1079 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
1080 PostMessageW(GuiData->hWindow, WM_SETCURSOR, -1, -1);
1081 }
1082
1083 return GuiData->MouseCursorRefCount;
1084 }
1085
1086 static BOOL NTAPI
1087 GuiSetMouseCursor(IN OUT PFRONTEND This,
1088 HCURSOR CursorHandle)
1089 {
1090 PGUI_CONSOLE_DATA GuiData = This->Context;
1091
1092 /* Do nothing if the window is hidden */
1093 if (!GuiData->IsWindowVisible) return TRUE;
1094
1095 /*
1096 * Set the cursor's handle. If the given handle is NULL,
1097 * then restore the default cursor.
1098 */
1099 GuiData->hCursor = (CursorHandle ? CursorHandle : ghDefaultCursor);
1100
1101 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
1102 PostMessageW(GuiData->hWindow, WM_SETCURSOR, -1, -1);
1103
1104 return TRUE;
1105 }
1106
1107 static HMENU NTAPI
1108 GuiMenuControl(IN OUT PFRONTEND This,
1109 UINT CmdIdLow,
1110 UINT CmdIdHigh)
1111 {
1112 PGUI_CONSOLE_DATA GuiData = This->Context;
1113
1114 GuiData->CmdIdLow = CmdIdLow ;
1115 GuiData->CmdIdHigh = CmdIdHigh;
1116
1117 return GetSystemMenu(GuiData->hWindow, FALSE);
1118 }
1119
1120 static BOOL NTAPI
1121 GuiSetMenuClose(IN OUT PFRONTEND This,
1122 BOOL Enable)
1123 {
1124 /*
1125 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
1126 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
1127 * for more information.
1128 */
1129
1130 PGUI_CONSOLE_DATA GuiData = This->Context;
1131 HMENU hSysMenu = GetSystemMenu(GuiData->hWindow, FALSE);
1132
1133 if (hSysMenu == NULL) return FALSE;
1134
1135 GuiData->IsCloseButtonEnabled = Enable;
1136 EnableMenuItem(hSysMenu, SC_CLOSE, MF_BYCOMMAND | (Enable ? MF_ENABLED : MF_GRAYED));
1137
1138 return TRUE;
1139 }
1140
1141 static FRONTEND_VTBL GuiVtbl =
1142 {
1143 GuiInitFrontEnd,
1144 GuiDeinitFrontEnd,
1145 GuiDrawRegion,
1146 GuiWriteStream,
1147 GuiRingBell,
1148 GuiSetCursorInfo,
1149 GuiSetScreenInfo,
1150 GuiResizeTerminal,
1151 GuiSetActiveScreenBuffer,
1152 GuiReleaseScreenBuffer,
1153 GuiRefreshInternalInfo,
1154 GuiChangeTitle,
1155 GuiChangeIcon,
1156 GuiGetConsoleWindowHandle,
1157 GuiGetLargestConsoleWindowSize,
1158 GuiGetSelectionInfo,
1159 GuiSetPalette,
1160 GuiGetDisplayMode,
1161 GuiSetDisplayMode,
1162 GuiShowMouseCursor,
1163 GuiSetMouseCursor,
1164 GuiMenuControl,
1165 GuiSetMenuClose,
1166 };
1167
1168
1169 NTSTATUS NTAPI
1170 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
1171 IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
1172 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
1173 IN HANDLE ConsoleLeaderProcessHandle)
1174 {
1175 PCONSOLE_START_INFO ConsoleStartInfo;
1176 PGUI_INIT_INFO GuiInitInfo;
1177
1178 if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleInitInfo == NULL)
1179 return STATUS_INVALID_PARAMETER;
1180
1181 ConsoleStartInfo = ConsoleInitInfo->ConsoleStartInfo;
1182
1183 /*
1184 * Initialize a private initialization info structure for later use.
1185 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
1186 */
1187 GuiInitInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*GuiInitInfo));
1188 if (GuiInitInfo == NULL) return STATUS_NO_MEMORY;
1189
1190 /* Initialize GUI terminal emulator common functionalities */
1191 if (!GuiInit(ConsoleInitInfo, ConsoleLeaderProcessHandle, GuiInitInfo))
1192 {
1193 ConsoleFreeHeap(GuiInitInfo);
1194 return STATUS_UNSUCCESSFUL;
1195 }
1196
1197 /*
1198 * Load terminal settings
1199 */
1200 #if 0
1201 /* Impersonate the caller in order to retrieve settings in its context */
1202 // if (!CsrImpersonateClient(NULL))
1203 // return STATUS_UNSUCCESSFUL;
1204 CsrImpersonateClient(NULL);
1205
1206 /* 1. Load the default settings */
1207 GuiConsoleGetDefaultSettings(&GuiInitInfo->TermInfo);
1208 #endif
1209
1210 GuiInitInfo->TermInfo.ShowWindow = SW_SHOWNORMAL;
1211
1212 if (ConsoleInitInfo->IsWindowVisible)
1213 {
1214 /* 2. Load the remaining console settings via the registry */
1215 if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
1216 {
1217 #if 0
1218 /* Load the terminal infos from the registry */
1219 GuiConsoleReadUserSettings(&GuiInitInfo->TermInfo);
1220 #endif
1221
1222 /*
1223 * Now, update them with the properties the user might gave to us
1224 * via the STARTUPINFO structure before calling CreateProcess
1225 * (and which was transmitted via the ConsoleStartInfo structure).
1226 * We therefore overwrite the values read in the registry.
1227 */
1228 if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
1229 {
1230 GuiInitInfo->TermInfo.ShowWindow = ConsoleStartInfo->wShowWindow;
1231 }
1232 if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
1233 {
1234 ConsoleInfo->AutoPosition = FALSE;
1235 ConsoleInfo->WindowPosition.x = ConsoleStartInfo->dwWindowOrigin.X;
1236 ConsoleInfo->WindowPosition.y = ConsoleStartInfo->dwWindowOrigin.Y;
1237 }
1238 if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
1239 {
1240 ConsoleInfo->FullScreen = TRUE;
1241 }
1242 }
1243 }
1244
1245 #if 0
1246 /* Revert impersonation */
1247 CsrRevertToSelf();
1248 #endif
1249
1250 // Font data
1251 StringCchCopyNW(GuiInitInfo->TermInfo.FaceName, ARRAYSIZE(GuiInitInfo->TermInfo.FaceName),
1252 ConsoleInfo->FaceName, ARRAYSIZE(ConsoleInfo->FaceName));
1253 GuiInitInfo->TermInfo.FontFamily = ConsoleInfo->FontFamily;
1254 GuiInitInfo->TermInfo.FontSize = ConsoleInfo->FontSize;
1255 GuiInitInfo->TermInfo.FontWeight = ConsoleInfo->FontWeight;
1256
1257 // Display
1258 GuiInitInfo->TermInfo.FullScreen = ConsoleInfo->FullScreen;
1259 // GuiInitInfo->TermInfo.ShowWindow;
1260 GuiInitInfo->TermInfo.AutoPosition = ConsoleInfo->AutoPosition;
1261 GuiInitInfo->TermInfo.WindowOrigin = ConsoleInfo->WindowPosition;
1262
1263 /* Initialize the icon handles */
1264 // if (ConsoleStartInfo->hIcon != NULL)
1265 GuiInitInfo->hIcon = ConsoleStartInfo->hIcon;
1266 // else
1267 // GuiInitInfo->hIcon = ghDefaultIcon;
1268
1269 // if (ConsoleStartInfo->hIconSm != NULL)
1270 GuiInitInfo->hIconSm = ConsoleStartInfo->hIconSm;
1271 // else
1272 // GuiInitInfo->hIconSm = ghDefaultIconSm;
1273
1274 // ASSERT(GuiInitInfo->hIcon && GuiInitInfo->hIconSm);
1275
1276 GuiInitInfo->IsWindowVisible = ConsoleInitInfo->IsWindowVisible;
1277
1278 /* Finally, initialize the frontend structure */
1279 FrontEnd->Vtbl = &GuiVtbl;
1280 FrontEnd->Context = NULL;
1281 FrontEnd->Context2 = GuiInitInfo;
1282
1283 return STATUS_SUCCESS;
1284 }
1285
1286 NTSTATUS NTAPI
1287 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)
1288 {
1289 if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER;
1290
1291 if (FrontEnd->Context ) GuiDeinitFrontEnd(FrontEnd);
1292 if (FrontEnd->Context2) ConsoleFreeHeap(FrontEnd->Context2);
1293
1294 return STATUS_SUCCESS;
1295 }
1296
1297 /* EOF */