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