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