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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 920 GuiGetThreadConsoleDesktop(IN OUT PFRONTEND This) 921 { 922 PGUI_CONSOLE_DATA GuiData = This->Context; 923 return GuiData->Desktop; 924 } 925 926 static HWND NTAPI 927 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This) 928 { 929 PGUI_CONSOLE_DATA GuiData = This->Context; 930 return GuiData->hWindow; 931 } 932 933 static VOID NTAPI 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 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 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 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 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 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 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 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 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 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 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 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