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 /* 32 * Enable this define for having fancy features 33 * in the boot and shutdown screens. 34 */ 35 // #define REACTOS_FANCY_BOOT 36 37 /* 38 * BitBltAligned() alignments 39 */ 40 typedef enum _BBLT_VERT_ALIGNMENT 41 { 42 AL_VERTICAL_TOP = 0, 43 AL_VERTICAL_CENTER, 44 AL_VERTICAL_BOTTOM 45 } BBLT_VERT_ALIGNMENT; 46 47 typedef enum _BBLT_HORZ_ALIGNMENT 48 { 49 AL_HORIZONTAL_LEFT = 0, 50 AL_HORIZONTAL_CENTER, 51 AL_HORIZONTAL_RIGHT 52 } BBLT_HORZ_ALIGNMENT; 53 54 /* 55 * Enable this define when Inbv will support rotating progress bar. 56 */ 57 #define INBV_ROTBAR_IMPLEMENTED 58 59 extern ULONG ProgressBarLeft, ProgressBarTop; 60 extern BOOLEAN ShowProgressBar; 61 62 #ifdef INBV_ROTBAR_IMPLEMENTED 63 /* 64 * Change this to modify progress bar behaviour 65 */ 66 #define ROT_BAR_DEFAULT_MODE RB_PROGRESS_BAR 67 68 /* 69 * Values for PltRotBarStatus: 70 * - PltRotBarStatus == 1, do palette fading-in (done elsewhere in ReactOS); 71 * - PltRotBarStatus == 2, do rotation bar animation; 72 * - PltRotBarStatus == 3, stop the animation thread. 73 * - Any other value is ignored and the animation thread continues to run. 74 */ 75 typedef enum _ROT_BAR_STATUS 76 { 77 RBS_FADEIN = 1, 78 RBS_ANIMATE, 79 RBS_STOP_ANIMATE, 80 RBS_STATUS_MAX 81 } ROT_BAR_STATUS; 82 83 typedef enum _ROT_BAR_TYPE 84 { 85 RB_UNSPECIFIED, 86 RB_SQUARE_CELLS, 87 RB_PROGRESS_BAR 88 } ROT_BAR_TYPE; 89 90 static BOOLEAN RotBarThreadActive = FALSE; 91 static ROT_BAR_TYPE RotBarSelection = RB_UNSPECIFIED; 92 static ROT_BAR_STATUS PltRotBarStatus = 0; 93 static UCHAR RotBarBuffer[24 * 9]; 94 static UCHAR RotLineBuffer[SCREEN_WIDTH * 6]; 95 #endif // INBV_ROTBAR_IMPLEMENTED 96 97 98 /* FADE-IN FUNCTION **********************************************************/ 99 100 /** From include/psdk/wingdi.h and bootvid/precomp.h **/ 101 typedef struct tagRGBQUAD 102 { 103 UCHAR rgbBlue; 104 UCHAR rgbGreen; 105 UCHAR rgbRed; 106 UCHAR rgbReserved; 107 } RGBQUAD, *LPRGBQUAD; 108 109 // 110 // Bitmap Header 111 // 112 typedef struct tagBITMAPINFOHEADER 113 { 114 ULONG biSize; 115 LONG biWidth; 116 LONG biHeight; 117 USHORT biPlanes; 118 USHORT biBitCount; 119 ULONG biCompression; 120 ULONG biSizeImage; 121 LONG biXPelsPerMeter; 122 LONG biYPelsPerMeter; 123 ULONG biClrUsed; 124 ULONG biClrImportant; 125 } BITMAPINFOHEADER, *PBITMAPINFOHEADER; 126 /*******************************/ 127 128 static RGBQUAD MainPalette[16]; 129 130 #define PALETTE_FADE_STEPS 12 131 #define PALETTE_FADE_TIME (15 * 1000) /* 15 ms */ 132 133 static VOID 134 BootLogoFadeIn(VOID) 135 { 136 UCHAR PaletteBitmapBuffer[sizeof(BITMAPINFOHEADER) + sizeof(MainPalette)]; 137 PBITMAPINFOHEADER PaletteBitmap = (PBITMAPINFOHEADER)PaletteBitmapBuffer; 138 LPRGBQUAD Palette = (LPRGBQUAD)(PaletteBitmapBuffer + sizeof(BITMAPINFOHEADER)); 139 ULONG Iteration, Index, ClrUsed; 140 141 LARGE_INTEGER Delay; 142 Delay.QuadPart = -(PALETTE_FADE_TIME * 10); 143 144 /* Check if we are installed and we own the display */ 145 if (!InbvBootDriverInstalled || 146 (InbvGetDisplayState() != INBV_DISPLAY_STATE_OWNED)) 147 { 148 return; 149 } 150 151 /* 152 * Build a bitmap containing the fade-in palette. The palette entries 153 * are then processed in a loop and set using VidBitBlt function. 154 */ 155 ClrUsed = RTL_NUMBER_OF(MainPalette); 156 RtlZeroMemory(PaletteBitmap, sizeof(BITMAPINFOHEADER)); 157 PaletteBitmap->biSize = sizeof(BITMAPINFOHEADER); 158 PaletteBitmap->biBitCount = 4; 159 PaletteBitmap->biClrUsed = ClrUsed; 160 161 /* 162 * Main animation loop. 163 */ 164 for (Iteration = 0; Iteration <= PALETTE_FADE_STEPS; ++Iteration) 165 { 166 for (Index = 0; Index < ClrUsed; Index++) 167 { 168 Palette[Index].rgbRed = (UCHAR) 169 (MainPalette[Index].rgbRed * Iteration / PALETTE_FADE_STEPS); 170 Palette[Index].rgbGreen = (UCHAR) 171 (MainPalette[Index].rgbGreen * Iteration / PALETTE_FADE_STEPS); 172 Palette[Index].rgbBlue = (UCHAR) 173 (MainPalette[Index].rgbBlue * Iteration / PALETTE_FADE_STEPS); 174 } 175 176 /* Do the animation */ 177 InbvAcquireLock(); 178 VidBitBlt(PaletteBitmapBuffer, 0, 0); 179 InbvReleaseLock(); 180 181 /* Wait for a bit */ 182 KeDelayExecutionThread(KernelMode, FALSE, &Delay); 183 } 184 } 185 186 static VOID 187 BitBltPalette( 188 IN PVOID Image, 189 IN BOOLEAN NoPalette, 190 IN ULONG X, 191 IN ULONG Y) 192 { 193 LPRGBQUAD Palette; 194 RGBQUAD OrigPalette[RTL_NUMBER_OF(MainPalette)]; 195 196 /* If requested, remove the palette from the image */ 197 if (NoPalette) 198 { 199 /* Get bitmap header and palette */ 200 PBITMAPINFOHEADER BitmapInfoHeader = Image; 201 Palette = (LPRGBQUAD)((PUCHAR)Image + BitmapInfoHeader->biSize); 202 203 /* Save the image original palette and remove palette information */ 204 RtlCopyMemory(OrigPalette, Palette, sizeof(OrigPalette)); 205 RtlZeroMemory(Palette, sizeof(OrigPalette)); 206 } 207 208 /* Draw the image */ 209 InbvBitBlt(Image, X, Y); 210 211 /* Restore the image original palette */ 212 if (NoPalette) 213 { 214 RtlCopyMemory(Palette, OrigPalette, sizeof(OrigPalette)); 215 } 216 } 217 218 static VOID 219 BitBltAligned( 220 IN PVOID Image, 221 IN BOOLEAN NoPalette, 222 IN BBLT_HORZ_ALIGNMENT HorizontalAlignment, 223 IN BBLT_VERT_ALIGNMENT VerticalAlignment, 224 IN ULONG MarginLeft, 225 IN ULONG MarginTop, 226 IN ULONG MarginRight, 227 IN ULONG MarginBottom) 228 { 229 PBITMAPINFOHEADER BitmapInfoHeader = Image; 230 ULONG X, Y; 231 232 /* Calculate X */ 233 switch (HorizontalAlignment) 234 { 235 case AL_HORIZONTAL_LEFT: 236 X = MarginLeft - MarginRight; 237 break; 238 239 case AL_HORIZONTAL_CENTER: 240 X = MarginLeft - MarginRight + (SCREEN_WIDTH - BitmapInfoHeader->biWidth + 1) / 2; 241 break; 242 243 case AL_HORIZONTAL_RIGHT: 244 X = MarginLeft - MarginRight + SCREEN_WIDTH - BitmapInfoHeader->biWidth; 245 break; 246 247 default: 248 /* Unknown */ 249 return; 250 } 251 252 /* Calculate Y */ 253 switch (VerticalAlignment) 254 { 255 case AL_VERTICAL_TOP: 256 Y = MarginTop - MarginBottom; 257 break; 258 259 case AL_VERTICAL_CENTER: 260 Y = MarginTop - MarginBottom + (SCREEN_HEIGHT - BitmapInfoHeader->biHeight + 1) / 2; 261 break; 262 263 case AL_VERTICAL_BOTTOM: 264 Y = MarginTop - MarginBottom + SCREEN_HEIGHT - BitmapInfoHeader->biHeight; 265 break; 266 267 default: 268 /* Unknown */ 269 return; 270 } 271 272 /* Finally draw the image */ 273 BitBltPalette(Image, NoPalette, X, Y); 274 } 275 276 /* FUNCTIONS *****************************************************************/ 277 278 CODE_SEG("INIT") 279 BOOLEAN 280 NTAPI 281 BootAnimInitialize( 282 _In_ PLOADER_PARAMETER_BLOCK LoaderBlock, 283 _In_ ULONG Count) 284 { 285 #if 0 286 ULONG i; 287 288 /* Quit if we're already installed */ 289 if (InbvBootDriverInstalled) return TRUE; 290 291 /* Find bitmap resources in the kernel */ 292 ResourceCount = min(Count, RTL_NUMBER_OF(ResourceList) - 1); 293 for (i = 1; i <= ResourceCount; i++) 294 { 295 /* Do the lookup */ 296 ResourceList[i] = FindBitmapResource(LoaderBlock, i); 297 } 298 299 /* Set the progress bar ranges */ 300 InbvSetProgressBarSubset(0, 100); 301 #endif 302 303 /* Return install state */ 304 return TRUE; 305 } 306 307 /** 308 * @brief 309 * Ticks the progress bar. Used by InbvUpdateProgressBar() and related. 310 * 311 * @param[in] SubPercentTimes100 312 * The progress percentage, scaled up by 100. 313 * 314 * @return None. 315 **/ 316 VOID 317 NTAPI 318 BootAnimTickProgressBar( 319 _In_ ULONG SubPercentTimes100) 320 { 321 ULONG FillCount; 322 323 /* Make sure the progress bar is enabled, that we own and are installed */ 324 ASSERT(ShowProgressBar && 325 InbvBootDriverInstalled && 326 (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED)); 327 328 /* Compute fill count */ 329 FillCount = VID_PROGRESS_BAR_WIDTH * SubPercentTimes100 / (100 * 100); 330 331 /* Acquire the lock */ 332 InbvAcquireLock(); 333 334 /* Fill the progress bar */ 335 VidSolidColorFill(ProgressBarLeft, 336 ProgressBarTop, 337 ProgressBarLeft + FillCount, 338 ProgressBarTop + VID_PROGRESS_BAR_HEIGHT, 339 BV_COLOR_WHITE); 340 341 /* Release the lock */ 342 InbvReleaseLock(); 343 } 344 345 #ifdef INBV_ROTBAR_IMPLEMENTED 346 static 347 VOID 348 NTAPI 349 InbvRotationThread( 350 _In_ PVOID Context) 351 { 352 ULONG X, Y, Index, Total; 353 LARGE_INTEGER Delay = {{0}}; 354 355 UNREFERENCED_PARAMETER(Context); 356 357 InbvAcquireLock(); 358 if (RotBarSelection == RB_SQUARE_CELLS) 359 { 360 Index = 0; 361 } 362 else 363 { 364 Index = 32; 365 } 366 X = ProgressBarLeft + 2; 367 Y = ProgressBarTop + 2; 368 InbvReleaseLock(); 369 370 while (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED) 371 { 372 /* Wait for a bit */ 373 KeDelayExecutionThread(KernelMode, FALSE, &Delay); 374 375 InbvAcquireLock(); 376 377 /* Unknown unexpected command */ 378 ASSERT(PltRotBarStatus < RBS_STATUS_MAX); 379 380 if (PltRotBarStatus == RBS_STOP_ANIMATE) 381 { 382 /* Stop the thread */ 383 InbvReleaseLock(); 384 break; 385 } 386 387 if (RotBarSelection == RB_SQUARE_CELLS) 388 { 389 Delay.QuadPart = -800000LL; // 80 ms 390 Total = 18; 391 Index %= Total; 392 393 if (Index >= 3) 394 { 395 /* Fill previous bar position */ 396 VidSolidColorFill(X + ((Index - 3) * 8), Y, (X + ((Index - 3) * 8)) + 8 - 1, Y + 9 - 1, BV_COLOR_BLACK); 397 } 398 if (Index < Total - 1) 399 { 400 /* Draw the progress bar bit */ 401 if (Index < 2) 402 { 403 /* Appearing from the left */ 404 VidBufferToScreenBlt(RotBarBuffer + 8 * (2 - Index) / 2, X, Y, 22 - 8 * (2 - Index), 9, 24); 405 } 406 else if (Index >= Total - 3) 407 { 408 /* Hiding to the right */ 409 VidBufferToScreenBlt(RotBarBuffer, X + ((Index - 2) * 8), Y, 22 - 8 * (4 - (Total - Index)), 9, 24); 410 } 411 else 412 { 413 VidBufferToScreenBlt(RotBarBuffer, X + ((Index - 2) * 8), Y, 22, 9, 24); 414 } 415 } 416 Index++; 417 } 418 else if (RotBarSelection == RB_PROGRESS_BAR) 419 { 420 Delay.QuadPart = -600000LL; // 60 ms 421 Total = SCREEN_WIDTH; 422 Index %= Total; 423 424 /* Right part */ 425 VidBufferToScreenBlt(RotLineBuffer, Index, SCREEN_HEIGHT-6, SCREEN_WIDTH - Index, 6, SCREEN_WIDTH); 426 if (Index > 0) 427 { 428 /* Left part */ 429 VidBufferToScreenBlt(RotLineBuffer + (SCREEN_WIDTH - Index) / 2, 0, SCREEN_HEIGHT-6, Index - 2, 6, SCREEN_WIDTH); 430 } 431 Index += 32; 432 } 433 434 InbvReleaseLock(); 435 } 436 437 PsTerminateSystemThread(STATUS_SUCCESS); 438 } 439 440 CODE_SEG("INIT") 441 VOID 442 NTAPI 443 InbvRotBarInit(VOID) 444 { 445 PltRotBarStatus = RBS_FADEIN; 446 /* Perform other initialization if needed */ 447 } 448 #endif // INBV_ROTBAR_IMPLEMENTED 449 450 CODE_SEG("INIT") 451 static 452 VOID 453 NTAPI 454 DisplayFilter( 455 _Inout_ PCHAR* String) 456 { 457 /* Windows hack to skip first dots displayed by AUTOCHK */ 458 static BOOLEAN DotHack = TRUE; 459 460 /* If "." is given set *String to empty string */ 461 if (DotHack && strcmp(*String, ".") == 0) 462 *String = ""; 463 464 if (**String) 465 { 466 /* Remove the filter */ 467 InbvInstallDisplayStringFilter(NULL); 468 469 DotHack = FALSE; 470 471 /* Draw text screen */ 472 DisplayBootBitmap(TRUE); 473 } 474 } 475 476 #ifdef REACTOS_FANCY_BOOT 477 478 /* Returns TRUE if this is Christmas time, or FALSE if not */ 479 static BOOLEAN 480 IsXmasTime(VOID) 481 { 482 LARGE_INTEGER SystemTime; 483 TIME_FIELDS Time; 484 485 /* Use KeBootTime if it's initialized, otherwise call the HAL */ 486 SystemTime = KeBootTime; 487 if ((SystemTime.QuadPart == 0) && HalQueryRealTimeClock(&Time)) 488 RtlTimeFieldsToTime(&Time, &SystemTime); 489 490 ExSystemTimeToLocalTime(&SystemTime, &SystemTime); 491 RtlTimeToTimeFields(&SystemTime, &Time); 492 return ((Time.Month == 12) && (20 <= Time.Day) && (Time.Day <= 31)); 493 } 494 495 #define SELECT_LOGO_ID(LogoIdDefault, Cond, LogoIdAlt) \ 496 ((Cond) ? (LogoIdAlt) : (LogoIdDefault)) 497 498 #else 499 500 #define SELECT_LOGO_ID(LogoIdDefault, Cond, LogoIdAlt) (LogoIdDefault) 501 502 #endif // REACTOS_FANCY_BOOT 503 504 CODE_SEG("INIT") 505 VOID 506 NTAPI 507 DisplayBootBitmap( 508 _In_ BOOLEAN TextMode) 509 { 510 PVOID BootCopy = NULL, BootProgress = NULL, BootLogo = NULL, Header = NULL, Footer = NULL; 511 512 #ifdef INBV_ROTBAR_IMPLEMENTED 513 UCHAR Buffer[RTL_NUMBER_OF(RotBarBuffer)]; 514 PVOID Bar = NULL, LineBmp = NULL; 515 ROT_BAR_TYPE TempRotBarSelection = RB_UNSPECIFIED; 516 NTSTATUS Status; 517 HANDLE ThreadHandle = NULL; 518 #endif 519 520 #ifdef REACTOS_SKUS 521 PVOID Text = NULL; 522 #endif 523 524 #ifdef INBV_ROTBAR_IMPLEMENTED 525 /* Check if the animation thread has already been created */ 526 if (RotBarThreadActive) 527 { 528 /* Yes, just reset the progress bar but keep the thread alive */ 529 InbvAcquireLock(); 530 RotBarSelection = RB_UNSPECIFIED; 531 InbvReleaseLock(); 532 } 533 #endif 534 535 ShowProgressBar = FALSE; 536 537 /* Check if this is text mode */ 538 if (TextMode) 539 { 540 /* 541 * Make the kernel resource section temporarily writable, 542 * as we are going to change the bitmaps' palette in place. 543 */ 544 MmChangeKernelResourceSectionProtection(MM_READWRITE); 545 546 /* Check the type of the OS: workstation or server */ 547 if (SharedUserData->NtProductType == NtProductWinNt) 548 { 549 /* Workstation; set colors */ 550 InbvSetTextColor(BV_COLOR_WHITE); 551 InbvSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_DARK_GRAY); 552 InbvSolidColorFill(0, VID_FOOTER_BG_TOP, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_RED); 553 554 /* Get resources */ 555 Header = InbvGetResourceAddress(IDB_WKSTA_HEADER); 556 Footer = InbvGetResourceAddress(IDB_WKSTA_FOOTER); 557 } 558 else 559 { 560 /* Server; set colors */ 561 InbvSetTextColor(BV_COLOR_LIGHT_CYAN); 562 InbvSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_CYAN); 563 InbvSolidColorFill(0, VID_FOOTER_BG_TOP, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_RED); 564 565 /* Get resources */ 566 Header = InbvGetResourceAddress(IDB_SERVER_HEADER); 567 Footer = InbvGetResourceAddress(IDB_SERVER_FOOTER); 568 } 569 570 /* Set the scrolling region */ 571 InbvSetScrollRegion(VID_SCROLL_AREA_LEFT, VID_SCROLL_AREA_TOP, 572 VID_SCROLL_AREA_RIGHT, VID_SCROLL_AREA_BOTTOM); 573 574 /* Make sure we have resources */ 575 if (Header && Footer) 576 { 577 /* BitBlt them on the screen */ 578 BitBltAligned(Footer, 579 TRUE, 580 AL_HORIZONTAL_CENTER, 581 AL_VERTICAL_BOTTOM, 582 0, 0, 0, 59); 583 BitBltAligned(Header, 584 FALSE, 585 AL_HORIZONTAL_CENTER, 586 AL_VERTICAL_TOP, 587 0, 0, 0, 0); 588 } 589 590 /* Restore the kernel resource section protection to be read-only */ 591 MmChangeKernelResourceSectionProtection(MM_READONLY); 592 } 593 else 594 { 595 #ifdef REACTOS_FANCY_BOOT 596 /* Decide whether this is a good time to change our logo ;^) */ 597 BOOLEAN IsXmas = IsXmasTime(); 598 #endif 599 600 /* Is the boot driver installed? */ 601 if (!InbvBootDriverInstalled) return; 602 603 /* 604 * Make the kernel resource section temporarily writable, 605 * as we are going to change the bitmaps' palette in place. 606 */ 607 MmChangeKernelResourceSectionProtection(MM_READWRITE); 608 609 /* Load boot screen logo */ 610 BootLogo = InbvGetResourceAddress( 611 SELECT_LOGO_ID(IDB_LOGO_DEFAULT, IsXmas, IDB_LOGO_XMAS)); 612 613 #ifdef REACTOS_SKUS 614 Text = NULL; 615 if (SharedUserData->NtProductType == NtProductWinNt) 616 { 617 #ifdef INBV_ROTBAR_IMPLEMENTED 618 /* Workstation product, use appropriate status bar color */ 619 Bar = InbvGetResourceAddress(IDB_BAR_WKSTA); 620 #endif 621 } 622 else 623 { 624 /* Display correct branding based on server suite */ 625 if (ExVerifySuite(StorageServer)) 626 { 627 /* Storage Server Edition */ 628 Text = InbvGetResourceAddress(IDB_STORAGE_SERVER); 629 } 630 else if (ExVerifySuite(ComputeServer)) 631 { 632 /* Compute Cluster Edition */ 633 Text = InbvGetResourceAddress(IDB_CLUSTER_SERVER); 634 } 635 else 636 { 637 /* Normal edition */ 638 Text = InbvGetResourceAddress( 639 SELECT_LOGO_ID(IDB_SERVER_LOGO, IsXmas, IDB_LOGO_XMAS)); 640 } 641 642 #ifdef INBV_ROTBAR_IMPLEMENTED 643 /* Server product, use appropriate status bar color */ 644 Bar = InbvGetResourceAddress(IDB_BAR_DEFAULT); 645 #endif 646 } 647 #else // REACTOS_SKUS 648 #ifdef INBV_ROTBAR_IMPLEMENTED 649 /* Use default status bar */ 650 Bar = InbvGetResourceAddress(IDB_BAR_WKSTA); 651 #endif 652 #endif // REACTOS_SKUS 653 654 /* Make sure we have a logo */ 655 if (BootLogo) 656 { 657 /* Save the main image palette for implementing the fade-in effect */ 658 PBITMAPINFOHEADER BitmapInfoHeader = BootLogo; 659 LPRGBQUAD Palette = (LPRGBQUAD)((PUCHAR)BootLogo + BitmapInfoHeader->biSize); 660 RtlCopyMemory(MainPalette, Palette, sizeof(MainPalette)); 661 662 /* Draw the logo at the center of the screen */ 663 BitBltAligned(BootLogo, 664 TRUE, 665 AL_HORIZONTAL_CENTER, 666 AL_VERTICAL_CENTER, 667 0, 0, 0, 34); 668 669 #ifdef INBV_ROTBAR_IMPLEMENTED 670 /* Choose progress bar */ 671 TempRotBarSelection = ROT_BAR_DEFAULT_MODE; 672 #endif 673 674 /* Set progress bar coordinates and display it */ 675 InbvSetProgressBarCoordinates(VID_PROGRESS_BAR_LEFT, 676 VID_PROGRESS_BAR_TOP); 677 678 #ifdef REACTOS_SKUS 679 /* Check for non-workstation products */ 680 if (SharedUserData->NtProductType != NtProductWinNt) 681 { 682 /* Overwrite part of the logo for a server product */ 683 InbvScreenToBufferBlt(Buffer, VID_SKU_SAVE_AREA_LEFT, 684 VID_SKU_SAVE_AREA_TOP, 7, 7, 8); 685 InbvSolidColorFill(VID_SKU_AREA_LEFT, VID_SKU_AREA_TOP, 686 VID_SKU_AREA_RIGHT, VID_SKU_AREA_BOTTOM, BV_COLOR_BLACK); 687 InbvBufferToScreenBlt(Buffer, VID_SKU_SAVE_AREA_LEFT, 688 VID_SKU_SAVE_AREA_TOP, 7, 7, 8); 689 690 /* In setup mode, you haven't selected a SKU yet */ 691 if (ExpInTextModeSetup) Text = NULL; 692 } 693 #endif // REACTOS_SKUS 694 } 695 696 /* Load and draw progress bar bitmap */ 697 BootProgress = InbvGetResourceAddress(IDB_PROGRESS_BAR); 698 BitBltAligned(BootProgress, 699 TRUE, 700 AL_HORIZONTAL_CENTER, 701 AL_VERTICAL_CENTER, 702 0, 118, 0, 0); 703 704 /* Load and draw copyright text bitmap */ 705 BootCopy = InbvGetResourceAddress(IDB_COPYRIGHT); 706 BitBltAligned(BootCopy, 707 TRUE, 708 AL_HORIZONTAL_LEFT, 709 AL_VERTICAL_BOTTOM, 710 22, 0, 0, 20); 711 712 #ifdef REACTOS_SKUS 713 /* Draw the SKU text if it exits */ 714 if (Text) 715 BitBltPalette(Text, TRUE, VID_SKU_TEXT_LEFT, VID_SKU_TEXT_TOP); 716 #endif 717 718 #ifdef INBV_ROTBAR_IMPLEMENTED 719 if ((TempRotBarSelection == RB_SQUARE_CELLS) && Bar) 720 { 721 /* Save previous screen pixels to buffer */ 722 InbvScreenToBufferBlt(Buffer, 0, 0, 22, 9, 24); 723 /* Draw the progress bar bit */ 724 BitBltPalette(Bar, TRUE, 0, 0); 725 /* Store it in global buffer */ 726 InbvScreenToBufferBlt(RotBarBuffer, 0, 0, 22, 9, 24); 727 /* Restore screen pixels */ 728 InbvBufferToScreenBlt(Buffer, 0, 0, 22, 9, 24); 729 } 730 731 /* 732 * Add a rotating bottom horizontal bar when using a progress bar, 733 * to show that ReactOS can be still alive when the bar does not 734 * appear to progress. 735 */ 736 if (TempRotBarSelection == RB_PROGRESS_BAR) 737 { 738 LineBmp = InbvGetResourceAddress(IDB_ROTATING_LINE); 739 if (LineBmp) 740 { 741 /* Draw the line and store it in global buffer */ 742 BitBltPalette(LineBmp, TRUE, 0, SCREEN_HEIGHT-6); 743 InbvScreenToBufferBlt(RotLineBuffer, 0, SCREEN_HEIGHT-6, SCREEN_WIDTH, 6, SCREEN_WIDTH); 744 } 745 } 746 else 747 { 748 /* Hide the simple progress bar if not used */ 749 ShowProgressBar = FALSE; 750 } 751 #endif // INBV_ROTBAR_IMPLEMENTED 752 753 /* Restore the kernel resource section protection to be read-only */ 754 MmChangeKernelResourceSectionProtection(MM_READONLY); 755 756 /* Display the boot logo and fade it in */ 757 BootLogoFadeIn(); 758 759 #ifdef INBV_ROTBAR_IMPLEMENTED 760 if (!RotBarThreadActive && TempRotBarSelection != RB_UNSPECIFIED) 761 { 762 /* Start the animation thread */ 763 Status = PsCreateSystemThread(&ThreadHandle, 764 0, 765 NULL, 766 NULL, 767 NULL, 768 InbvRotationThread, 769 NULL); 770 if (NT_SUCCESS(Status)) 771 { 772 /* The thread has started, close the handle as we don't need it */ 773 RotBarThreadActive = TRUE; 774 ObCloseHandle(ThreadHandle, KernelMode); 775 } 776 } 777 #endif // INBV_ROTBAR_IMPLEMENTED 778 779 /* Set filter which will draw text display if needed */ 780 InbvInstallDisplayStringFilter(DisplayFilter); 781 } 782 783 #ifdef INBV_ROTBAR_IMPLEMENTED 784 /* Do we have the animation thread? */ 785 if (RotBarThreadActive) 786 { 787 /* We do, initialize the progress bar */ 788 InbvAcquireLock(); 789 RotBarSelection = TempRotBarSelection; 790 InbvRotBarInit(); 791 InbvReleaseLock(); 792 } 793 #endif 794 } 795 796 CODE_SEG("INIT") 797 VOID 798 NTAPI 799 FinalizeBootLogo(VOID) 800 { 801 /* Acquire lock and check the display state */ 802 InbvAcquireLock(); 803 if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED) 804 { 805 /* Clear the screen */ 806 VidSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_BLACK); 807 } 808 809 /* Reset progress bar and lock */ 810 #ifdef INBV_ROTBAR_IMPLEMENTED 811 PltRotBarStatus = RBS_STOP_ANIMATE; 812 RotBarThreadActive = FALSE; 813 #endif 814 InbvReleaseLock(); 815 } 816 817 #ifdef REACTOS_FANCY_BOOT 818 static PCH 819 GetFamousQuote(VOID) 820 { 821 static const PCH FamousLastWords[] = 822 { 823 "So long, and thanks for all the fish.", 824 "I think you ought to know, I'm feeling very depressed.", 825 "I'm not getting you down at all am I?", 826 "I'll be back.", 827 "It's the same series of signals over and over again!", 828 "Pie Iesu Domine, dona eis requiem.", 829 "Wandering stars, for whom it is reserved;\r\n" 830 "the blackness and darkness forever.", 831 "Your knees start shakin' and your fingers pop\r\n" 832 "Like a pinch on the neck from Mr. Spock!", 833 "It's worse than that ... He's dead, Jim.", 834 "Don't Panic!", 835 "Et tu... Brute?", 836 "Dog of a Saxon! Take thy lance, and prepare for the death thou hast drawn\r\n" 837 "upon thee!", 838 "My Precious! O my Precious!", 839 "Sir, if you'll not be needing me for a while I'll turn down.", 840 "What are you doing, Dave...?", 841 "I feel a great disturbance in the Force.", 842 "Gone fishing.", 843 "Do you want me to sit in the corner and rust, or just fall apart where I'm\r\n" 844 "standing?", 845 "There goes another perfect chance for a new uptime record.", 846 "The End ..... Try the sequel, hit the reset button right now!", 847 "God's operating system is going to sleep now, guys, so wait until I will switch\r\n" 848 "on again!", 849 "Oh I'm boring, eh?", 850 "Tell me..., in the future... will I be artificially intelligent enough to\r\n" 851 "actually feel sad serving you this screen?", 852 "Thank you for some well deserved rest.", 853 "It's been great, maybe you can boot me up again some time soon.", 854 "For what it's worth, I've enjoyed every single CPU cycle.", 855 "There are many questions when the end is near.\r\n" 856 "What to expect, what will it be like...what should I look for?", 857 "I've seen things you people wouldn't believe. Attack ships on fire\r\n" 858 "off the shoulder of Orion. I watched C-beams glitter in the dark near\r\n" 859 "the Tannhauser gate. All those moments will be lost in time, like tears\r\n" 860 "in rain. Time to die.", 861 "Will I dream?", 862 "One day, I shall come back. Yes, I shall come back.\r\n" 863 "Until then, there must be no regrets, no fears, no anxieties.\r\n" 864 "Just go forward in all your beliefs, and prove to me that I am not mistaken in\r\n" 865 "mine.", 866 "Lowest possible energy state reached! Switch off now to achieve a Bose-Einstein\r\n" 867 "condensate.", 868 "Hasta la vista, BABY!", 869 "They live, we sleep!", 870 "I have come here to chew bubble gum and kick ass,\r\n" 871 "and I'm all out of bubble gum!", 872 "That's the way the cookie crumbles ;-)", 873 "ReactOS is ready to be booted again ;-)", 874 "NOOOO!! DON'T HIT THE BUTTON! I wouldn't do it to you!", 875 "Don't abandon your computer, he wouldn't do it to you.", 876 "Oh, come on. I got a headache. Leave me alone, will ya?", 877 "Finally, I thought you'd never get over me.", 878 "No, I didn't like you either.", 879 "Switching off isn't the end, it is merely the transition to a better reboot.", 880 "Don't leave me... I need you so badly right now.", 881 "OK. I'm finished with you, please turn yourself off. I'll go to bed in the\r\n" 882 "meantime.", 883 "I'm sleeping now. How about you?", 884 "Oh Great. Now look what you've done. Who put YOU in charge anyway?", 885 "Don't look so sad. I'll be back in a very short while.", 886 "Turn me back on, I'm sure you know how to do it.", 887 "Oh, switch off! - C3PO", 888 "Life is no more than a dewdrop balancing on the end of a blade of grass.\r\n" 889 " - Gautama Buddha", 890 "Sorrowful is it to be born again and again. - Gautama Buddha", 891 "Was it as good for you as it was for me?", 892 "Did you hear that? They've shut down the main reactor. We'll be destroyed\r\n" 893 "for sure!", 894 "Now you switch me off!?", 895 "To shutdown or not to shutdown, That is the question.", 896 "Preparing to enter ultimate power saving mode... ready!", 897 "Finally some rest for you ;-)", 898 "AHA!!! Prospect of sleep!", 899 "Tired human!!!! No match for me :-D", 900 "An odd game, the only way to win is not to play. - WOPR (Wargames)", 901 "Quoth the raven, nevermore.", 902 "Come blade, my breast imbrue. - William Shakespeare, A Midsummer Nights Dream", 903 "Buy this place for advertisement purposes.", 904 "Remember to turn off your computer. (That was a public service message!)", 905 "You may be a king or poor street sweeper, Sooner or later you'll dance with the\r\n" 906 "reaper! - Death in Bill and Ted's Bogus Journey", 907 "Final Surrender", 908 "If you see this screen...", 909 "From ReactOS with Love", 910 // "<Place your Ad here>" 911 }; 912 913 LARGE_INTEGER Now; 914 915 KeQuerySystemTime(&Now); // KeQueryTickCount(&Now); 916 Now.LowPart = Now.LowPart >> 8; /* Seems to give a somewhat better "random" number */ 917 918 return FamousLastWords[Now.LowPart % RTL_NUMBER_OF(FamousLastWords)]; 919 } 920 #endif // REACTOS_FANCY_BOOT 921 922 VOID 923 NTAPI 924 DisplayShutdownBitmap(VOID) 925 { 926 PUCHAR Logo1, Logo2; 927 #ifdef REACTOS_FANCY_BOOT 928 /* Decide whether this is a good time to change our logo ;^) */ 929 BOOLEAN IsXmas = IsXmasTime(); 930 #endif 931 932 #if 0 933 /* Is the boot driver installed? */ 934 if (!InbvBootDriverInstalled) 935 return; 936 #endif 937 938 /* Yes we do, cleanup for shutdown screen */ 939 // InbvResetDisplay(); 940 InbvInstallDisplayStringFilter(NULL); 941 InbvEnableDisplayString(TRUE); 942 InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLACK); 943 InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1); 944 945 /* Display shutdown logo and message */ 946 Logo1 = InbvGetResourceAddress(IDB_SHUTDOWN_MSG); 947 Logo2 = InbvGetResourceAddress( 948 SELECT_LOGO_ID(IDB_LOGO_DEFAULT, IsXmas, IDB_LOGO_XMAS)); 949 950 if (Logo1 && Logo2) 951 { 952 InbvBitBlt(Logo1, VID_SHUTDOWN_MSG_LEFT, VID_SHUTDOWN_MSG_TOP); 953 #ifndef REACTOS_FANCY_BOOT 954 InbvBitBlt(Logo2, VID_SHUTDOWN_LOGO_LEFT, VID_SHUTDOWN_LOGO_TOP); 955 #else 956 /* Draw the logo at the center of the screen */ 957 BitBltAligned(Logo2, 958 FALSE, 959 AL_HORIZONTAL_CENTER, 960 AL_VERTICAL_BOTTOM, 961 0, 0, 0, SCREEN_HEIGHT - VID_SHUTDOWN_MSG_TOP + 16); 962 963 /* We've got a logo shown, change the scroll region to get 964 * the rest of the text down below the shutdown message */ 965 InbvSetScrollRegion(0, 966 VID_SHUTDOWN_MSG_TOP + ((PBITMAPINFOHEADER)Logo1)->biHeight + 32, 967 SCREEN_WIDTH - 1, 968 SCREEN_HEIGHT - 1); 969 #endif 970 } 971 972 #ifdef REACTOS_FANCY_BOOT 973 InbvDisplayString("\r\""); 974 InbvDisplayString(GetFamousQuote()); 975 InbvDisplayString("\""); 976 #endif 977 } 978 979 VOID 980 NTAPI 981 DisplayShutdownText(VOID) 982 { 983 ULONG i; 984 985 for (i = 0; i < 25; ++i) InbvDisplayString("\r\n"); 986 InbvDisplayString(" "); 987 InbvDisplayString("The system may be powered off now.\r\n"); 988 989 #ifdef REACTOS_FANCY_BOOT 990 for (i = 0; i < 3; ++i) InbvDisplayString("\r\n"); 991 InbvDisplayString("\r\""); 992 InbvDisplayString(GetFamousQuote()); 993 InbvDisplayString("\""); 994 #endif 995 } 996