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.
41 #include "../include/refit_call_wrapper.h"
43 #include "../include/egemb_refind_banner.h"
45 // Console defines and variables
51 static VOID
SwitchToText(IN BOOLEAN CursorEnabled
);
52 static VOID
SwitchToGraphics(VOID
);
53 static VOID
DrawScreenHeader(IN CHAR16
*Title
);
55 // UGA defines and variables
59 BOOLEAN AllowGraphicsMode
;
61 EG_PIXEL StdBackgroundPixel
= { 0xbf, 0xbf, 0xbf, 0 };
62 EG_PIXEL MenuBackgroundPixel
= { 0xbf, 0xbf, 0xbf, 0 };
64 static BOOLEAN GraphicsScreenDirty
;
66 // general defines and variables
68 static BOOLEAN haveError
= FALSE
;
71 // Screen initialization and switching
81 if (egHasGraphicsMode()) {
82 egGetScreenSize(&UGAWidth
, &UGAHeight
);
83 AllowGraphicsMode
= TRUE
;
85 AllowGraphicsMode
= FALSE
;
86 egSetGraphicsModeEnabled(FALSE
); // just to be sure we are in text mode
88 GraphicsScreenDirty
= TRUE
;
91 refit_call2_wrapper(ST
->ConOut
->EnableCursor
, ST
->ConOut
, FALSE
);
93 // get size of text console
94 if (refit_call4_wrapper(ST
->ConOut
->QueryMode
, ST
->ConOut
, ST
->ConOut
->Mode
->Mode
, &ConWidth
, &ConHeight
) != EFI_SUCCESS
) {
95 // use default values on error
100 // make a buffer for a whole text line
101 BlankLine
= AllocatePool((ConWidth
+ 1) * sizeof(CHAR16
));
102 for (i
= 0; i
< ConWidth
; i
++)
106 // show the banner (even when in graphics mode)
107 DrawScreenHeader(L
"Initializing...");
110 VOID
SetupScreen(VOID
)
112 if (GlobalConfig
.TextOnly
) {
113 // switch to text mode if requested
114 AllowGraphicsMode
= FALSE
;
117 } else if (AllowGraphicsMode
) {
118 // clear screen and show banner
119 // (now we know we'll stay in graphics mode)
120 if ((GlobalConfig
.RequestedScreenWidth
> 0) && (GlobalConfig
.RequestedScreenHeight
> 0) &&
121 egSetScreenSize(GlobalConfig
.RequestedScreenWidth
, GlobalConfig
.RequestedScreenHeight
)) {
122 UGAWidth
= GlobalConfig
.RequestedScreenWidth
;
123 UGAHeight
= GlobalConfig
.RequestedScreenHeight
;
124 } // if user requested a particular screen resolution
126 BltClearScreen(TRUE
);
130 static VOID
SwitchToText(IN BOOLEAN CursorEnabled
)
132 egSetGraphicsModeEnabled(FALSE
);
133 refit_call2_wrapper(ST
->ConOut
->EnableCursor
, ST
->ConOut
, CursorEnabled
);
136 static VOID
SwitchToGraphics(VOID
)
138 if (AllowGraphicsMode
&& !egIsGraphicsModeEnabled()) {
139 egSetGraphicsModeEnabled(TRUE
);
140 GraphicsScreenDirty
= TRUE
;
145 // Screen control for running tools
148 VOID
BeginTextScreen(IN CHAR16
*Title
)
150 DrawScreenHeader(Title
);
157 VOID
FinishTextScreen(IN BOOLEAN WaitAlways
)
159 if (haveError
|| WaitAlways
) {
168 VOID
BeginExternalScreen(IN BOOLEAN UseGraphicsMode
, IN CHAR16
*Title
)
170 EG_PIXEL DarkBackgroundPixel
= { 0x0, 0x0, 0x0, 0 };
172 if (!AllowGraphicsMode
)
173 UseGraphicsMode
= FALSE
;
175 if (UseGraphicsMode
) {
177 BltClearScreen(FALSE
);
179 egClearScreen(&DarkBackgroundPixel
);
180 DrawScreenHeader(Title
);
184 // DrawScreenHeader(Title);
186 if (!UseGraphicsMode
)
193 VOID
FinishExternalScreen(VOID
)
195 // make sure we clean up later
196 GraphicsScreenDirty
= TRUE
;
207 VOID
TerminateScreen(VOID
)
210 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_BASIC
);
211 refit_call1_wrapper(ST
->ConOut
->ClearScreen
, ST
->ConOut
);
214 refit_call2_wrapper(ST
->ConOut
->EnableCursor
, ST
->ConOut
, TRUE
);
217 static VOID
DrawScreenHeader(IN CHAR16
*Title
)
221 // clear to black background
222 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_BASIC
);
223 refit_call1_wrapper(ST
->ConOut
->ClearScreen
, ST
->ConOut
);
225 // paint header background
226 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_BANNER
);
227 for (y
= 0; y
< 3; y
++) {
228 refit_call3_wrapper(ST
->ConOut
->SetCursorPosition
, ST
->ConOut
, 0, y
);
233 refit_call3_wrapper(ST
->ConOut
->SetCursorPosition
, ST
->ConOut
, 3, 1);
234 Print(L
"rEFInd - %s", Title
);
237 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_BASIC
);
238 refit_call3_wrapper(ST
->ConOut
->SetCursorPosition
, ST
->ConOut
, 0, 4);
245 static BOOLEAN
ReadAllKeyStrokes(VOID
)
247 BOOLEAN GotKeyStrokes
;
251 GotKeyStrokes
= FALSE
;
253 Status
= refit_call2_wrapper(ST
->ConIn
->ReadKeyStroke
, ST
->ConIn
, &key
);
254 if (Status
== EFI_SUCCESS
) {
255 GotKeyStrokes
= TRUE
;
260 return GotKeyStrokes
;
263 VOID
PauseForKey(VOID
)
267 Print(L
"\n* Hit any key to continue *");
269 if (ReadAllKeyStrokes()) { // remove buffered key strokes
270 refit_call1_wrapper(BS
->Stall
, 5000000); // 5 seconds delay
271 ReadAllKeyStrokes(); // empty the buffer again
274 refit_call3_wrapper(BS
->WaitForEvent
, 1, &ST
->ConIn
->WaitForKey
, &index
);
275 ReadAllKeyStrokes(); // empty the buffer to protect the menu
281 VOID
DebugPause(VOID
)
283 // show console and wait for key
292 VOID
EndlessIdleLoop(VOID
)
298 refit_call3_wrapper(BS
->WaitForEvent
, 1, &ST
->ConIn
->WaitForKey
, &index
);
306 #ifdef __MAKEWITH_GNUEFI
307 BOOLEAN
CheckFatalError(IN EFI_STATUS Status
, IN CHAR16
*where
)
309 CHAR16 ErrorName
[64];
311 if (!EFI_ERROR(Status
))
314 StatusToString(ErrorName
, Status
);
315 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_ERROR
);
316 Print(L
"Fatal Error: %s %s\n", ErrorName
, where
);
317 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_BASIC
);
320 //BS->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData);
325 BOOLEAN
CheckError(IN EFI_STATUS Status
, IN CHAR16
*where
)
327 CHAR16 ErrorName
[64];
329 if (!EFI_ERROR(Status
))
332 StatusToString(ErrorName
, Status
);
333 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_ERROR
);
334 Print(L
"Error: %s %s\n", ErrorName
, where
);
335 refit_call2_wrapper(ST
->ConOut
->SetAttribute
, ST
->ConOut
, ATTR_BASIC
);
341 BOOLEAN
CheckFatalError(IN EFI_STATUS Status
, IN CHAR16
*where
)
343 // CHAR16 ErrorName[64];
345 if (!EFI_ERROR(Status
))
348 // StatusToString(ErrorName, Status);
349 gST
->ConOut
->SetAttribute (gST
->ConOut
, ATTR_ERROR
);
350 Print(L
"Fatal Error: %r %s\n", Status
, where
);
351 gST
->ConOut
->SetAttribute (gST
->ConOut
, ATTR_BASIC
);
354 //gBS->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData);
359 BOOLEAN
CheckError(IN EFI_STATUS Status
, IN CHAR16
*where
)
361 // CHAR16 ErrorName[64];
363 if (!EFI_ERROR(Status
))
366 // StatusToString(ErrorName, Status);
367 gST
->ConOut
->SetAttribute (gST
->ConOut
, ATTR_ERROR
);
368 Print(L
"Error: %r %s\n", Status
, where
);
369 gST
->ConOut
->SetAttribute (gST
->ConOut
, ATTR_BASIC
);
377 // Graphics functions
380 VOID
SwitchToGraphicsAndClear(VOID
)
383 if (GraphicsScreenDirty
)
384 BltClearScreen(TRUE
);
387 VOID
BltClearScreen(IN BOOLEAN ShowBanner
)
389 static EG_IMAGE
*Banner
= NULL
;
391 if (ShowBanner
&& !(GlobalConfig
.HideUIFlags
& HIDEUI_FLAG_BANNER
)) {
392 // load banner on first call
393 if (Banner
== NULL
) {
394 if (GlobalConfig
.BannerFileName
== NULL
)
395 Banner
= egPrepareEmbeddedImage(&egemb_refind_banner
, FALSE
);
397 Banner
= egLoadImage(SelfDir
, GlobalConfig
.BannerFileName
, FALSE
);
399 MenuBackgroundPixel
= Banner
->PixelData
[0];
402 // clear and draw banner
403 egClearScreen(&MenuBackgroundPixel
);
405 BltImage(Banner
, (UGAWidth
- Banner
->Width
) >> 1,
406 ((UGAHeight
- LAYOUT_TOTAL_HEIGHT
) >> 1) + LAYOUT_BANNER_HEIGHT
- Banner
->Height
);
409 // clear to standard background color
410 egClearScreen(&StdBackgroundPixel
);
413 GraphicsScreenDirty
= FALSE
;
416 VOID
BltImage(IN EG_IMAGE
*Image
, IN UINTN XPos
, IN UINTN YPos
)
418 egDrawImage(Image
, XPos
, YPos
);
419 GraphicsScreenDirty
= TRUE
;
422 VOID
BltImageAlpha(IN EG_IMAGE
*Image
, IN UINTN XPos
, IN UINTN YPos
, IN EG_PIXEL
*BackgroundPixel
)
426 // compose on background
427 CompImage
= egCreateFilledImage(Image
->Width
, Image
->Height
, FALSE
, BackgroundPixel
);
428 egComposeImage(CompImage
, Image
, 0, 0);
430 // blit to screen and clean up
431 egDrawImage(CompImage
, XPos
, YPos
);
432 egFreeImage(CompImage
);
433 GraphicsScreenDirty
= TRUE
;
436 // VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos)
438 // UINTN TotalWidth, TotalHeight, CompWidth, CompHeight, OffsetX, OffsetY;
439 // EG_IMAGE *CompImage;
441 // // initialize buffer with base image
442 // CompImage = egCopyImage(BaseImage);
443 // TotalWidth = BaseImage->Width;
444 // TotalHeight = BaseImage->Height;
446 // // place the top image
447 // CompWidth = TopImage->Width;
448 // if (CompWidth > TotalWidth)
449 // CompWidth = TotalWidth;
450 // OffsetX = (TotalWidth - CompWidth) >> 1;
451 // CompHeight = TopImage->Height;
452 // if (CompHeight > TotalHeight)
453 // CompHeight = TotalHeight;
454 // OffsetY = (TotalHeight - CompHeight) >> 1;
455 // egComposeImage(CompImage, TopImage, OffsetX, OffsetY);
457 // // blit to screen and clean up
458 // egDrawImage(CompImage, XPos, YPos);
459 // egFreeImage(CompImage);
460 // GraphicsScreenDirty = TRUE;
463 VOID
BltImageCompositeBadge(IN EG_IMAGE
*BaseImage
, IN EG_IMAGE
*TopImage
, IN EG_IMAGE
*BadgeImage
, IN UINTN XPos
, IN UINTN YPos
)
465 UINTN TotalWidth
= 0, TotalHeight
= 0, CompWidth
= 0, CompHeight
= 0, OffsetX
= 0, OffsetY
= 0;
466 EG_IMAGE
*CompImage
= NULL
;
468 // initialize buffer with base image
469 if (BaseImage
!= NULL
) {
470 CompImage
= egCopyImage(BaseImage
);
471 TotalWidth
= BaseImage
->Width
;
472 TotalHeight
= BaseImage
->Height
;
475 // place the top image
476 if ((TopImage
!= NULL
) && (CompImage
!= NULL
)) {
477 CompWidth
= TopImage
->Width
;
478 if (CompWidth
> TotalWidth
)
479 CompWidth
= TotalWidth
;
480 OffsetX
= (TotalWidth
- CompWidth
) >> 1;
481 CompHeight
= TopImage
->Height
;
482 if (CompHeight
> TotalHeight
)
483 CompHeight
= TotalHeight
;
484 OffsetY
= (TotalHeight
- CompHeight
) >> 1;
485 egComposeImage(CompImage
, TopImage
, OffsetX
, OffsetY
);
488 // place the badge image
489 if (BadgeImage
!= NULL
&& CompImage
!= NULL
&& (BadgeImage
->Width
+ 8) < CompWidth
&& (BadgeImage
->Height
+ 8) < CompHeight
) {
490 OffsetX
+= CompWidth
- 8 - BadgeImage
->Width
;
491 OffsetY
+= CompHeight
- 8 - BadgeImage
->Height
;
492 egComposeImage(CompImage
, BadgeImage
, OffsetX
, OffsetY
);
495 // blit to screen and clean up
496 egDrawImage(CompImage
, XPos
, YPos
);
497 egFreeImage(CompImage
);
498 GraphicsScreenDirty
= TRUE
;