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