]> code.delx.au - refind/blobdiff - refind/menu.c
Version supports Secure Boot/MOK verification of binaries.
[refind] / refind / menu.c
index d35cd11c4ab46d71a18007cab2f874f7f83c4818..5f76da4f541baf8eb1b36ecb4e97ab457cce2f0b 100644 (file)
 #include "menu.h"
 #include "config.h"
 #include "libeg.h"
-#include "refit_call_wrapper.h"
+#include "../include/refit_call_wrapper.h"
 
-#include "egemb_back_selected_small.h"
-#include "egemb_arrow_left.h"
-#include "egemb_arrow_right.h"
+#include "../include/egemb_back_selected_small.h"
+#include "../include/egemb_arrow_left.h"
+#include "../include/egemb_arrow_right.h"
 
 // other menu definitions
 
@@ -308,11 +308,6 @@ VOID AddMenuEntry(IN REFIT_MENU_SCREEN *Screen, IN REFIT_MENU_ENTRY *Entry)
     AddListElement((VOID ***) &(Screen->Entries), &(Screen->EntryCount), Entry);
 }
 
-VOID FreeMenu(IN REFIT_MENU_SCREEN *Screen)
-{
-    if (Screen->Entries)
-        FreePool(Screen->Entries);
-}
 
 static INTN FindMenuShortcutEntry(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *Shortcut)
 {
@@ -371,7 +366,7 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty
     INTN ShortcutEntry;
     BOOLEAN HaveTimeout = FALSE;
     UINTN TimeoutCountdown = 0;
-    CHAR16 *TimeoutMessage;
+    CHAR16 TimeoutMessage[256];
     CHAR16 KeyAsString[2];
     UINTN MenuExit;
 
@@ -400,9 +395,8 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty
         }
 
         if (HaveTimeout) {
-            TimeoutMessage = PoolPrint(L"%s in %d seconds", Screen->TimeoutText, (TimeoutCountdown + 5) / 10);
+            SPrint(TimeoutMessage, 255, L"%s in %d seconds", Screen->TimeoutText, (TimeoutCountdown + 5) / 10);
             StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, TimeoutMessage);
-            FreePool(TimeoutMessage);
         }
 
         // read key press (and wait for it if applicable)
@@ -492,7 +486,7 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty
     if (ChosenEntry)
         *ChosenEntry = Screen->Entries[State.CurrentSelection];
     return MenuExit;
-} /* static UINTN RunGenericMenu( */
+} /* static UINTN RunGenericMenu() */
 
 //
 // text-mode generic style
@@ -504,7 +498,7 @@ static VOID TextMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State,
     UINTN MenuWidth, ItemWidth, MenuHeight;
     static UINTN MenuPosY;
     static CHAR16 **DisplayStrings;
-    CHAR16 *TimeoutMessage;
+    CHAR16 TimeoutMessage[256];
 
     State->ScrollMode = SCROLL_MODE_TEXT;
     switch (Function) {
@@ -531,11 +525,26 @@ static VOID TextMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State,
 
             // prepare strings for display
             DisplayStrings = AllocatePool(sizeof(CHAR16 *) * Screen->EntryCount);
-            for (i = 0; i <= State->MaxIndex; i++)
-                DisplayStrings[i] = PoolPrint(L" %-.*s ", MenuWidth, Screen->Entries[i]->Title);
-            // TODO: shorten strings that are too long (PoolPrint doesn't do that...)
-            // TODO: use more elaborate techniques for shortening too long strings (ellipses in the middle)
-            // TODO: account for double-width characters
+            for (i = 0; i <= State->MaxIndex; i++) {
+                // Note: Theoretically, SPrint() is a cleaner way to do this; but the
+                // description of the StrSize parameter to SPrint implies it's measured
+                // in characters, but in practice both TianoCore and GNU-EFI seem to
+                // use bytes instead, resulting in truncated displays. I could just
+                // double the size of the StrSize parameter, but that seems unsafe in
+                // case a future library change starts treating this as characters, so
+                // I'm doing it the hard way in this instance.
+                // TODO: Review the above and possibly change other uses of SPrint()
+                DisplayStrings[i] = AllocateZeroPool(2 * sizeof(CHAR16));
+                DisplayStrings[i][0] = L' ';
+                MergeStrings(&DisplayStrings[i], Screen->Entries[i]->Title, 0);
+                if (StrLen(DisplayStrings[i]) > MenuWidth)
+                   DisplayStrings[i][MenuWidth - 1] = 0;
+//                DisplayStrings[i] = AllocateZeroPool(256 * sizeof(CHAR16));
+//                SPrint(DisplayStrings[i], ((MenuWidth < 255) ? MenuWidth : 255) * sizeof(CHAR16),
+//                       L" %s ", Screen->Entries[i]->Title);
+                // TODO: use more elaborate techniques for shortening too long strings (ellipses in the middle)
+                // TODO: account for double-width characters
+            } // for
 
             // initial painting
             BeginTextScreen(Screen->Title);
@@ -552,8 +561,8 @@ static VOID TextMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State,
         case MENU_FUNCTION_CLEANUP:
             // release temporary memory
             for (i = 0; i <= State->MaxIndex; i++)
-                FreePool(DisplayStrings[i]);
-            FreePool(DisplayStrings);
+                MyFreePool(DisplayStrings[i]);
+            MyFreePool(DisplayStrings);
             break;
 
         case MENU_FUNCTION_PAINT_ALL:
@@ -602,9 +611,8 @@ static VOID TextMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State,
                 // paint or update message
                 refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR);
                 refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, ConHeight - 1);
