3 * Screen handling functions
5 * Copyright (c) 2006 Christoph Pfisterer
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the
20 * * Neither the name of Christoph Pfisterer nor the names of the
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 * Modifications copyright (c) 2012-2015 Roderick W. Smith
39 * Modifications distributed under the terms of the GNU General Public
40 * License (GPL) version 3 (GPLv3), or (at your option) any later version.
44 * This program is free software: you can redistribute it and/or modify
45 * it under the terms of the GNU General Public License as published by
46 * the Free Software Foundation, either version 3 of the License, or
47 * (at your option) any later version.
49 * This program is distributed in the hope that it will be useful,
50 * but WITHOUT ANY WARRANTY; without even the implied warranty of
51 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
52 * GNU General Public License for more details.
54 * You should have received a copy of the GNU General Public License
55 * along with this program. If not, see <http://www.gnu.org/licenses/>.
64 #include "../include/refit_call_wrapper.h"
66 #include "../include/egemb_refind_banner.h"
68 // Console defines and variables
72 CHAR16
*BlankLine
= NULL
;
74 // UGA defines and variables
78 BOOLEAN AllowGraphicsMode
;
80 EG_PIXEL StdBackgroundPixel
= { 0xbf, 0xbf, 0xbf, 0 };
81 EG_PIXEL MenuBackgroundPixel
= { 0xbf, 0xbf, 0xbf, 0 };
82 EG_PIXEL DarkBackgroundPixel
= { 0x0, 0x0, 0x0, 0 };
84 static BOOLEAN GraphicsScreenDirty
;
86 // general defines and variables
88 static BOOLEAN haveError
= FALSE
;
90 static VOID
PrepareBlankLine(VOID
) {
93 MyFreePool(BlankLine
);
94 // make a buffer for a whole text line
95 BlankLine
= AllocatePool((ConWidth
+ 1) * sizeof(CHAR16
));
96 for (i
= 0; i
< ConWidth
; i
++)
102 // Screen initialization and switching
105 VOID
InitScreen(VOID
)
110 if (egHasGraphicsMode()) {
111 egGetScreenSize(&UGAWidth
, &UGAHeight
);
112 AllowGraphicsMode
= TRUE
;
114 AllowGraphicsMode
= FALSE
;
115 egSetTextMode(GlobalConfig
.RequestedTextMode
);
116 egSetGraphicsModeEnabled(FALSE
); // just to be sure we are in text mode
118 GraphicsScreenDirty
= TRUE
;
121 refit_call2_wrapper(ST
->ConOut
->EnableCursor
, ST
->ConOut
, FALSE
);
123 // get size of text console
124 if (refit_call4_wrapper(ST
->ConOut
->QueryMode
, ST
->ConOut
, ST
->ConOut
->Mode
->Mode
, &ConWidth
, &ConHeight
) != EFI_SUCCESS
) {
125 // use default values on error
132 // show the banner if in text mode
133 if (GlobalConfig
.TextOnly
&& (GlobalConfig
.ScreensaverTime
!= -1))
134 DrawScreenHeader(L
"Initializing...");
137 // Set the screen resolution and mode (text vs. graphics).
138 VOID
SetupScreen(VOID
)
140 UINTN NewWidth
, NewHeight
;
142 // Convert mode number to horizontal & vertical resolution values
143 if ((GlobalConfig
.RequestedScreenWidth
> 0) && (GlobalConfig
.RequestedScreenHeight
== 0))
144 egGetResFromMode(&(GlobalConfig
.RequestedScreenWidth
), &(GlobalConfig
.RequestedScreenHeight
));
146 // Set the believed-to-be current resolution to the LOWER of the current
147 // believed-to-be resolution and the requested resolution. This is done to
148 // enable setting a lower-than-default resolution.
149 if ((GlobalConfig
.RequestedScreenWidth
> 0) && (GlobalConfig
.RequestedScreenHeight
> 0)) {
150 UGAWidth
= (UGAWidth
< GlobalConfig
.RequestedScreenWidth
) ? UGAWidth
: GlobalConfig
.RequestedScreenWidth
;
151 UGAHeight
= (UGAHeight
< GlobalConfig
.RequestedScreenHeight
) ? UGAHeight
: GlobalConfig
.RequestedScreenHeight
;
154 // Set text mode. If this requires increasing the size of the graphics mode, do so.
155 if (egSetTextMode(GlobalConfig
.RequestedTextMode
)) {
156 egGetScreenSize(&NewWidth
, &NewHeight
);
157 if ((NewWidth
> UGAWidth
) || (NewHeight
> UGAHeight
)) {
159 UGAHeight
= NewHeight
;
161 if ((UGAWidth
> GlobalConfig
.RequestedScreenWidth
) || (UGAHeight
> GlobalConfig
.RequestedScreenHeight
)) {
162 // Requested text mode forces us to use a bigger graphics mode
163 GlobalConfig
.RequestedScreenWidth
= UGAWidth
;
164 GlobalConfig
.RequestedScreenHeight
= UGAHeight
;
168 if (GlobalConfig
.RequestedScreenWidth
> 0) {
169 egSetScreenSize(&(GlobalConfig
.RequestedScreenWidth
), &(GlobalConfig
.RequestedScreenHeight
));
170 egGetScreenSize(&UGAWidth
, &UGAHeight
);
171 } // if user requested a particular screen resolution
173 if (GlobalConfig
.TextOnly
) {
174 // switch to text mode if requested
175 AllowGraphicsMode
= FALSE
;
178 } else if (AllowGraphicsMode
) {
179 // clear screen and show banner
180 // (now we know we'll stay in graphics mode)
182 if (GlobalConfig
.ScreensaverTime
!= -1) {
183 BltClearScreen(TRUE
);
184 } else { // start with screen blanked
185 GraphicsScreenDirty
= TRUE
;
188 } // VOID SetupScreen()
190 VOID
SwitchToText(IN BOOLEAN CursorEnabled
)
192 egSetGraphicsModeEnabled(FALSE
);
193 refit_call2_wrapper(ST
->ConOut
->EnableCursor
, ST
->ConOut
, CursorEnabled
);
194 // get size of text console
195 if (refit_call4_wrapper(ST
->ConOut
->QueryMode
, ST
->ConOut
, ST
->ConOut
->Mode
->Mode
, &ConWidth
, &ConHeight
) != EFI_SUCCESS
) {
196 // use default values on error
203 VOID
SwitchToGraphics(VOID
)
205 if (AllowGraphicsMode
&& !egIsGraphicsModeEnabled()) {
206 egSetGraphicsModeEnabled(TRUE
);
207 GraphicsScreenDirty
= TRUE
;
212 // Screen control for running tools
215 VOID
BeginTextScreen(IN CHAR16
*Title
)
217 DrawScreenHeader(Title
);
224 VOID
FinishTextScreen(IN BOOLEAN WaitAlways
)
226 if (haveError
|| WaitAlways
) {
235 VOID
BeginExternalScreen(IN BOOLEAN UseGraphicsMode
, IN CHAR16
*Title
)
237 if (!AllowGraphicsMode
)
238 UseGraphicsMode
= FALSE
;
240 if (UseGraphicsMode
) {
242 BltClearScreen(FALSE
);
244 egClearScreen(&DarkBackgroundPixel
);
245 DrawScreenHeader(Title
);
253 VOID
FinishExternalScreen(VOID
)
255 // make sure we clean up later
256 GraphicsScreenDirty
= TRUE
;
263 // Reset the screen resolution, in case external program changed it....
270 VOID
TerminateScreen(VOID
)
273 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_BASIC
);
274 refit_call1_wrapper(ST
->ConOut
->ClearScreen
, ST
->ConOut
);
277 refit_call2_wrapper(ST
->ConOut
->EnableCursor
, ST
->ConOut
, TRUE
);
280 VOID
DrawScreenHeader(IN CHAR16
*Title
)
284 // clear to black background
285 egClearScreen(&DarkBackgroundPixel
); // first clear in graphics mode
286 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_BASIC
);
287 refit_call1_wrapper(ST
->ConOut
->ClearScreen
, ST
->ConOut
); // then clear in text mode
289 // paint header background
290 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_BANNER
);
291 for (y
= 0; y
< 3; y
++) {
292 refit_call3_wrapper(ST
->ConOut
->SetCursorPosition
, ST
->ConOut
, 0, y
);
297 refit_call3_wrapper(ST
->ConOut
->SetCursorPosition
, ST
->ConOut
, 3, 1);
298 Print(L
"rEFInd - %s", Title
);
301 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_BASIC
);
302 refit_call3_wrapper(ST
->ConOut
->SetCursorPosition
, ST
->ConOut
, 0, 4);
309 BOOLEAN
ReadAllKeyStrokes(VOID
)
311 BOOLEAN GotKeyStrokes
;
315 GotKeyStrokes
= FALSE
;
317 Status
= refit_call2_wrapper(ST
->ConIn
->ReadKeyStroke
, ST
->ConIn
, &key
);
318 if (Status
== EFI_SUCCESS
) {
319 GotKeyStrokes
= TRUE
;
324 return GotKeyStrokes
;
327 VOID
PauseForKey(VOID
)
331 Print(L
"\n* Hit any key to continue *");
333 if (ReadAllKeyStrokes()) { // remove buffered key strokes
334 refit_call1_wrapper(BS
->Stall
, 5000000); // 5 seconds delay
335 ReadAllKeyStrokes(); // empty the buffer again
338 refit_call3_wrapper(BS
->WaitForEvent
, 1, &ST
->ConIn
->WaitForKey
, &index
);
339 ReadAllKeyStrokes(); // empty the buffer to protect the menu
344 // Pause a specified number of seconds
345 VOID
PauseSeconds(UINTN Seconds
) {
346 refit_call1_wrapper(BS
->Stall
, 1000000 * Seconds
);
347 } // VOID PauseSeconds()
350 VOID
DebugPause(VOID
)
352 // show console and wait for key
361 VOID
EndlessIdleLoop(VOID
)
367 refit_call3_wrapper(BS
->WaitForEvent
, 1, &ST
->ConIn
->WaitForKey
, &index
);
375 #ifdef __MAKEWITH_GNUEFI
376 BOOLEAN
CheckFatalError(IN EFI_STATUS Status
, IN CHAR16
*where
)
378 CHAR16 ErrorName
[64];
380 if (!EFI_ERROR(Status
))
383 StatusToString(ErrorName
, Status
);
384 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_ERROR
);
385 Print(L
"Fatal Error: %s %s\n", ErrorName
, where
);
386 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_BASIC
);
389 //BS->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData);
394 BOOLEAN
CheckError(IN EFI_STATUS Status
, IN CHAR16
*where
)
396 CHAR16 ErrorName
[64];
398 if (!EFI_ERROR(Status
))
401 StatusToString(ErrorName
, Status
);
402 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_ERROR
);
403 Print(L
"Error: %s %s\n", ErrorName
, where
);
404 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_BASIC
);
410 BOOLEAN
CheckFatalError(IN EFI_STATUS Status
, IN CHAR16
*where
)
412 // CHAR16 ErrorName[64];
414 if (!EFI_ERROR(Status
))
417 gST
->ConOut
->SetAttribute (gST
->ConOut
, ATTR_ERROR
);
418 Print(L
"Fatal Error: %r %s\n", Status
, where
);
419 gST
->ConOut
->SetAttribute (gST
->ConOut
, ATTR_BASIC
);
422 //gBS->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData);
427 BOOLEAN
CheckError(IN EFI_STATUS Status
, IN CHAR16
*where
)
429 if (!EFI_ERROR(Status
))
432 gST
->ConOut
->SetAttribute (gST
->ConOut
, ATTR_ERROR
);
433 Print(L
"Error: %r %s\n", Status
, where
);
434 gST
->ConOut
->SetAttribute (gST
->ConOut
, ATTR_BASIC
);
442 // Graphics functions
445 VOID
SwitchToGraphicsAndClear(VOID
)
448 if (GraphicsScreenDirty
)
449 BltClearScreen(TRUE
);
452 VOID
BltClearScreen(BOOLEAN ShowBanner
)
454 static EG_IMAGE
*Banner
= NULL
;
455 EG_IMAGE
*NewBanner
= NULL
;
456 INTN BannerPosX
, BannerPosY
;
457 EG_PIXEL Black
= { 0x0, 0x0, 0x0, 0 };
459 if (ShowBanner
&& !(GlobalConfig
.HideUIFlags
& HIDEUI_FLAG_BANNER
)) {
460 // load banner on first call
461 if (Banner
== NULL
) {
462 if (GlobalConfig
.BannerFileName
)
463 Banner
= egLoadImage(SelfDir
, GlobalConfig
.BannerFileName
, FALSE
);
465 Banner
= egPrepareEmbeddedImage(&egemb_refind_banner
, FALSE
);
469 if (GlobalConfig
.BannerScale
== BANNER_FILLSCREEN
) {
470 if ((Banner
->Height
!= UGAHeight
) || (Banner
->Width
!= UGAWidth
)) {
471 NewBanner
= egScaleImage(Banner
, UGAWidth
, UGAHeight
);
473 } else if ((Banner
->Width
> UGAWidth
) || (Banner
->Height
> UGAHeight
)) {
474 NewBanner
= egCropImage(Banner
, 0, 0, (Banner
->Width
> UGAWidth
) ? UGAWidth
: Banner
->Width
,
475 (Banner
->Height
> UGAHeight
) ? UGAHeight
: Banner
->Height
);
481 MenuBackgroundPixel
= Banner
->PixelData
[0];
482 } // if Banner exists
484 // clear and draw banner
485 if (GlobalConfig
.ScreensaverTime
!= -1)
486 egClearScreen(&MenuBackgroundPixel
);
488 egClearScreen(&Black
);
490 if (Banner
!= NULL
) {
491 BannerPosX
= (Banner
->Width
< UGAWidth
) ? ((UGAWidth
- Banner
->Width
) / 2) : 0;
492 BannerPosY
= (INTN
) (ComputeRow0PosY() / 2) - (INTN
) Banner
->Height
;
495 GlobalConfig
.BannerBottomEdge
= BannerPosY
+ Banner
->Height
;
496 if (GlobalConfig
.ScreensaverTime
!= -1)
497 BltImage(Banner
, (UINTN
) BannerPosX
, (UINTN
) BannerPosY
);
500 } else { // not showing banner
501 // clear to menu background color
502 egClearScreen(&MenuBackgroundPixel
);
505 GraphicsScreenDirty
= FALSE
;
506 egFreeImage(GlobalConfig
.ScreenBackground
);
507 GlobalConfig
.ScreenBackground
= egCopyScreen();
508 } // VOID BltClearScreen()
511 VOID
BltImage(IN EG_IMAGE
*Image
, IN UINTN XPos
, IN UINTN YPos
)
513 egDrawImage(Image
, XPos
, YPos
);
514 GraphicsScreenDirty
= TRUE
;
517 VOID
BltImageAlpha(IN EG_IMAGE
*Image
, IN UINTN XPos
, IN UINTN YPos
, IN EG_PIXEL
*BackgroundPixel
)
521 // compose on background
522 CompImage
= egCreateFilledImage(Image
->Width
, Image
->Height
, FALSE
, BackgroundPixel
);
523 egComposeImage(CompImage
, Image
, 0, 0);
525 // blit to screen and clean up
526 egDrawImage(CompImage
, XPos
, YPos
);
527 egFreeImage(CompImage
);
528 GraphicsScreenDirty
= TRUE
;
531 // VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos)
533 // UINTN TotalWidth, TotalHeight, CompWidth, CompHeight, OffsetX, OffsetY;
534 // EG_IMAGE *CompImage;
536 // // initialize buffer with base image
537 // CompImage = egCopyImage(BaseImage);
538 // TotalWidth = BaseImage->Width;
539 // TotalHeight = BaseImage->Height;
541 // // place the top image
542 // CompWidth = TopImage->Width;
543 // if (CompWidth > TotalWidth)
544 // CompWidth = TotalWidth;
545 // OffsetX = (TotalWidth - CompWidth) >> 1;
546 // CompHeight = TopImage->Height;
547 // if (CompHeight > TotalHeight)
548 // CompHeight = TotalHeight;
549 // OffsetY = (TotalHeight - CompHeight) >> 1;
550 // egComposeImage(CompImage, TopImage, OffsetX, OffsetY);
552 // // blit to screen and clean up
553 // egDrawImage(CompImage, XPos, YPos);
554 // egFreeImage(CompImage);
555 // GraphicsScreenDirty = TRUE;
558 VOID
BltImageCompositeBadge(IN EG_IMAGE
*BaseImage
, IN EG_IMAGE
*TopImage
, IN EG_IMAGE
*BadgeImage
, IN UINTN XPos
, IN UINTN YPos
)
560 UINTN TotalWidth
= 0, TotalHeight
= 0, CompWidth
= 0, CompHeight
= 0, OffsetX
= 0, OffsetY
= 0;
561 EG_IMAGE
*CompImage
= NULL
;
563 // initialize buffer with base image
564 if (BaseImage
!= NULL
) {
565 CompImage
= egCopyImage(BaseImage
);
566 TotalWidth
= BaseImage
->Width
;
567 TotalHeight
= BaseImage
->Height
;
570 // place the top image
571 if ((TopImage
!= NULL
) && (CompImage
!= NULL
)) {
572 CompWidth
= TopImage
->Width
;
573 if (CompWidth
> TotalWidth
)
574 CompWidth
= TotalWidth
;
575 OffsetX
= (TotalWidth
- CompWidth
) >> 1;
576 CompHeight
= TopImage
->Height
;
577 if (CompHeight
> TotalHeight
)
578 CompHeight
= TotalHeight
;
579 OffsetY
= (TotalHeight
- CompHeight
) >> 1;
580 egComposeImage(CompImage
, TopImage
, OffsetX
, OffsetY
);
583 // place the badge image
584 if (BadgeImage
!= NULL
&& CompImage
!= NULL
&& (BadgeImage
->Width
+ 8) < CompWidth
&& (BadgeImage
->Height
+ 8) < CompHeight
) {
585 OffsetX
+= CompWidth
- 8 - BadgeImage
->Width
;
586 OffsetY
+= CompHeight
- 8 - BadgeImage
->Height
;
587 egComposeImage(CompImage
, BadgeImage
, OffsetX
, OffsetY
);
590 // blit to screen and clean up
591 if (CompImage
!= NULL
) {
592 if (CompImage
->HasAlpha
)
593 egDrawImageWithTransparency(CompImage
, NULL
, XPos
, YPos
, CompImage
->Width
, CompImage
->Height
);
595 egDrawImage(CompImage
, XPos
, YPos
);
596 egFreeImage(CompImage
);
597 GraphicsScreenDirty
= TRUE
;