c3e14d309900beb153507843633f1f2e2d2d4b86
[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 /*
233 while (PeekMessageW(&TempMsg, NULL, 0, 0, PM_REMOVE))
234 {
235 TranslateMessage(&TempMsg);
236 DispatchMessageW(&TempMsg);
237 }*/
238 while (PeekMessageW(&TempMsg, NULL, 0, 0, PM_REMOVE)) ;
239
240 if (GuiData->hWindow == NULL) continue;
241
242 DestroyWindow(GuiData->hWindow);
243
244 NtSetEvent(GuiData->hGuiTermEvent, NULL);
245
246 if (InterlockedDecrement(&WindowCount) == 0)
247 {
248 DPRINT("CONSRV: Going to quit the Input Thread 0x%p\n", InputThreadId);
249 goto Quit;
250 }
251
252 continue;
253 }
254 }
255
256 TranslateMessage(&msg);
257 DispatchMessageW(&msg);
258 }
259
260 Quit:
261 DPRINT("CONSRV: Quit the Input Thread 0x%p, Status = 0x%08lx\n", InputThreadId, Status);
262
263 /* Remove this console input thread from this desktop */
264 // DesktopConsoleThreadInfo.DesktopHandle;
265 DesktopConsoleThreadInfo.ThreadId = 0;
266 NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
267 &DesktopConsoleThreadInfo,
268 sizeof(DesktopConsoleThreadInfo));
269
270 /* Close the duplicated desktop handle */
271 CloseDesktop(DesktopConsoleThreadInfo.DesktopHandle); // NtUserCloseDesktop
272
273 /* Cleanup CSR thread */
274 if (pcsrt)
275 {
276 if (hThread != pcsrt->ThreadHandle)
277 DPRINT1("WARNING!! hThread (0x%p) != pcsrt->ThreadHandle (0x%p), you may expect crashes soon!!\n", hThread, pcsrt->ThreadHandle);
278
279 CsrDereferenceThread(pcsrt);
280 }
281
282 /* Exit the thread */
283 RtlExitUserThread(Status);
284 return 0;
285 }
286
287 // FIXME: Maybe return a NTSTATUS
288 static BOOL
289 GuiInit(IN PCONSOLE_INIT_INFO ConsoleInitInfo,
290 IN HANDLE ConsoleLeaderProcessHandle,
291 IN OUT PGUI_INIT_INFO GuiInitInfo)
292 {
293 BOOL Success = TRUE;
294 UNICODE_STRING DesktopPath;
295 DESKTOP_CONSOLE_THREAD DesktopConsoleThreadInfo;
296 HWINSTA hWinSta;
297 HDESK hDesk;
298
299 NTSTATUS Status;
300 HANDLE hInputThread;
301 CLIENT_ID ClientId;
302
303 /*
304 * Initialize and register the console window class, if needed.
305 */
306 if (!ConsInitialized)
307 {
308 if (!RegisterConWndClass(ConSrvDllInstance)) return FALSE;
309 ConsInitialized = TRUE;
310 }
311
312 /*
313 * Set-up the console input thread. We have
314 * one console input thread per desktop.
315 */
316
317 if (!CsrImpersonateClient(NULL))
318 // return STATUS_BAD_IMPERSONATION_LEVEL;
319 return FALSE;
320
321 if (ConsoleInitInfo->DesktopLength)
322 {
323 DesktopPath.MaximumLength = ConsoleInitInfo->DesktopLength;
324 DesktopPath.Length = DesktopPath.MaximumLength - sizeof(UNICODE_NULL);
325 DesktopPath.Buffer = ConsoleInitInfo->Desktop;
326 }
327 else
328 {
329 RtlInitUnicodeString(&DesktopPath, L"Default");
330 }
331
332 hDesk = NtUserResolveDesktop(ConsoleLeaderProcessHandle,
333 &DesktopPath,
334 0,
335 &hWinSta);
336 DPRINT("NtUserResolveDesktop(DesktopPath = '%wZ') returned hDesk = 0x%p; hWinSta = 0x%p\n",
337 &DesktopPath, hDesk, hWinSta);
338
339 CsrRevertToSelf();
340
341 if (hDesk == NULL) return FALSE;
342
343 /*
344 * We need to see whether we need to create a
345 * new console input thread for this desktop.
346 */
347 DesktopConsoleThreadInfo.DesktopHandle = hDesk;
348 DesktopConsoleThreadInfo.ThreadId = (ULONG_PTR)INVALID_HANDLE_VALUE; // Special value to say we just want to retrieve the thread ID.
349 NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
350 &DesktopConsoleThreadInfo,
351 sizeof(DesktopConsoleThreadInfo));
352 DPRINT("NtUserConsoleControl returned ThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId);
353
354 /*
355 * Save the opened window station and desktop handles in the initialization
356 * structure. They will be used later on, and released, by the GUI frontend.
357 */
358 GuiInitInfo->WinSta = hWinSta;
359 GuiInitInfo->Desktop = hDesk;
360
361 /* Here GuiInitInfo contains original handles */
362
363 /* If we already have a console input thread on this desktop... */
364 if (DesktopConsoleThreadInfo.ThreadId != 0)
365 {
366 /* ... just use it... */
367 DPRINT("Using input thread InputThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId);
368 GuiInitInfo->InputThreadId = DesktopConsoleThreadInfo.ThreadId;
369 goto Quit;
370 }
371
372 /* ... otherwise create a new one. */
373
374 /* Initialize a startup event for the thread to signal it */
375 Status = NtCreateEvent(&GuiInitInfo->GuiThreadStartupEvent, EVENT_ALL_ACCESS,
376 NULL, SynchronizationEvent, FALSE);
377 if (!NT_SUCCESS(Status))
378 {
379 Success = FALSE;
380 goto Quit;
381 }
382
383 /*
384 * Duplicate the desktop handle for the console input thread internal needs.
385 * If it happens to need also a window station handle in the future, then
386 * it is there that you also need to duplicate the window station handle!
387 *
388 * Note also that we are going to temporarily overwrite the stored handles
389 * in GuiInitInfo because it happens that we use also this structure to give
390 * the duplicated handles to the input thread that is going to initialize.
391 * After the input thread finishes its initialization, we restore the handles
392 * in GuiInitInfo to their old values.
393 */
394 Status = NtDuplicateObject(NtCurrentProcess(),
395 hDesk,
396 NtCurrentProcess(),
397 (PHANDLE)&GuiInitInfo->Desktop,
398 0, 0, DUPLICATE_SAME_ACCESS);
399 if (!NT_SUCCESS(Status))
400 {
401 Success = FALSE;
402 goto Quit;
403 }
404
405 /* Here GuiInitInfo contains duplicated handles */
406
407 Status = RtlCreateUserThread(NtCurrentProcess(),
408 NULL,
409 TRUE, // Start the thread in suspended state
410 0,
411 0,
412 0,
413 (PVOID)GuiConsoleInputThread,
414 (PVOID)GuiInitInfo,
415 &hInputThread,
416 &ClientId);
417 if (NT_SUCCESS(Status))
418 {
419 /* Add it as a static server thread and resume it */
420 CsrAddStaticServerThread(hInputThread, &ClientId, 0);
421 Status = NtResumeThread(hInputThread, NULL);
422 }
423 DPRINT("Thread creation hInputThread = 0x%p, InputThreadId = 0x%p, Status = 0x%08lx\n",
424 hInputThread, ClientId.UniqueThread, Status);
425
426 if (!NT_SUCCESS(Status) || hInputThread == NULL)
427 {
428 /* Close the thread's handle */
429 if (hInputThread) NtClose(hInputThread);
430
431 /* We need to close here the duplicated desktop handle */
432 CloseDesktop(GuiInitInfo->Desktop); // NtUserCloseDesktop
433
434 /* Close the startup event and bail out */
435 NtClose(GuiInitInfo->GuiThreadStartupEvent);
436
437 DPRINT1("CONSRV: Failed to create graphics console thread.\n");
438 Success = FALSE;
439 goto Quit;
440 }
441
442 /* No need to close hInputThread, this is done by CSR automatically */
443
444 /* Wait for the thread to finish its initialization, and close the startup event */
445 NtWaitForSingleObject(GuiInitInfo->GuiThreadStartupEvent, FALSE, NULL);
446 NtClose(GuiInitInfo->GuiThreadStartupEvent);
447
448 /*
449 * Save the input thread ID for later use, and restore the original handles.
450 * The copies are held by the console input thread.
451 */
452 GuiInitInfo->InputThreadId = (ULONG_PTR)ClientId.UniqueThread;
453 GuiInitInfo->WinSta = hWinSta;
454 GuiInitInfo->Desktop = hDesk;
455
456 /* Here GuiInitInfo contains again original handles */
457
458 Quit:
459 if (!Success)
460 {
461 /*
462 * Close the original handles. Do not use the copies in GuiInitInfo
463 * because we may have failed in the middle of the duplicate operation
464 * and the handles stored in GuiInitInfo may have changed.
465 */
466 CloseDesktop(hDesk); // NtUserCloseDesktop
467 CloseWindowStation(hWinSta); // NtUserCloseWindowStation
468 }
469
470 return Success;
471 }
472
473
474 /******************************************************************************
475 * GUI Console Driver *
476 ******************************************************************************/
477
478 static VOID NTAPI
479 GuiDeinitFrontEnd(IN OUT PFRONTEND This);
480
481 static NTSTATUS NTAPI
482 GuiInitFrontEnd(IN OUT PFRONTEND This,
483 IN PCONSRV_CONSOLE Console)
484 {
485 PGUI_INIT_INFO GuiInitInfo;
486 PGUI_CONSOLE_DATA GuiData;
487
488 if (This == NULL || Console == NULL || This->Context2 == NULL)
489 return STATUS_INVALID_PARAMETER;
490
491 ASSERT(This->Console == Console);
492
493 GuiInitInfo = This->Context2;
494
495 /* Terminal data allocation */
496 GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*GuiData));
497 if (!GuiData)
498 {
499 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
500 return STATUS_UNSUCCESSFUL;
501 }
502 /// /* HACK */ Console->FrontEndIFace.Context = (PVOID)GuiData; /* HACK */
503 GuiData->Console = Console;
504 GuiData->ActiveBuffer = Console->ActiveBuffer;
505 GuiData->hWindow = NULL;
506 GuiData->IsWindowVisible = GuiInitInfo->IsWindowVisible;
507
508 /* The console can be resized */
509 Console->FixedSize = FALSE;
510
511 InitializeCriticalSection(&GuiData->Lock);
512
513 /*
514 * Set up GUI data
515 */
516 RtlCopyMemory(&GuiData->GuiInfo, &GuiInitInfo->TermInfo, sizeof(GuiInitInfo->TermInfo));
517
518 /* Initialize the icon handles */
519 if (GuiInitInfo->hIcon != NULL)
520 GuiData->hIcon = GuiInitInfo->hIcon;
521 else
522 GuiData->hIcon = ghDefaultIcon;
523
524 if (GuiInitInfo->hIconSm != NULL)
525 GuiData->hIconSm = GuiInitInfo->hIconSm;
526 else
527 GuiData->hIconSm = ghDefaultIconSm;
528
529 ASSERT(GuiData->hIcon && GuiData->hIconSm);
530
531 /* Mouse is shown by default with its default cursor shape */
532 GuiData->hCursor = ghDefaultCursor;
533 GuiData->MouseCursorRefCount = 0;
534
535 /* A priori don't ignore mouse signals */
536 GuiData->IgnoreNextMouseSignal = FALSE;
537 /* Initialize HACK FOR CORE-8394. See conwnd.c!OnMouse for more details. */
538 GuiData->HackCORE8394IgnoreNextMove = FALSE;
539
540 /* Close button and the corresponding system menu item are enabled by default */
541 GuiData->IsCloseButtonEnabled = TRUE;
542
543 /* There is no user-reserved menu id range by default */
544 GuiData->CmdIdLow = GuiData->CmdIdHigh = 0;
545
546 /* Initialize the selection */
547 RtlZeroMemory(&GuiData->Selection, sizeof(GuiData->Selection));
548 GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
549 RtlZeroMemory(&GuiData->dwSelectionCursor, sizeof(GuiData->dwSelectionCursor));
550 GuiData->LineSelection = FALSE; // Default to block selection
551 // TODO: Retrieve the selection mode via the registry.
552
553 GuiData->InputThreadId = GuiInitInfo->InputThreadId;
554 GuiData->WinSta = GuiInitInfo->WinSta;
555 GuiData->Desktop = GuiInitInfo->Desktop;
556
557 /* Finally, finish to initialize the frontend structure */
558 This->Context = GuiData;
559 ConsoleFreeHeap(This->Context2);
560 This->Context2 = NULL;
561
562 /*
563 * We need to wait until the GUI has been fully initialized
564 * to retrieve custom settings i.e. WindowSize etc...
565 * Ideally we could use SendNotifyMessage for this but its not
566 * yet implemented.
567 */
568 NtCreateEvent(&GuiData->hGuiInitEvent, EVENT_ALL_ACCESS,
569 NULL, SynchronizationEvent, FALSE);
570 NtCreateEvent(&GuiData->hGuiTermEvent, EVENT_ALL_ACCESS,
571 NULL, SynchronizationEvent, FALSE);
572
573 DPRINT("GUI - Checkpoint\n");
574
575 /* Create the terminal window */
576 PostThreadMessageW(GuiData->InputThreadId, PM_CREATE_CONSOLE, 0, (LPARAM)GuiData);
577
578 /* Wait until initialization has finished */
579 NtWaitForSingleObject(GuiData->hGuiInitEvent, FALSE, NULL);
580 DPRINT("OK we created the console window\n");
581 NtClose(GuiData->hGuiInitEvent);
582 GuiData->hGuiInitEvent = NULL;
583
584 /* Check whether we really succeeded in initializing the terminal window */
585 if (GuiData->hWindow == NULL)
586 {
587 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
588 GuiDeinitFrontEnd(This);
589 return STATUS_UNSUCCESSFUL;
590 }
591
592 return STATUS_SUCCESS;
593 }
594
595 static VOID NTAPI
596 GuiDeinitFrontEnd(IN OUT PFRONTEND This)
597 {
598 PGUI_CONSOLE_DATA GuiData = This->Context;
599
600 DPRINT("Send PM_DESTROY_CONSOLE message and wait on hGuiTermEvent...\n");
601 PostThreadMessageW(GuiData->InputThreadId, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
602 NtWaitForSingleObject(GuiData->hGuiTermEvent, FALSE, NULL);
603 DPRINT("hGuiTermEvent set\n");
604 NtClose(GuiData->hGuiTermEvent);
605 GuiData->hGuiTermEvent = NULL;
606
607 CloseDesktop(GuiData->Desktop); // NtUserCloseDesktop
608 CloseWindowStation(GuiData->WinSta); // NtUserCloseWindowStation
609
610 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
611 GuiData->hIcon, ghDefaultIcon, GuiData->hIconSm, ghDefaultIconSm);
612 if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
613 {
614 DPRINT("Destroy hIcon\n");
615 DestroyIcon(GuiData->hIcon);
616 }
617 if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
618 {
619 DPRINT("Destroy hIconSm\n");
620 DestroyIcon(GuiData->hIconSm);
621 }
622
623 This->Context = NULL;
624 DeleteCriticalSection(&GuiData->Lock);
625 ConsoleFreeHeap(GuiData);
626
627 DPRINT("Quit GuiDeinitFrontEnd\n");
628 }
629
630 static VOID NTAPI
631 GuiDrawRegion(IN OUT PFRONTEND This,
632 SMALL_RECT* Region)
633 {
634 PGUI_CONSOLE_DATA GuiData = This->Context;
635
636 /* Do nothing if the window is hidden */
637 if (!GuiData->IsWindowVisible) return;
638
639 DrawRegion(GuiData, Region);
640 }
641
642 static VOID NTAPI
643 GuiWriteStream(IN OUT PFRONTEND This,
644 SMALL_RECT* Region,
645 SHORT CursorStartX,
646 SHORT CursorStartY,
647 UINT ScrolledLines,
648 PWCHAR Buffer,
649 UINT Length)
650 {
651 PGUI_CONSOLE_DATA GuiData = This->Context;
652 PCONSOLE_SCREEN_BUFFER Buff;
653 SHORT CursorEndX, CursorEndY;
654 RECT ScrollRect;
655
656 if (NULL == GuiData || NULL == GuiData->hWindow) return;
657
658 /* Do nothing if the window is hidden */
659 if (!GuiData->IsWindowVisible) return;
660
661 Buff = GuiData->ActiveBuffer;
662 if (GetType(Buff) != TEXTMODE_BUFFER) return;
663
664 if (0 != ScrolledLines)
665 {
666 ScrollRect.left = 0;
667 ScrollRect.top = 0;
668 ScrollRect.right = Buff->ViewSize.X * GuiData->CharWidth;
669 ScrollRect.bottom = Region->Top * GuiData->CharHeight;
670
671 ScrollWindowEx(GuiData->hWindow,
672 0,
673 -(int)(ScrolledLines * GuiData->CharHeight),
674 &ScrollRect,
675 NULL,
676 NULL,
677 NULL,
678 SW_INVALIDATE);
679 }
680
681 DrawRegion(GuiData, Region);
682
683 if (CursorStartX < Region->Left || Region->Right < CursorStartX
684 || CursorStartY < Region->Top || Region->Bottom < CursorStartY)
685 {
686 InvalidateCell(GuiData, CursorStartX, CursorStartY);
687 }
688
689 CursorEndX = Buff->CursorPosition.X;
690 CursorEndY = Buff->CursorPosition.Y;
691 if ((CursorEndX < Region->Left || Region->Right < CursorEndX
692 || CursorEndY < Region->Top || Region->Bottom < CursorEndY)
693 && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
694 {
695 InvalidateCell(GuiData, CursorEndX, CursorEndY);
696 }
697
698 // HACK!!
699 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
700 // repaint the window without having it just freeze up and stay on the screen permanently.
701 Buff->CursorBlinkOn = TRUE;
702 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
703 }
704
705 /* static */ VOID NTAPI
706 GuiRingBell(IN OUT PFRONTEND This)
707 {
708 PGUI_CONSOLE_DATA GuiData = This->Context;
709
710 /* Emit an error beep sound */
711 SendNotifyMessage(GuiData->hWindow, PM_CONSOLE_BEEP, 0, 0);
712 }
713
714 static BOOL NTAPI
715 GuiSetCursorInfo(IN OUT PFRONTEND This,
716 PCONSOLE_SCREEN_BUFFER Buff)
717 {
718 PGUI_CONSOLE_DATA GuiData = This->Context;
719
720 /* Do nothing if the window is hidden */
721 if (!GuiData->IsWindowVisible) return TRUE;
722
723 if (GuiData->ActiveBuffer == Buff)
724 {
725 InvalidateCell(GuiData, Buff->CursorPosition.X, Buff->CursorPosition.Y);
726 }
727
728 return TRUE;
729 }
730
731 static BOOL NTAPI
732 GuiSetScreenInfo(IN OUT PFRONTEND This,
733 PCONSOLE_SCREEN_BUFFER Buff,
734 SHORT OldCursorX,
735 SHORT OldCursorY)
736 {
737 PGUI_CONSOLE_DATA GuiData = This->Context;
738
739 /* Do nothing if the window is hidden */
740 if (!GuiData->IsWindowVisible) return TRUE;
741
742 if (GuiData->ActiveBuffer == Buff)
743 {
744 /* Redraw char at old position (remove cursor) */
745 InvalidateCell(GuiData, OldCursorX, OldCursorY);
746 /* Redraw char at new position (show cursor) */
747 InvalidateCell(GuiData, Buff->CursorPosition.X, Buff->CursorPosition.Y);
748 }
749
750 return TRUE;
751 }
752
753 static VOID NTAPI
754 GuiResizeTerminal(IN OUT PFRONTEND This)
755 {
756 PGUI_CONSOLE_DATA GuiData = This->Context;
757
758 /* Resize the window to the user's values */
759 PostMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
760 }
761
762 static VOID NTAPI
763 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This)
764 {
765 PGUI_CONSOLE_DATA GuiData = This->Context;
766 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
767 HPALETTE hPalette;
768
769 EnterCriticalSection(&GuiData->Lock);
770 GuiData->WindowSizeLock = TRUE;
771
772 InterlockedExchangePointer((PVOID*)&GuiData->ActiveBuffer,
773 ConDrvGetActiveScreenBuffer(GuiData->Console));
774
775 GuiData->WindowSizeLock = FALSE;
776 LeaveCriticalSection(&GuiData->Lock);
777
778 ActiveBuffer = GuiData->ActiveBuffer;
779
780 /* Change the current palette */
781 if (ActiveBuffer->PaletteHandle == NULL)
782 hPalette = GuiData->hSysPalette;
783 else
784 hPalette = ActiveBuffer->PaletteHandle;
785
786 DPRINT("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette);
787
788 /* Set the new palette for the framebuffer */
789 SelectPalette(GuiData->hMemDC, hPalette, FALSE);
790
791 /* Specify the use of the system palette for the framebuffer */
792 SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage);
793
794 /* Realize the (logical) palette */
795 RealizePalette(GuiData->hMemDC);
796
797 GuiResizeTerminal(This);
798 // ConioDrawConsole(Console);
799 }
800
801 static VOID NTAPI
802 GuiReleaseScreenBuffer(IN OUT PFRONTEND This,
803 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer)
804 {
805 PGUI_CONSOLE_DATA GuiData = This->Context;
806
807 /*
808 * If we were notified to release a screen buffer that is not actually
809 * ours, then just ignore the notification...
810 */
811 if (ScreenBuffer != GuiData->ActiveBuffer) return;
812
813 /*
814 * ... else, we must release our active buffer. Two cases are present:
815 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
816 * active screen buffer, then we can safely switch to it.
817 * - If ScreenBuffer IS the console active screen buffer, we must release
818 * it ONLY.
819 */
820
821 /* Release the old active palette and set the default one */
822 if (GetCurrentObject(GuiData->hMemDC, OBJ_PAL) == ScreenBuffer->PaletteHandle)
823 {
824 /* Set the new palette */
825 SelectPalette(GuiData->hMemDC, GuiData->hSysPalette, FALSE);
826 }
827
828 /* Set the adequate active screen buffer */
829 if (ScreenBuffer != GuiData->Console->ActiveBuffer)
830 {
831 GuiSetActiveScreenBuffer(This);
832 }
833 else
834 {
835 EnterCriticalSection(&GuiData->Lock);
836 GuiData->WindowSizeLock = TRUE;
837
838 InterlockedExchangePointer((PVOID*)&GuiData->ActiveBuffer, NULL);
839
840 GuiData->WindowSizeLock = FALSE;
841 LeaveCriticalSection(&GuiData->Lock);
842 }
843 }
844
845 static BOOL NTAPI
846 GuiSetMouseCursor(IN OUT PFRONTEND This,
847 HCURSOR CursorHandle);
848
849 static VOID NTAPI
850 GuiRefreshInternalInfo(IN OUT PFRONTEND This)
851 {
852 PGUI_CONSOLE_DATA GuiData = This->Context;
853
854 /* Update the console leader information held by the window */
855 SetConWndConsoleLeaderCID(GuiData);
856
857 /*
858 * HACK:
859 * We reset the cursor here so that, when a console app quits, we reset
860 * the cursor to the default one. It's quite a hack since it doesn't proceed
861 * per - console process... This must be fixed.
862 *
863 * See GuiInitConsole(...) for more information.
864 */
865
866 /* Mouse is shown by default with its default cursor shape */
867 GuiData->MouseCursorRefCount = 0; // Reinitialize the reference counter
868 GuiSetMouseCursor(This, NULL);
869 }
870
871 static VOID NTAPI
872 GuiChangeTitle(IN OUT PFRONTEND This)
873 {
874 PGUI_CONSOLE_DATA GuiData = This->Context;
875 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
876 SetWindowTextW(GuiData->hWindow, GuiData->Console->Title.Buffer);
877 }
878
879 static BOOL NTAPI
880 GuiChangeIcon(IN OUT PFRONTEND This,
881 HICON IconHandle)
882 {
883 PGUI_CONSOLE_DATA GuiData = This->Context;
884 HICON hIcon, hIconSm;
885
886 if (IconHandle == NULL)
887 {
888 hIcon = ghDefaultIcon;
889 hIconSm = ghDefaultIconSm;
890 }
891 else
892 {
893 hIcon = CopyIcon(IconHandle);
894 hIconSm = CopyIcon(IconHandle);
895 }
896
897 if (hIcon == NULL)
898 return FALSE;
899
900 if (hIcon != GuiData->hIcon)
901 {
902 if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
903 {
904 DestroyIcon(GuiData->hIcon);
905 }
906 if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
907 {
908 DestroyIcon(GuiData->hIconSm);
909 }
910
911 GuiData->hIcon = hIcon;
912 GuiData->hIconSm = hIconSm;
913
914 DPRINT("Set icons in GuiChangeIcon\n");
915 PostMessageW(GuiData->hWindow, WM_SETICON, ICON_BIG , (LPARAM)GuiData->hIcon );
916 PostMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
917 }
918
919 return TRUE;
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 GetSystemMenu(GuiData->hWindow, FALSE);
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 HMENU hSysMenu = GetSystemMenu(GuiData->hWindow, FALSE);
1135
1136 if (hSysMenu == NULL) return FALSE;
1137
1138 GuiData->IsCloseButtonEnabled = Enable;
1139 EnableMenuItem(hSysMenu, SC_CLOSE, MF_BYCOMMAND | (Enable ? MF_ENABLED : MF_GRAYED));
1140
1141 return TRUE;
1142 }
1143
1144 static FRONTEND_VTBL GuiVtbl =
1145 {
1146 GuiInitFrontEnd,
1147 GuiDeinitFrontEnd,
1148 GuiDrawRegion,
1149 GuiWriteStream,
1150 GuiRingBell,
1151 GuiSetCursorInfo,
1152 GuiSetScreenInfo,
1153 GuiResizeTerminal,
1154 GuiSetActiveScreenBuffer,
1155 GuiReleaseScreenBuffer,
1156 GuiRefreshInternalInfo,
1157 GuiChangeTitle,
1158 GuiChangeIcon,
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
1181 if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleInitInfo == NULL)
1182 return STATUS_INVALID_PARAMETER;
1183
1184 ConsoleStartInfo = ConsoleInitInfo->ConsoleStartInfo;
1185
1186 /*
1187 * Initialize a private initialization info structure for later use.
1188 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
1189 */
1190 GuiInitInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*GuiInitInfo));
1191 if (GuiInitInfo == NULL) return STATUS_NO_MEMORY;
1192
1193 /* Initialize GUI terminal emulator common functionalities */
1194 if (!GuiInit(ConsoleInitInfo, ConsoleLeaderProcessHandle, GuiInitInfo))
1195 {
1196 ConsoleFreeHeap(GuiInitInfo);
1197 return STATUS_UNSUCCESSFUL;
1198 }
1199
1200 /*
1201 * Load terminal settings
1202 */
1203 #if 0
1204 /* Impersonate the caller in order to retrieve settings in its context */
1205 // if (!CsrImpersonateClient(NULL))
1206 // return STATUS_UNSUCCESSFUL;
1207 CsrImpersonateClient(NULL);
1208
1209 /* 1. Load the default settings */
1210 GuiConsoleGetDefaultSettings(&GuiInitInfo->TermInfo);
1211 #endif
1212
1213 GuiInitInfo->TermInfo.ShowWindow = SW_SHOWNORMAL;
1214
1215 if (ConsoleInitInfo->IsWindowVisible)
1216 {
1217 /* 2. Load the remaining console settings via the registry */
1218 if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
1219 {
1220 #if 0
1221 /* Load the terminal infos from the registry */
1222 GuiConsoleReadUserSettings(&GuiInitInfo->TermInfo);
1223 #endif
1224
1225 /*
1226 * Now, update them with the properties the user might gave to us
1227 * via the STARTUPINFO structure before calling CreateProcess
1228 * (and which was transmitted via the ConsoleStartInfo structure).
1229 * We therefore overwrite the values read in the registry.
1230 */
1231 if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
1232 {
1233 GuiInitInfo->TermInfo.ShowWindow = ConsoleStartInfo->wShowWindow;
1234 }
1235 if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
1236 {
1237 ConsoleInfo->AutoPosition = FALSE;
1238 ConsoleInfo->WindowPosition.x = ConsoleStartInfo->dwWindowOrigin.X;
1239 ConsoleInfo->WindowPosition.y = ConsoleStartInfo->dwWindowOrigin.Y;
1240 }
1241 if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
1242 {
1243 ConsoleInfo->FullScreen = TRUE;
1244 }
1245 }
1246 }
1247
1248 #if 0
1249 /* Revert impersonation */
1250 CsrRevertToSelf();
1251 #endif
1252
1253 // Font data
1254 StringCchCopyNW(GuiInitInfo->TermInfo.FaceName, ARRAYSIZE(GuiInitInfo->TermInfo.FaceName),
1255 ConsoleInfo->FaceName, ARRAYSIZE(ConsoleInfo->FaceName));
1256 GuiInitInfo->TermInfo.FontFamily = ConsoleInfo->FontFamily;
1257 GuiInitInfo->TermInfo.FontSize = ConsoleInfo->FontSize;
1258 GuiInitInfo->TermInfo.FontWeight = ConsoleInfo->FontWeight;
1259
1260 // Display
1261 GuiInitInfo->TermInfo.FullScreen = ConsoleInfo->FullScreen;
1262 // GuiInitInfo->TermInfo.ShowWindow;
1263 GuiInitInfo->TermInfo.AutoPosition = ConsoleInfo->AutoPosition;
1264 GuiInitInfo->TermInfo.WindowOrigin = ConsoleInfo->WindowPosition;
1265
1266 /* Initialize the icon handles */
1267 // if (ConsoleStartInfo->hIcon != NULL)
1268 GuiInitInfo->hIcon = ConsoleStartInfo->hIcon;
1269 // else
1270 // GuiInitInfo->hIcon = ghDefaultIcon;
1271
1272 // if (ConsoleStartInfo->hIconSm != NULL)
1273 GuiInitInfo->hIconSm = ConsoleStartInfo->hIconSm;
1274 // else
1275 // GuiInitInfo->hIconSm = ghDefaultIconSm;
1276
1277 // ASSERT(GuiInitInfo->hIcon && GuiInitInfo->hIconSm);
1278
1279 GuiInitInfo->IsWindowVisible = ConsoleInitInfo->IsWindowVisible;
1280
1281 /* Finally, initialize the frontend structure */
1282 FrontEnd->Vtbl = &GuiVtbl;
1283 FrontEnd->Context = NULL;
1284 FrontEnd->Context2 = GuiInitInfo;
1285
1286 return STATUS_SUCCESS;
1287 }
1288
1289 NTSTATUS NTAPI
1290 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)
1291 {
1292 if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER;
1293
1294 if (FrontEnd->Context ) GuiDeinitFrontEnd(FrontEnd);
1295 if (FrontEnd->Context2) ConsoleFreeHeap(FrontEnd->Context2);
1296
1297 return STATUS_SUCCESS;
1298 }
1299
1300 /* EOF */