mirror of
https://github.com/edera-dev/sprout.git
synced 2026-11-04 16:42:20 +00:00
fix(boot): make the graphical menu mouse opt-in
Add menu-styles.graphical.enable-mouse, which is off by default. Without it, or without a pointing device, the cursor is not drawn and the hint only mentions the keyboard.
This commit is contained in:
1 parent
ffbfcbc1f0
commit
9ac55ada50
5 files changed
+74
-10
No files matched your search
@@ -130,7 +130,7 @@ $ sprout.efi --boot="Boot Xen"
|
|||||||
$ sprout.efi --autoconfigure
|
$ sprout.efi --autoconfigure
|
||||||
# Use the basic boot menu instead of the simple one.
|
# Use the basic boot menu instead of the simple one.
|
||||||
$ sprout.efi --menu-style=basic
|
$ sprout.efi --menu-style=basic
|
||||||
# Use the graphical boot menu, which can be used with the mouse.
|
# Use the graphical boot menu.
|
||||||
$ sprout.efi --menu-style=graphical
|
$ sprout.efi --menu-style=graphical
|
||||||
# Show the boot menu for 10 seconds before booting the default entry.
|
# Show the boot menu for 10 seconds before booting the default entry.
|
||||||
$ sprout.efi --menu-timeout=10
|
$ sprout.efi --menu-timeout=10
|
||||||
@@ -142,6 +142,16 @@ $ sprout.efi --retain-boot-console
|
|||||||
$ sprout.efi --bls-strict-mode
|
$ sprout.efi --bls-strict-mode
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Graphical Menu
|
||||||
|
|
||||||
|
The graphical menu selects entries with the keyboard. The mouse is off by default. To use it, enable it in
|
||||||
|
`sprout.toml`. The cursor is only shown when the mouse is enabled and the firmware has a pointing device.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[menu-styles.graphical]
|
||||||
|
enable-mouse = true
|
||||||
|
```
|
||||||
|
|
||||||
### Boot Linux from ESP
|
### Boot Linux from ESP
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
|||||||
+12
-2
@@ -630,6 +630,9 @@ fn run(reboot_on_error: &mut bool) -> Result<()> {
|
|||||||
.menu_style
|
.menu_style
|
||||||
.unwrap_or(config.options.menu_style);
|
.unwrap_or(config.options.menu_style);
|
||||||
|
|
||||||
|
// The graphical menu only uses the mouse when it is enabled in the configuration.
|
||||||
|
let graphical_mouse = config.menu_styles.graphical.enable_mouse;
|
||||||
|
|
||||||
// Find the forced boot entry, unless the boot menu is forced.
|
// Find the forced boot entry, unless the boot menu is forced.
|
||||||
// The oneshot entry from the bootloader interface is forced by id, and it is used instead of
|
// The oneshot entry from the bootloader interface is forced by id, and it is used instead of
|
||||||
// --boot. If the forced boot entry can't be found, such as when it was removed,
|
// --boot. If the forced boot entry can't be found, such as when it was removed,
|
||||||
@@ -664,8 +667,15 @@ fn run(reboot_on_error: &mut bool) -> Result<()> {
|
|||||||
let entry = match forced_entry {
|
let entry = match forced_entry {
|
||||||
Some(entry) => entry,
|
Some(entry) => entry,
|
||||||
// Delegate to the menu to select an entry to boot.
|
// Delegate to the menu to select an entry to boot.
|
||||||
None => menu::select(&timer, menu_timeout, menu_disabled, menu_style, &entries)
|
None => menu::select(
|
||||||
.context("unable to select entry via boot menu")?,
|
&timer,
|
||||||
|
menu_timeout,
|
||||||
|
menu_disabled,
|
||||||
|
menu_style,
|
||||||
|
graphical_mouse,
|
||||||
|
&entries,
|
||||||
|
)
|
||||||
|
.context("unable to select entry via boot menu")?,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Tell the bootloader interface what the selected entry is.
|
// Tell the bootloader interface what the selected entry is.
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub mod basic;
|
|||||||
/// font: The bitmap font that the graphical menu draws text with.
|
/// font: The bitmap font that the graphical menu draws text with.
|
||||||
mod font;
|
mod font;
|
||||||
|
|
||||||
/// graphical: A menu drawn on the graphics output that is used with the keyboard or the mouse.
|
/// graphical: A menu drawn on the graphics output that is used with the keyboard, or the mouse if enabled.
|
||||||
pub mod graphical;
|
pub mod graphical;
|
||||||
|
|
||||||
/// logo: The Sprout logo that the graphical menu draws in a corner.
|
/// logo: The Sprout logo that the graphical menu draws in a corner.
|
||||||
@@ -177,6 +177,7 @@ pub fn select<'live>(
|
|||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
menu_disabled: bool,
|
menu_disabled: bool,
|
||||||
style: MenuStyle,
|
style: MenuStyle,
|
||||||
|
graphical_mouse: bool,
|
||||||
entries: &'live [BootableEntry],
|
entries: &'live [BootableEntry],
|
||||||
) -> Result<&'live BootableEntry> {
|
) -> Result<&'live BootableEntry> {
|
||||||
// A hidden menu gives the user a moment to ask for the menu with a key press.
|
// A hidden menu gives the user a moment to ask for the menu with a key press.
|
||||||
@@ -208,7 +209,11 @@ pub fn select<'live>(
|
|||||||
|
|
||||||
// The graphical menu needs a graphics output, which not every machine has.
|
// The graphical menu needs a graphics output, which not every machine has.
|
||||||
// If it fails, the simple menu is used instead, which falls back to the basic menu.
|
// If it fails, the simple menu is used instead, which falls back to the basic menu.
|
||||||
MenuStyle::Graphical => GraphicalMenu.select(timeout, entries).or_else(|error| {
|
MenuStyle::Graphical => GraphicalMenu {
|
||||||
|
enable_mouse: graphical_mouse,
|
||||||
|
}
|
||||||
|
.select(timeout, entries)
|
||||||
|
.or_else(|error| {
|
||||||
warn!(
|
warn!(
|
||||||
"unable to show the graphical boot menu, using the simple menu: {:#}",
|
"unable to show the graphical boot menu, using the simple menu: {:#}",
|
||||||
error
|
error
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ const PIXELS_PER_MILLIMETER: i64 = 8;
|
|||||||
const TITLE: &str = "sprout";
|
const TITLE: &str = "sprout";
|
||||||
|
|
||||||
/// The hint shown once the countdown has been stopped.
|
/// The hint shown once the countdown has been stopped.
|
||||||
const HINT: &str = "Pick an entry with the arrow keys or the mouse.";
|
const HINT: &str = "Pick an entry with the arrow keys.";
|
||||||
|
|
||||||
|
/// The hint shown instead of [HINT] when the mouse is in use.
|
||||||
|
const HINT_MOUSE: &str = "Pick an entry with the arrow keys or the mouse.";
|
||||||
|
|
||||||
/// The color of the top of the background, which fades into [BACKGROUND_BOTTOM].
|
/// The color of the top of the background, which fades into [BACKGROUND_BOTTOM].
|
||||||
const BACKGROUND_TOP: (u8, u8, u8) = (0x3a, 0x1c, 0x4e);
|
const BACKGROUND_TOP: (u8, u8, u8) = (0x3a, 0x1c, 0x4e);
|
||||||
@@ -87,8 +90,11 @@ const CURSOR: [&str; 16] = [
|
|||||||
" XXXX ",
|
" XXXX ",
|
||||||
];
|
];
|
||||||
|
|
||||||
/// A graphical boot menu that selects entries with the keyboard or the mouse.
|
/// A graphical boot menu that selects entries with the keyboard, or the mouse if enabled.
|
||||||
pub struct GraphicalMenu;
|
pub struct GraphicalMenu {
|
||||||
|
/// Whether the mouse is used when the firmware has a pointing device.
|
||||||
|
pub enable_mouse: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// The pointing devices of the firmware.
|
/// The pointing devices of the firmware.
|
||||||
/// Firmware commonly has both kinds of protocol, even if one has no device behind it.
|
/// Firmware commonly has both kinds of protocol, even if one has no device behind it.
|
||||||
@@ -258,7 +264,7 @@ impl Layout {
|
|||||||
.map(|entry| entry.title().chars().count())
|
.map(|entry| entry.title().chars().count())
|
||||||
.max()
|
.max()
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let status = HINT.len().max(STATUS_WIDEST.len());
|
let status = HINT.len().max(HINT_MOUSE.len()).max(STATUS_WIDEST.len());
|
||||||
let panel_width = ((longest + 4) * cell + padding * 2)
|
let panel_width = ((longest + 4) * cell + padding * 2)
|
||||||
.max(40 * cell)
|
.max(40 * cell)
|
||||||
.max((status + 8) * cell)
|
.max((status + 8) * cell)
|
||||||
@@ -806,6 +812,7 @@ fn run(
|
|||||||
loop {
|
loop {
|
||||||
scene.status = match remaining {
|
scene.status = match remaining {
|
||||||
Some(remaining) => format!("Boot in {} s.", remaining.as_millis().div_ceil(1000)),
|
Some(remaining) => format!("Boot in {} s.", remaining.as_millis().div_ceil(1000)),
|
||||||
|
None if mouse.is_some() => String::from(HINT_MOUSE),
|
||||||
None => String::from(HINT),
|
None => String::from(HINT),
|
||||||
};
|
};
|
||||||
for screen in screens.iter_mut() {
|
for screen in screens.iter_mut() {
|
||||||
@@ -901,7 +908,7 @@ impl BootMenu for GraphicalMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut screens = Screen::open_all(entries)?;
|
let mut screens = Screen::open_all(entries)?;
|
||||||
let mut mouse = Mouse::open();
|
let mut mouse = self.enable_mouse.then(Mouse::open).flatten();
|
||||||
|
|
||||||
let result = uefi::system::with_stdin(|input| {
|
let result = uefi::system::with_stdin(|input| {
|
||||||
run(input, mouse.take(), &mut screens, timeout, entries, default)
|
run(input, mouse.take(), &mut screens, timeout, entries, default)
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ pub struct RootConfiguration {
|
|||||||
/// Default options for Sprout.
|
/// Default options for Sprout.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub options: OptionsConfiguration,
|
pub options: OptionsConfiguration,
|
||||||
|
/// Settings for each style of boot menu.
|
||||||
|
#[serde(rename = "menu-styles", default)]
|
||||||
|
pub menu_styles: MenuStylesConfiguration,
|
||||||
/// Values to be inserted into the root sprout context.
|
/// Values to be inserted into the root sprout context.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub values: BTreeMap<String, String>,
|
pub values: BTreeMap<String, String>,
|
||||||
@@ -99,12 +102,30 @@ pub struct OptionsConfiguration {
|
|||||||
pub bls_strict_mode: bool,
|
pub bls_strict_mode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Settings for each style of boot menu.
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
|
||||||
|
pub struct MenuStylesConfiguration {
|
||||||
|
/// Settings for the graphical boot menu.
|
||||||
|
#[serde(default)]
|
||||||
|
pub graphical: GraphicalMenuConfiguration,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Settings for the graphical boot menu.
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
|
||||||
|
pub struct GraphicalMenuConfiguration {
|
||||||
|
/// Enables selecting entries with the mouse, and shows the cursor. When disabled, or when
|
||||||
|
/// the firmware has no pointing device, entries are selected with the keyboard only.
|
||||||
|
#[serde(rename = "enable-mouse", default)]
|
||||||
|
pub enable_mouse: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// The default configuration, which matches an empty configuration file.
|
/// The default configuration, which matches an empty configuration file.
|
||||||
impl Default for RootConfiguration {
|
impl Default for RootConfiguration {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
version: latest_version(),
|
version: latest_version(),
|
||||||
options: Default::default(),
|
options: Default::default(),
|
||||||
|
menu_styles: Default::default(),
|
||||||
values: Default::default(),
|
values: Default::default(),
|
||||||
drivers: Default::default(),
|
drivers: Default::default(),
|
||||||
extractors: Default::default(),
|
extractors: Default::default(),
|
||||||
@@ -171,6 +192,17 @@ mod tests {
|
|||||||
assert_eq!(default.options.autoconfigure, empty.options.autoconfigure);
|
assert_eq!(default.options.autoconfigure, empty.options.autoconfigure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn graphical_mouse_is_off_by_default() {
|
||||||
|
assert!(
|
||||||
|
!RootConfiguration::default()
|
||||||
|
.menu_styles
|
||||||
|
.graphical
|
||||||
|
.enable_mouse
|
||||||
|
);
|
||||||
|
assert!(!empty().menu_styles.graphical.enable_mouse);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bls_strict_mode_is_off_by_default() {
|
fn bls_strict_mode_is_off_by_default() {
|
||||||
assert!(!RootConfiguration::default().options.bls_strict_mode);
|
assert!(!RootConfiguration::default().options.bls_strict_mode);
|
||||||
|
|||||||
Reference in new issue
Block a user