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