-                TimeoutMessage = PoolPrint(L"%s  ", ParamText);
+                SPrint(TimeoutMessage, 255, L"%s  ", ParamText);
                 refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, TimeoutMessage);
-                FreePool(TimeoutMessage);
             }
             break;
 
@@ -711,7 +719,7 @@ static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *Sta
             break;
 
     }
-}
+} // static VOID GraphicsMenuStyle()
 
 //
 // graphical main menu style
@@ -875,7 +883,7 @@ VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINT
             break;
 
         case MENU_FUNCTION_CLEANUP:
-            FreePool(itemPosX);
+            MyFreePool(itemPosX);
             break;
 
         case MENU_FUNCTION_PAINT_ALL:
@@ -907,7 +915,39 @@ VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINT
             break;
 
     }
-}
+} // VOID MainMenuStyle()
+
+// Enable the user to edit boot loader options.
+// Returns TRUE if the user exited with edited options; FALSE if the user
+// pressed Esc to terminate the edit.
+static BOOLEAN EditOptions(LOADER_ENTRY *MenuEntry) {
+   UINTN x_max, y_max;
+   CHAR16 *EditedOptions;
+//   CHAR16 message[] = L"Use cursor keys to edit, Esc to exit, Enter to boot with edited options";
+   EG_PIXEL DarkBackgroundPixel  = { 0x0, 0x0, 0x0, 0 };
+   BOOLEAN retval = FALSE;
+
+   refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max);
+
+   if (!GlobalConfig.TextOnly)
+      SwitchToText(TRUE);
+
+   egClearScreen(&DarkBackgroundPixel);
+
+   refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y_max - 1);
+//   refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, message);
+   refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut,
+                       L"Use cursor keys to edit, Esc to exit, Enter to boot with edited options");
+
+   if (line_edit(MenuEntry->LoadOptions, &EditedOptions, x_max, 1)) {
+      MyFreePool(MenuEntry->LoadOptions);
+      MenuEntry->LoadOptions = EditedOptions;
+      retval = TRUE;
+   } // if
+   if (!GlobalConfig.TextOnly)
+      SwitchToGraphics();
+   return retval;
+} // VOID EditOptions()
 
 //
 // user-callable dispatcher functions
@@ -950,6 +990,10 @@ UINTN RunMainMenu(IN REFIT_MENU_SCREEN *Screen, IN CHAR16* DefaultSelection, OUT
             MenuExit = RunGenericMenu(TempChosenEntry->SubScreen, Style, -1, &TempChosenEntry);
             if (MenuExit == MENU_EXIT_ESCAPE || TempChosenEntry->Tag == TAG_RETURN)
                 MenuExit = 0;
+            if (MenuExit == MENU_EXIT_DETAILS) {
+               if (!EditOptions((LOADER_ENTRY *) TempChosenEntry))
+                  MenuExit = 0;
+            } // if
         }
     }