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