X-Git-Url: https://code.delx.au/refind/blobdiff_plain/973b1bf7ee3cf6cc136f3271581edfa1a1f31c77..480ba418c97ece5557ac0efc5dc189ff19fb8b8f:/refind/screen.c diff --git a/refind/screen.c b/refind/screen.c index 9f0d483..a408430 100644 --- a/refind/screen.c +++ b/refind/screen.c @@ -33,11 +33,34 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), or (at your option) any later version. + * + */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #include "global.h" #include "screen.h" #include "config.h" #include "libegint.h" +#include "lib.h" +#include "menu.h" #include "../include/refit_call_wrapper.h" #include "../include/egemb_refind_banner.h" @@ -46,9 +69,7 @@ UINTN ConWidth; UINTN ConHeight; -CHAR16 *BlankLine; - -static VOID DrawScreenHeader(IN CHAR16 *Title); +CHAR16 *BlankLine = NULL; // UGA defines and variables @@ -58,6 +79,7 @@ BOOLEAN AllowGraphicsMode; EG_PIXEL StdBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 }; EG_PIXEL MenuBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 }; +EG_PIXEL DarkBackgroundPixel = { 0x0, 0x0, 0x0, 0 }; static BOOLEAN GraphicsScreenDirty; @@ -65,14 +87,23 @@ static BOOLEAN GraphicsScreenDirty; static BOOLEAN haveError = FALSE; +static VOID PrepareBlankLine(VOID) { + UINTN i; + + MyFreePool(BlankLine); + // make a buffer for a whole text line + BlankLine = AllocatePool((ConWidth + 1) * sizeof(CHAR16)); + for (i = 0; i < ConWidth; i++) + BlankLine[i] = ' '; + BlankLine[i] = 0; +} + // // Screen initialization and switching // VOID InitScreen(VOID) { - UINTN i; - // initialize libeg egInitScreen(); @@ -81,6 +112,7 @@ VOID InitScreen(VOID) AllowGraphicsMode = TRUE; } else { AllowGraphicsMode = FALSE; + egSetTextMode(GlobalConfig.RequestedTextMode); egSetGraphicsModeEnabled(FALSE); // just to be sure we are in text mode } GraphicsScreenDirty = TRUE; @@ -95,22 +127,47 @@ VOID InitScreen(VOID) ConHeight = 25; } - // make a buffer for a whole text line - BlankLine = AllocatePool((ConWidth + 1) * sizeof(CHAR16)); - for (i = 0; i < ConWidth; i++) - BlankLine[i] = ' '; - BlankLine[i] = 0; + PrepareBlankLine(); - // show the banner (even when in graphics mode) - DrawScreenHeader(L"Initializing..."); + // show the banner if in text mode + if (GlobalConfig.TextOnly && (GlobalConfig.ScreensaverTime != -1)) + DrawScreenHeader(L"Initializing..."); } +// Set the screen resolution and mode (text vs. graphics). VOID SetupScreen(VOID) { - if ((GlobalConfig.RequestedScreenWidth > 0) && (GlobalConfig.RequestedScreenHeight > 0) && - egSetScreenSize(GlobalConfig.RequestedScreenWidth, GlobalConfig.RequestedScreenHeight)) { - UGAWidth = GlobalConfig.RequestedScreenWidth; - UGAHeight = GlobalConfig.RequestedScreenHeight; + UINTN NewWidth, NewHeight; + + // Convert mode number to horizontal & vertical resolution values + if ((GlobalConfig.RequestedScreenWidth > 0) && (GlobalConfig.RequestedScreenHeight == 0)) + egGetResFromMode(&(GlobalConfig.RequestedScreenWidth), &(GlobalConfig.RequestedScreenHeight)); + + // Set the believed-to-be current resolution to the LOWER of the current + // believed-to-be resolution and the requested resolution. This is done to + // enable setting a lower-than-default resolution. + if ((GlobalConfig.RequestedScreenWidth > 0) && (GlobalConfig.RequestedScreenHeight > 0)) { + UGAWidth = (UGAWidth < GlobalConfig.RequestedScreenWidth) ? UGAWidth : GlobalConfig.RequestedScreenWidth; + UGAHeight = (UGAHeight < GlobalConfig.RequestedScreenHeight) ? UGAHeight : GlobalConfig.RequestedScreenHeight; + } + + // Set text mode. If this requires increasing the size of the graphics mode, do so. + if (egSetTextMode(GlobalConfig.RequestedTextMode)) { + egGetScreenSize(&NewWidth, &NewHeight); + if ((NewWidth > UGAWidth) || (NewHeight > UGAHeight)) { + UGAWidth = NewWidth; + UGAHeight = NewHeight; + } + if ((UGAWidth > GlobalConfig.RequestedScreenWidth) || (UGAHeight > GlobalConfig.RequestedScreenHeight)) { + // Requested text mode forces us to use a bigger graphics mode + GlobalConfig.RequestedScreenWidth = UGAWidth; + GlobalConfig.RequestedScreenHeight = UGAHeight; + } // if + } + + if (GlobalConfig.RequestedScreenWidth > 0) { + egSetScreenSize(&(GlobalConfig.RequestedScreenWidth), &(GlobalConfig.RequestedScreenHeight)); + egGetScreenSize(&UGAWidth, &UGAHeight); } // if user requested a particular screen resolution if (GlobalConfig.TextOnly) { @@ -122,9 +179,13 @@ VOID SetupScreen(VOID) // clear screen and show banner // (now we know we'll stay in graphics mode) SwitchToGraphics(); - BltClearScreen(TRUE); + if (GlobalConfig.ScreensaverTime != -1) { + BltClearScreen(TRUE); + } else { // start with screen blanked + GraphicsScreenDirty = TRUE; + } } -} +} // VOID SetupScreen() VOID SwitchToText(IN BOOLEAN CursorEnabled) { @@ -136,6 +197,7 @@ VOID SwitchToText(IN BOOLEAN CursorEnabled) ConWidth = 80; ConHeight = 25; } + PrepareBlankLine(); } VOID SwitchToGraphics(VOID) @@ -162,8 +224,8 @@ VOID BeginTextScreen(IN CHAR16 *Title) VOID FinishTextScreen(IN BOOLEAN WaitAlways) { if (haveError || WaitAlways) { - SwitchToText(FALSE); - PauseForKey(); + PauseForKey(); + SwitchToText(FALSE); } // reset error flag @@ -172,8 +234,6 @@ VOID FinishTextScreen(IN BOOLEAN WaitAlways) VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title) { - EG_PIXEL DarkBackgroundPixel = { 0x0, 0x0, 0x0, 0 }; - if (!AllowGraphicsMode) UseGraphicsMode = FALSE; @@ -181,15 +241,10 @@ VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title) SwitchToGraphics(); BltClearScreen(FALSE); } else { - egClearScreen(&DarkBackgroundPixel); - DrawScreenHeader(Title); - } // if/else - - // show the header -// DrawScreenHeader(Title); - - if (!UseGraphicsMode) + egClearScreen(&DarkBackgroundPixel); + DrawScreenHeader(Title); SwitchToText(TRUE); + } // reset error flag haveError = FALSE; @@ -205,6 +260,9 @@ VOID FinishExternalScreen(VOID) PauseForKey(); } + // Reset the screen resolution, in case external program changed it.... + SetupScreen(); + // reset error flag haveError = FALSE; } @@ -219,13 +277,14 @@ VOID TerminateScreen(VOID) refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE); } -static VOID DrawScreenHeader(IN CHAR16 *Title) +VOID DrawScreenHeader(IN CHAR16 *Title) { UINTN y; // clear to black background + egClearScreen(&DarkBackgroundPixel); // first clear in graphics mode refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); - refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut); + refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut); // then clear in text mode // paint header background refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BANNER); @@ -247,7 +306,7 @@ static VOID DrawScreenHeader(IN CHAR16 *Title) // Keyboard input // -static BOOLEAN ReadAllKeyStrokes(VOID) +BOOLEAN ReadAllKeyStrokes(VOID) { BOOLEAN GotKeyStrokes; EFI_STATUS Status; @@ -282,6 +341,11 @@ VOID PauseForKey(VOID) Print(L"\n"); } +// Pause a specified number of seconds +VOID PauseSeconds(UINTN Seconds) { + refit_call1_wrapper(BS->Stall, 1000000 * Seconds); +} // VOID PauseSeconds() + #if REFIT_DEBUG > 0 VOID DebugPause(VOID) { @@ -350,7 +414,6 @@ BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where) if (!EFI_ERROR(Status)) return FALSE; -// StatusToString(ErrorName, Status); gST->ConOut->SetAttribute (gST->ConOut, ATTR_ERROR); Print(L"Fatal Error: %r %s\n", Status, where); gST->ConOut->SetAttribute (gST->ConOut, ATTR_BASIC); @@ -363,12 +426,9 @@ BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where) BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where) { -// CHAR16 ErrorName[64]; - if (!EFI_ERROR(Status)) return FALSE; -// StatusToString(ErrorName, Status); gST->ConOut->SetAttribute (gST->ConOut, ATTR_ERROR); Print(L"Error: %r %s\n", Status, where); gST->ConOut->SetAttribute (gST->ConOut, ATTR_BASIC); @@ -389,34 +449,64 @@ VOID SwitchToGraphicsAndClear(VOID) BltClearScreen(TRUE); } -VOID BltClearScreen(IN BOOLEAN ShowBanner) +VOID BltClearScreen(BOOLEAN ShowBanner) { static EG_IMAGE *Banner = NULL; + EG_IMAGE *NewBanner = NULL; + INTN BannerPosX, BannerPosY; + EG_PIXEL Black = { 0x0, 0x0, 0x0, 0 }; if (ShowBanner && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_BANNER)) { // load banner on first call if (Banner == NULL) { - if (GlobalConfig.BannerFileName == NULL) - Banner = egPrepareEmbeddedImage(&egemb_refind_banner, FALSE); - else + if (GlobalConfig.BannerFileName) Banner = egLoadImage(SelfDir, GlobalConfig.BannerFileName, FALSE); - if (Banner != NULL) - MenuBackgroundPixel = Banner->PixelData[0]; + if (Banner == NULL) + Banner = egPrepareEmbeddedImage(&egemb_refind_banner, FALSE); } + if (Banner) { + if (GlobalConfig.BannerScale == BANNER_FILLSCREEN) { + if ((Banner->Height != UGAHeight) || (Banner->Width != UGAWidth)) { + NewBanner = egScaleImage(Banner, UGAWidth, UGAHeight); + } // if + } else if ((Banner->Width > UGAWidth) || (Banner->Height > UGAHeight)) { + NewBanner = egCropImage(Banner, 0, 0, (Banner->Width > UGAWidth) ? UGAWidth : Banner->Width, + (Banner->Height > UGAHeight) ? UGAHeight : Banner->Height); + } // if/elseif + if (NewBanner) { + MyFreePool(Banner); + Banner = NewBanner; + } + MenuBackgroundPixel = Banner->PixelData[0]; + } // if Banner exists + // clear and draw banner - egClearScreen(&MenuBackgroundPixel); - if (Banner != NULL) - BltImage(Banner, (UGAWidth - Banner->Width) >> 1, - ((UGAHeight - LAYOUT_TOTAL_HEIGHT) >> 1) + LAYOUT_BANNER_HEIGHT - Banner->Height); + if (GlobalConfig.ScreensaverTime != -1) + egClearScreen(&MenuBackgroundPixel); + else + egClearScreen(&Black); + + if (Banner != NULL) { + BannerPosX = (Banner->Width < UGAWidth) ? ((UGAWidth - Banner->Width) / 2) : 0; + BannerPosY = (INTN) (ComputeRow0PosY() / 2) - (INTN) Banner->Height; + if (BannerPosY < 0) + BannerPosY = 0; + GlobalConfig.BannerBottomEdge = BannerPosY + Banner->Height; + if (GlobalConfig.ScreensaverTime != -1) + BltImage(Banner, (UINTN) BannerPosX, (UINTN) BannerPosY); + } - } else { - // clear to standard background color - egClearScreen(&StdBackgroundPixel); + } else { // not showing banner + // clear to menu background color + egClearScreen(&MenuBackgroundPixel); } GraphicsScreenDirty = FALSE; -} + egFreeImage(GlobalConfig.ScreenBackground); + GlobalConfig.ScreenBackground = egCopyScreen(); +} // VOID BltClearScreen() + VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos) { @@ -498,189 +588,12 @@ VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG } // blit to screen and clean up - egDrawImage(CompImage, XPos, YPos); - egFreeImage(CompImage); - GraphicsScreenDirty = TRUE; -} - -// Line-editing functions borrowed from gummiboot (cursor_left(), cursor_right(), & line_edit()). -// gummiboot is copyright (c) 2012 by Kay Sievers and Harald Hoyer -// and is licensed under the LGPL 2.1. - -static void cursor_left(UINTN *cursor, UINTN *first) -{ - if ((*cursor) > 0) - (*cursor)--; - else if ((*first) > 0) - (*first)--; -} - -static void cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) -{ - if ((*cursor)+2 < x_max) - (*cursor)++; - else if ((*first) + (*cursor) < len) - (*first)++; + if (CompImage != NULL) { + if (CompImage->HasAlpha) + egDrawImageWithTransparency(CompImage, NULL, XPos, YPos, CompImage->Width, CompImage->Height); + else + egDrawImage(CompImage, XPos, YPos); + egFreeImage(CompImage); + GraphicsScreenDirty = TRUE; + } } - -BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max, UINTN y_pos) { - CHAR16 *line; - UINTN size; - UINTN len; - UINTN first; - CHAR16 *print; - UINTN cursor; - BOOLEAN exit; - BOOLEAN enter; - - if (!line_in) - line_in = L""; - size = StrLen(line_in) + 1024; - line = AllocatePool(size * sizeof(CHAR16)); - StrCpy(line, line_in); - len = StrLen(line); - print = AllocatePool(x_max * sizeof(CHAR16)); - - refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE); - - first = 0; - cursor = 0; - enter = FALSE; - exit = FALSE; - while (!exit) { - UINTN index; - EFI_STATUS err; - EFI_INPUT_KEY key; - UINTN i; - - i = len - first; - if (i >= x_max-2) - i = x_max-2; - CopyMem(print, line + first, i * sizeof(CHAR16)); - print[i++] = ' '; - print[i] = '\0'; - - refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y_pos); - refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, print); - refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); - - refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); - err = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); - if (EFI_ERROR(err)) - continue; - - switch (key.ScanCode) { - case SCAN_ESC: - exit = TRUE; - break; - case SCAN_HOME: - cursor = 0; - first = 0; - continue; - case SCAN_END: - cursor = len; - if (cursor >= x_max) { - cursor = x_max-2; - first = len - (x_max-2); - } - continue; - case SCAN_UP: - while((first + cursor) && line[first + cursor] == ' ') - cursor_left(&cursor, &first); - while((first + cursor) && line[first + cursor] != ' ') - cursor_left(&cursor, &first); - while((first + cursor) && line[first + cursor] == ' ') - cursor_left(&cursor, &first); - if (first + cursor != len && first + cursor) - cursor_right(&cursor, &first, x_max, len); - refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); - continue; - case SCAN_DOWN: - while(line[first + cursor] && line[first + cursor] == ' ') - cursor_right(&cursor, &first, x_max, len); - while(line[first + cursor] && line[first + cursor] != ' ') - cursor_right(&cursor, &first, x_max, len); - while(line[first + cursor] && line[first + cursor] == ' ') - cursor_right(&cursor, &first, x_max, len); - refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); - continue; - case SCAN_RIGHT: - if (first + cursor == len) - continue; - cursor_right(&cursor, &first, x_max, len); - refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); - continue; - case SCAN_LEFT: - cursor_left(&cursor, &first); - refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); - continue; - case SCAN_DELETE: - if (len == 0) - continue; - if (first + cursor == len) - continue; - for (i = first + cursor; i < len; i++) - line[i] = line[i+1]; - line[len-1] = ' '; - len--; - continue; - } - - switch (key.UnicodeChar) { - case CHAR_LINEFEED: - case CHAR_CARRIAGE_RETURN: - *line_out = line; - line = NULL; - enter = TRUE; - exit = TRUE; - break; - case CHAR_BACKSPACE: - if (len == 0) - continue; - if (first == 0 && cursor == 0) - continue; - for (i = first + cursor-1; i < len; i++) - line[i] = line[i+1]; - len--; - if (cursor > 0) - cursor--; - if (cursor > 0 || first == 0) - continue; - /* show full line if it fits */ - if (len < x_max-2) { - cursor = first; - first = 0; - continue; - } - /* jump left to see what we delete */ - if (first > 10) { - first -= 10; - cursor = 10; - } else { - cursor = first; - first = 0; - } - continue; - case '\t': - case ' ' ... '~': - case 0x80 ... 0xffff: - if (len+1 == size) - continue; - for (i = len; i > first + cursor; i--) - line[i] = line[i-1]; - line[first + cursor] = key.UnicodeChar; - len++; - line[len] = '\0'; - if (cursor+2 < x_max) - cursor++; - else if (first + cursor < len) - first++; - continue; - } - } - - refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE); - FreePool(print); - FreePool(line); - return enter; -} /* BOOLEAN line_edit() */