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