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