1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Boot Theme & Animation 5 * COPYRIGHT: Copyright 2007 Alex Ionescu (alex.ionescu@reactos.org) 6 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org) 7 * Copyright 2012-2022 Hermès Bélusca-Maïto 8 * Copyright 2017-2018 Stanislav Motylkov 9 * Copyright 2019-2020 Yaroslav Kibysh 10 */ 11 12 /* INCLUDES ******************************************************************/ 13 14 #include <ntoskrnl.h> 15 #include "inbv/logo.h" 16 17 /* See also mm/ARM3/miarm.h */ 18 #define MM_READONLY 1 // PAGE_READONLY 19 #define MM_READWRITE 4 // PAGE_WRITECOPY 20 21 /* GLOBALS *******************************************************************/ 22 23 /* 24 * ReactOS uses the same boot screen for all the products. 25 * 26 * Enable this define when ReactOS will have different SKUs 27 * (Workstation, Server, Storage Server, Cluster Server, etc...). 28 */ 29 // #define REACTOS_SKUS 30 31 typedef enum _ROT_BAR_TYPE 32 { 33 RB_UNSPECIFIED, 34 RB_SQUARE_CELLS, 35 RB_PROGRESS_BAR 36 } ROT_BAR_TYPE; 37 38 /* 39 * BitBltAligned() alignments 40 */ 41 typedef enum _BBLT_VERT_ALIGNMENT 42 { 43 AL_VERTICAL_TOP = 0, 44 AL_VERTICAL_CENTER, 45 AL_VERTICAL_BOTTOM 46 } BBLT_VERT_ALIGNMENT; 47 48 typedef enum _BBLT_HORZ_ALIGNMENT 49 { 50 AL_HORIZONTAL_LEFT = 0, 51 AL_HORIZONTAL_CENTER, 52 AL_HORIZONTAL_RIGHT 53 } BBLT_HORZ_ALIGNMENT; 54 55 /* 56 * Enable this define when Inbv will support rotating progress bar. 57 */ 58 #define INBV_ROTBAR_IMPLEMENTED 59 60 extern ULONG ProgressBarLeft, ProgressBarTop; 61 extern BOOLEAN ShowProgressBar; 62 63 #ifdef INBV_ROTBAR_IMPLEMENTED 64 /* 65 * Change this to modify progress bar behaviour 66 */ 67 #define ROT_BAR_DEFAULT_MODE RB_PROGRESS_BAR 68 69 /* 70 * Values for PltRotBarStatus: 71 * - PltRotBarStatus == 1, do palette fading-in (done elsewhere in ReactOS); 72 * - PltRotBarStatus == 2, do rotation bar animation; 73 * - PltRotBarStatus == 3, stop the animation thread. 74 * - Any other value is ignored and the animation thread continues to run. 75 */ 76 typedef enum _ROT_BAR_STATUS 77 { 78 RBS_FADEIN = 1, 79 RBS_ANIMATE, 80 RBS_STOP_ANIMATE, 81 RBS_STATUS_MAX 82 } ROT_BAR_STATUS; 83 84 static BOOLEAN RotBarThreadActive = FALSE; 85 static ROT_BAR_TYPE RotBarSelection = RB_UNSPECIFIED; 86 static ROT_BAR_STATUS PltRotBarStatus = 0; 87 static UCHAR RotBarBuffer[24 * 9]; 88 static UCHAR RotLineBuffer[SCREEN_WIDTH * 6]; 89 #endif 90 91 92 /* FADE-IN FUNCTION **********************************************************/ 93 94 /** From include/psdk/wingdi.h and bootvid/precomp.h **/ 95 typedef struct tagRGBQUAD 96 { 97 UCHAR rgbBlue; 98 UCHAR rgbGreen; 99 UCHAR rgbRed; 100 UCHAR rgbReserved; 101 } RGBQUAD, *LPRGBQUAD; 102 103 // 104 // Bitmap Header 105 // 106 typedef struct tagBITMAPINFOHEADER 107 { 108 ULONG biSize; 109 LONG biWidth; 110 LONG biHeight; 111 USHORT biPlanes; 112 USHORT biBitCount; 113 ULONG biCompression; 114 ULONG biSizeImage; 115 LONG biXPelsPerMeter; 116 LONG biYPelsPerMeter; 117 ULONG biClrUsed; 118 ULONG biClrImportant; 119 } BITMAPINFOHEADER, *PBITMAPINFOHEADER; 120 /*******************************/ 121 122 static RGBQUAD MainPalette[16]; 123 124 #define PALETTE_FADE_STEPS 12 125 #define PALETTE_FADE_TIME (15 * 1000) /* 15 ms */ 126 127 static VOID 128 BootLogoFadeIn(VOID) 129 { 130 UCHAR PaletteBitmapBuffer[sizeof(BITMAPINFOHEADER) + sizeof(MainPalette)]; 131 PBITMAPINFOHEADER PaletteBitmap = (PBITMAPINFOHEADER)PaletteBitmapBuffer; 132 LPRGBQUAD Palette = (LPRGBQUAD)(PaletteBitmapBuffer + sizeof(BITMAPINFOHEADER)); 133 ULONG Iteration, Index, ClrUsed; 134 135 LARGE_INTEGER Delay; 136 Delay.QuadPart = -(PALETTE_FADE_TIME * 10); 137 138 /* Check if we are installed and we own the display */ 139 if (!InbvBootDriverInstalled || 140 (InbvGetDisplayState() != INBV_DISPLAY_STATE_OWNED)) 141 { 142 return; 143 } 144 145 /* 146 * Build a bitmap containing the fade-in palette. The palette entries 147 * are then processed in a loop and set using VidBitBlt function. 148 */ 149 ClrUsed = RTL_NUMBER_OF(MainPalette); 150 RtlZeroMemory(PaletteBitmap, sizeof(BITMAPINFOHEADER)); 151 PaletteBitmap->biSize = sizeof(BITMAPINFOHEADER); 152 PaletteBitmap->biBitCount = 4; 153 PaletteBitmap->biClrUsed = ClrUsed; 154 155 /* 156 * Main animation loop. 157 */ 158 for (Iteration = 0; Iteration <= PALETTE_FADE_STEPS; ++Iteration) 159 { 160 for (Index = 0; Index < ClrUsed; Index++) 161 { 162 Palette[Index].rgbRed = (UCHAR) 163 (MainPalette[Index].rgbRed * Iteration / PALETTE_FADE_STEPS); 164 Palette[Index].rgbGreen = (UCHAR) 165 (MainPalette[Index].rgbGreen * Iteration / PALETTE_FADE_STEPS); 166 Palette[Index].rgbBlue = (UCHAR) 167 (MainPalette[Index].rgbBlue * Iteration / PALETTE_FADE_STEPS); 168 } 169 170 /* Do the animation */ 171 InbvAcquireLock(); 172 VidBitBlt(PaletteBitmapBuffer, 0, 0); 173 InbvReleaseLock(); 174 175 /* Wait for a bit */ 176 KeDelayExecutionThread(KernelMode, FALSE, &Delay); 177 } 178 } 179 180 static VOID 181 BitBltPalette( 182 IN PVOID Image, 183 IN BOOLEAN NoPalette, 184 IN ULONG X, 185 IN ULONG Y) 186 { 187 LPRGBQUAD Palette; 188 RGBQUAD OrigPalette[RTL_NUMBER_OF(MainPalette)]; 189 190 /* If requested, remove the palette from the image */ 191 if (NoPalette) 192 { 193 /* Get bitmap header and palette */ 194 PBITMAPINFOHEADER BitmapInfoHeader = Image; 195 Palette = (LPRGBQUAD)((PUCHAR)Image + BitmapInfoHeader->biSize); 196 197 /* Save the image original palette and remove palette information */ 198 RtlCopyMemory(OrigPalette, Palette, sizeof(OrigPalette)); 199 RtlZeroMemory(Palette, sizeof(OrigPalette)); 200 } 201 202 /* Draw the image */ 203 InbvBitBlt(Image, X, Y); 204 205 /* Restore the image original palette */ 206 if (NoPalette) 207 { 208 RtlCopyMemory(Palette, OrigPalette, sizeof(OrigPalette)); 209 } 210 } 211 212 static VOID 213 BitBltAligned( 214 IN PVOID Image, 215 IN BOOLEAN NoPalette, 216 IN BBLT_HORZ_ALIGNMENT HorizontalAlignment, 217 IN BBLT_VERT_ALIGNMENT VerticalAlignment, 218 IN ULONG MarginLeft, 219 IN ULONG MarginTop, 220 IN ULONG MarginRight, 221 IN ULONG MarginBottom) 222 { 223 PBITMAPINFOHEADER BitmapInfoHeader = Image; 224 ULONG X, Y; 225 226 /* Calculate X */ 227 switch (HorizontalAlignment) 228 { 229 case AL_HORIZONTAL_LEFT: 230 X = MarginLeft - MarginRight; 231 break; 232 233 case AL_HORIZONTAL_CENTER: 234 X = MarginLeft - MarginRight + (SCREEN_WIDTH - BitmapInfoHeader->biWidth + 1) / 2; 235 break; 236 237 case AL_HORIZONTAL_RIGHT: 238 X = MarginLeft - MarginRight + SCREEN_WIDTH - BitmapInfoHeader->biWidth; 239 break; 240 241 default: 242 /* Unknown */ 243 return; 244 } 245 246 /* Calculate Y */ 247 switch (VerticalAlignment) 248 { 249 case AL_VERTICAL_TOP: 250 Y = MarginTop - MarginBottom; 251 break; 252 253 case AL_VERTICAL_CENTER: 254 Y = MarginTop - MarginBottom + (SCREEN_HEIGHT - BitmapInfoHeader->biHeight + 1) / 2; 255 break; 256 257 case AL_VERTICAL_BOTTOM: 258 Y = MarginTop - MarginBottom + SCREEN_HEIGHT - BitmapInfoHeader->biHeight; 259 break; 260 261 default: 262 /* Unknown */ 263 return; 264 } 265 266 /* Finally draw the image */ 267 BitBltPalette(Image, NoPalette, X, Y); 268 } 269 270 /* FUNCTIONS *****************************************************************/ 271 272 CODE_SEG("INIT") 273 BOOLEAN 274 NTAPI 275 BootAnimInitialize( 276 _In_ PLOADER_PARAMETER_BLOCK LoaderBlock, 277 _In_ ULONG Count) 278 { 279 #if 0 280 ULONG i; 281 282 /* Quit if we're already installed */ 283 if (InbvBootDriverInstalled) return TRUE; 284 285 /* Find bitmap resources in the kernel */ 286 ResourceCount = min(Count, RTL_NUMBER_OF(ResourceList) - 1); 287 for (i = 1; i <= ResourceCount; i++) 288 { 289 /* Do the lookup */ 290 ResourceList[i] = FindBitmapResource(LoaderBlock, i); 291 } 292 293 /* Set the progress bar ranges */ 294 InbvSetProgressBarSubset(0, 100); 295 #endif 296 297 /* Return install state */ 298 return TRUE; 299 } 300 301 /** 302 * @brief 303 * Ticks the progress bar. Used by InbvUpdateProgressBar() and related. 304 * 305 * @param[in] SubPercentTimes100 306 * The progress percentage, scaled up by 100. 307 * 308 * @return None. 309 **/ 310 VOID 311 NTAPI 312 BootAnimTickProgressBar( 313 _In_ ULONG SubPercentTimes100) 314 { 315 ULONG FillCount; 316 317 /* Make sure the progress bar is enabled, that we own and are installed */ 318 ASSERT(ShowProgressBar && 319 InbvBootDriverInstalled && 320 (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED)); 321 322 /* Compute fill count */ 323 FillCount = VID_PROGRESS_BAR_WIDTH * SubPercentTimes100 / (100 * 100); 324 325 /* Acquire the lock */ 326 InbvAcquireLock(); 327 328 /* Fill the progress bar */ 329 VidSolidColorFill(ProgressBarLeft, 330 ProgressBarTop, 331 ProgressBarLeft + FillCount, 332 ProgressBarTop + VID_PROGRESS_BAR_HEIGHT, 333 BV_COLOR_WHITE); 334 335 /* Release the lock */ 336 InbvReleaseLock(); 337 } 338 339 #ifdef INBV_ROTBAR_IMPLEMENTED 340 static 341 VOID 342 NTAPI 343 InbvRotationThread( 344 _In_ PVOID Context) 345 { 346 ULONG X, Y, Index, Total; 347 LARGE_INTEGER Delay = {{0}}; 348 349 InbvAcquireLock(); 350 if (RotBarSelection == RB_SQUARE_CELLS) 351 { 352 Index = 0; 353 } 354 else 355 { 356 Index = 32; 357 } 358 X = ProgressBarLeft + 2; 359 Y = ProgressBarTop + 2; 360 InbvReleaseLock(); 361 362 while (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED) 363 { 364 /* Wait for a bit */ 365 KeDelayExecutionThread(KernelMode, FALSE, &Delay); 366 367 InbvAcquireLock(); 368 369 /* Unknown unexpected command */ 370 ASSERT(PltRotBarStatus < RBS_STATUS_MAX); 371 372 if (PltRotBarStatus == RBS_STOP_ANIMATE) 373 { 374 /* Stop the thread */ 375 InbvReleaseLock(); 376 break; 377 } 378 379 if (RotBarSelection == RB_SQUARE_CELLS) 380 { 381 Delay.QuadPart = -800000; // 80 ms 382 Total = 18; 383 Index %= Total; 384 385 if (Index >= 3) 386 { 387 /* Fill previous bar position */ 388 VidSolidColorFill(X + ((Index - 3) * 8), Y, (X + ((Index - 3) * 8)) + 8 - 1, Y + 9 - 1, BV_COLOR_BLACK); 389 } 390 if (Index < Total - 1) 391 { 392 /* Draw the progress bar bit */ 393 if (Index < 2) 394 { 395 /* Appearing from the left */ 396 VidBufferToScreenBlt(RotBarBuffer + 8 * (2 - Index) / 2, X, Y, 22 - 8 * (2 - Index), 9, 24); 397 } 398 else if (Index >= Total - 3) 399 { 400 /* Hiding to the right */ 401 VidBufferToScreenBlt(RotBarBuffer, X + ((Index - 2) * 8), Y, 22 - 8 * (4 - (Total - Index)), 9, 24); 402 } 403 else 404 { 405 VidBufferToScreenBlt(RotBarBuffer, X + ((Index - 2) * 8), Y, 22, 9, 24); 406 } 407 } 408 Index++; 409 } 410 else if (RotBarSelection == RB_PROGRESS_BAR) 411 { 412 Delay.QuadPart = -600000; // 60 ms 413 Total = SCREEN_WIDTH; 414 Index %= Total; 415 416 /* Right part */ 417 VidBufferToScreenBlt(RotLineBuffer, Index, SCREEN_HEIGHT-6, SCREEN_WIDTH - Index, 6, SCREEN_WIDTH); 418 if (Index > 0) 419 { 420 /* Left part */ 421 VidBufferToScreenBlt(RotLineBuffer + (SCREEN_WIDTH - Index) / 2, 0, SCREEN_HEIGHT-6, Index - 2, 6, SCREEN_WIDTH); 422 } 423 Index += 32; 424 } 425 426 InbvReleaseLock(); 427 } 428 429 PsTerminateSystemThread(STATUS_SUCCESS); 430 } 431 432 CODE_SEG("INIT") 433 VOID 434 NTAPI 435 InbvRotBarInit(VOID) 436 { 437 PltRotBarStatus = RBS_FADEIN; 438 /* Perform other initialization if needed */ 439 } 440 #endif 441 442 CODE_SEG("INIT") 443 static 444 VOID 445 NTAPI 446 DisplayFilter( 447 _Inout_ PCHAR* String) 448 { 449 /* Windows hack to skip first dots displayed by AUTOCHK */ 450 static BOOLEAN DotHack = TRUE; 451 452 /* If "." is given set *String to empty string */ 453 if (DotHack && strcmp(*String, ".") == 0) 454 *String = ""; 455 456 if (**String) 457 { 458 /* Remove the filter */ 459 InbvInstallDisplayStringFilter(NULL); 460 461 DotHack = FALSE; 462 463 /* Draw text screen */ 464 DisplayBootBitmap(TRUE); 465 } 466 } 467 468 CODE_SEG("INIT") 469 VOID 470 NTAPI 471 DisplayBootBitmap( 472 _In_ BOOLEAN TextMode) 473 { 474 PVOID BootCopy = NULL, BootProgress = NULL, BootLogo = NULL, Header = NULL, Footer = NULL; 475 476 #ifdef INBV_ROTBAR_IMPLEMENTED 477 UCHAR Buffer[24 * 9]; 478 PVOID Bar = NULL, LineBmp = NULL; 479 ROT_BAR_TYPE TempRotBarSelection = RB_UNSPECIFIED; 480 NTSTATUS Status; 481 HANDLE ThreadHandle = NULL; 482 #endif 483 484 #ifdef REACTOS_SKUS 485 PVOID Text = NULL; 486 #endif 487 488 #ifdef INBV_ROTBAR_IMPLEMENTED 489 /* Check if the animation thread has already been created */ 490 if (RotBarThreadActive) 491 { 492 /* Yes, just reset the progress bar but keep the thread alive */ 493 InbvAcquireLock(); 494 RotBarSelection = RB_UNSPECIFIED; 495 InbvReleaseLock(); 496 } 497 #endif 498 499 ShowProgressBar = FALSE; 500 501 /* Check if this is text mode */ 502 if (TextMode) 503 { 504 /* 505 * Make the kernel resource section temporarily writable, 506 * as we are going to change the bitmaps' palette in place. 507 */ 508 MmChangeKernelResourceSectionProtection(MM_READWRITE); 509 510 /* Check the type of the OS: workstation or server */ 511 if (SharedUserData->NtProductType == NtProductWinNt) 512 { 513 /* Workstation; set colors */ 514 InbvSetTextColor(BV_COLOR_WHITE); 515 InbvSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_DARK_GRAY); 516 InbvSolidColorFill(0, VID_FOOTER_BG_TOP, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_RED); 517 518 /* Get resources */ 519 Header = InbvGetResourceAddress(IDB_WKSTA_HEADER); 520 Footer = InbvGetResourceAddress(IDB_WKSTA_FOOTER); 521 } 522 else 523 { 524 /* Server; set colors */ 525 InbvSetTextColor(BV_COLOR_LIGHT_CYAN); 526 InbvSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_CYAN); 527 InbvSolidColorFill(0, VID_FOOTER_BG_TOP, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_RED); 528 529 /* Get resources */ 530 Header = InbvGetResourceAddress(IDB_SERVER_HEADER); 531 Footer = InbvGetResourceAddress(IDB_SERVER_FOOTER); 532 } 533 534 /* Set the scrolling region */ 535 InbvSetScrollRegion(VID_SCROLL_AREA_LEFT, VID_SCROLL_AREA_TOP, 536 VID_SCROLL_AREA_RIGHT, VID_SCROLL_AREA_BOTTOM); 537 538 /* Make sure we have resources */ 539 if (Header && Footer) 540 { 541 /* BitBlt them on the screen */ 542 BitBltAligned(Footer, 543 TRUE, 544 AL_HORIZONTAL_CENTER, 545 AL_VERTICAL_BOTTOM, 546 0, 0, 0, 59); 547 BitBltAligned(Header, 548 FALSE, 549 AL_HORIZONTAL_CENTER, 550 AL_VERTICAL_TOP, 551 0, 0, 0, 0); 552 } 553 554 /* Restore the kernel resource section protection to be read-only */ 555 MmChangeKernelResourceSectionProtection(MM_READONLY); 556 } 557 else 558 { 559 /* Is the boot driver installed? */ 560 if (!InbvBootDriverInstalled) return; 561 562 /* 563 * Make the kernel resource section temporarily writable, 564 * as we are going to change the bitmaps' palette in place. 565 */ 566 MmChangeKernelResourceSectionProtection(MM_READWRITE); 567 568 /* Load boot screen logo */ 569 BootLogo = InbvGetResourceAddress(IDB_LOGO_DEFAULT); 570 571 #ifdef REACTOS_SKUS 572 Text = NULL; 573 if (SharedUserData->NtProductType == NtProductWinNt) 574 { 575 #ifdef INBV_ROTBAR_IMPLEMENTED 576 /* Workstation product, use appropriate status bar color */ 577 Bar = InbvGetResourceAddress(IDB_BAR_WKSTA); 578 #endif 579 } 580 else 581 { 582 /* Display correct branding based on server suite */ 583 if (ExVerifySuite(StorageServer)) 584 { 585 /* Storage Server Edition */ 586 Text = InbvGetResourceAddress(IDB_STORAGE_SERVER); 587 } 588 else if (ExVerifySuite(ComputeServer)) 589 { 590 /* Compute Cluster Edition */ 591 Text = InbvGetResourceAddress(IDB_CLUSTER_SERVER); 592 } 593 else 594 { 595 /* Normal edition */ 596 Text = InbvGetResourceAddress(IDB_SERVER_LOGO); 597 } 598 599 #ifdef INBV_ROTBAR_IMPLEMENTED 600 /* Server product, use appropriate status bar color */ 601 Bar = InbvGetResourceAddress(IDB_BAR_DEFAULT); 602 #endif 603 } 604 #else 605 /* Use default status bar */ 606 Bar = InbvGetResourceAddress(IDB_BAR_WKSTA); 607 #endif 608 609 /* Make sure we have a logo */ 610 if (BootLogo) 611 { 612 /* Save the main image palette for implementing the fade-in effect */ 613 PBITMAPINFOHEADER BitmapInfoHeader = BootLogo; 614 LPRGBQUAD Palette = (LPRGBQUAD)((PUCHAR)BootLogo + BitmapInfoHeader->biSize); 615 RtlCopyMemory(MainPalette, Palette, sizeof(MainPalette)); 616 617 /* Draw the logo at the center of the screen */ 618 BitBltAligned(BootLogo, 619 TRUE, 620 AL_HORIZONTAL_CENTER, 621 AL_VERTICAL_CENTER, 622 0, 0, 0, 34); 623 624 #ifdef INBV_ROTBAR_IMPLEMENTED 625 /* Choose progress bar */ 626 TempRotBarSelection = ROT_BAR_DEFAULT_MODE; 627 #endif 628 629 /* Set progress bar coordinates and display it */ 630 InbvSetProgressBarCoordinates(VID_PROGRESS_BAR_LEFT, 631 VID_PROGRESS_BAR_TOP); 632 633 #ifdef REACTOS_SKUS 634 /* Check for non-workstation products */ 635 if (SharedUserData->NtProductType != NtProductWinNt) 636 { 637 /* Overwrite part of the logo for a server product */ 638 InbvScreenToBufferBlt(Buffer, VID_SKU_SAVE_AREA_LEFT, 639 VID_SKU_SAVE_AREA_TOP, 7, 7, 8); 640 InbvSolidColorFill(VID_SKU_AREA_LEFT, VID_SKU_AREA_TOP, 641 VID_SKU_AREA_RIGHT, VID_SKU_AREA_BOTTOM, BV_COLOR_BLACK); 642 InbvBufferToScreenBlt(Buffer, VID_SKU_SAVE_AREA_LEFT, 643 VID_SKU_SAVE_AREA_TOP, 7, 7, 8); 644 645 /* In setup mode, you haven't selected a SKU yet */ 646 if (ExpInTextModeSetup) Text = NULL; 647 } 648 #endif 649 } 650 651 /* Load and draw progress bar bitmap */ 652 BootProgress = InbvGetResourceAddress(IDB_PROGRESS_BAR); 653 BitBltAligned(BootProgress, 654 TRUE, 655 AL_HORIZONTAL_CENTER, 656 AL_VERTICAL_CENTER, 657 0, 118, 0, 0); 658 659 /* Load and draw copyright text bitmap */ 660 BootCopy = InbvGetResourceAddress(IDB_COPYRIGHT); 661 BitBltAligned(BootCopy, 662 TRUE, 663 AL_HORIZONTAL_LEFT, 664 AL_VERTICAL_BOTTOM, 665 22, 0, 0, 20); 666 667 #ifdef REACTOS_SKUS 668 /* Draw the SKU text if it exits */ 669 if (Text) 670 BitBltPalette(Text, TRUE, VID_SKU_TEXT_LEFT, VID_SKU_TEXT_TOP); 671 #endif 672 673 #ifdef INBV_ROTBAR_IMPLEMENTED 674 if ((TempRotBarSelection == RB_SQUARE_CELLS) && Bar) 675 { 676 /* Save previous screen pixels to buffer */ 677 InbvScreenToBufferBlt(Buffer, 0, 0, 22, 9, 24); 678 /* Draw the progress bar bit */ 679 BitBltPalette(Bar, TRUE, 0, 0); 680 /* Store it in global buffer */ 681 InbvScreenToBufferBlt(RotBarBuffer, 0, 0, 22, 9, 24); 682 /* Restore screen pixels */ 683 InbvBufferToScreenBlt(Buffer, 0, 0, 22, 9, 24); 684 } 685 686 /* 687 * Add a rotating bottom horizontal bar when using a progress bar, 688 * to show that ReactOS can be still alive when the bar does not 689 * appear to progress. 690 */ 691 if (TempRotBarSelection == RB_PROGRESS_BAR) 692 { 693 LineBmp = InbvGetResourceAddress(IDB_ROTATING_LINE); 694 if (LineBmp) 695 { 696 /* Draw the line and store it in global buffer */ 697 BitBltPalette(LineBmp, TRUE, 0, SCREEN_HEIGHT-6); 698 InbvScreenToBufferBlt(RotLineBuffer, 0, SCREEN_HEIGHT-6, SCREEN_WIDTH, 6, SCREEN_WIDTH); 699 } 700 } 701 else 702 { 703 /* Hide the simple progress bar if not used */ 704 ShowProgressBar = FALSE; 705 } 706 #endif 707 708 /* Restore the kernel resource section protection to be read-only */ 709 MmChangeKernelResourceSectionProtection(MM_READONLY); 710 711 /* Display the boot logo and fade it in */ 712 BootLogoFadeIn(); 713 714 #ifdef INBV_ROTBAR_IMPLEMENTED 715 if (!RotBarThreadActive && TempRotBarSelection != RB_UNSPECIFIED) 716 { 717 /* Start the animation thread */ 718 Status = PsCreateSystemThread(&ThreadHandle, 719 0, 720 NULL, 721 NULL, 722 NULL, 723 InbvRotationThread, 724 NULL); 725 if (NT_SUCCESS(Status)) 726 { 727 /* The thread has started, close the handle as we don't need it */ 728 RotBarThreadActive = TRUE; 729 ObCloseHandle(ThreadHandle, KernelMode); 730 } 731 } 732 #endif 733 734 /* Set filter which will draw text display if needed */ 735 InbvInstallDisplayStringFilter(DisplayFilter); 736 } 737 738 #ifdef INBV_ROTBAR_IMPLEMENTED 739 /* Do we have the animation thread? */ 740 if (RotBarThreadActive) 741 { 742 /* We do, initialize the progress bar */ 743 InbvAcquireLock(); 744 RotBarSelection = TempRotBarSelection; 745 InbvRotBarInit(); 746 InbvReleaseLock(); 747 } 748 #endif 749 } 750 751 CODE_SEG("INIT") 752 VOID 753 NTAPI 754 FinalizeBootLogo(VOID) 755 { 756 /* Acquire lock and check the display state */ 757 InbvAcquireLock(); 758 if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED) 759 { 760 /* Clear the screen */ 761 VidSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_BLACK); 762 } 763 764 /* Reset progress bar and lock */ 765 #ifdef INBV_ROTBAR_IMPLEMENTED 766 PltRotBarStatus = RBS_STOP_ANIMATE; 767 RotBarThreadActive = FALSE; 768 #endif 769 InbvReleaseLock(); 770 } 771