#!/usr/local/bin/perl # Show a form for editing GRUB 2 theme and appearance settings. use strict; use warnings; require './grub2-lib.pl'; ## no critic our (%text); &ReadParse(); &error_setup($text{'theme_err'}); my %access = &get_module_acl(); &error("$text{'eacl_np'} $text{'eacl_pedit'}") if (!$access{'edit'}); my $parsed = &read_grub_defaults(); my $values = $parsed->{'values'}; my $current_theme = &field_value($values->{'GRUB_THEME'}); my $theme_action = $current_theme ne '' ? 'keep' : 'clear'; &ui_print_header(undef, $text{'theme_title'}, "", "theme_mode"); # Theme source is only used when the action selector requests installation. print &ui_form_start("save_theme.cgi", "post"); print &ui_table_start($text{'defaults_theme_header'}, "width=100%", 2); print &ui_table_row( &hlink($text{'defaults_theme_current'}, "theme"), $current_theme ne '' ? &ui_tag('tt', &html_escape($current_theme)) : $text{'defaults_theme_none'} ); print &ui_table_row( &hlink($text{'defaults_theme_action'}, "theme_mode"), &ui_select("theme_mode", $theme_action, [ [ "keep", $text{'defaults_theme_keep'} ], [ "install", $text{'defaults_theme_install'} ], [ "clear", $text{'defaults_theme_clear'} ], ]) ); print &ui_table_row( &hlink($text{'defaults_theme_source'}, "theme_source"), &ui_textbox("theme_source", "", 60). " ".&file_chooser_button("theme_source"). &ui_tag('div', &ui_note($text{'defaults_theme_note'}, 0)) ); print &ui_table_row( &hlink($text{'defaults_terminal_output'}, "terminal_output"), &ui_select("terminal_output", &field_value($values->{'GRUB_TERMINAL_OUTPUT'}), [ [ "", $text{'defaults_keep'} ], [ "console", $text{'defaults_terminal_console'} ], [ "gfxterm", $text{'defaults_terminal_gfxterm'} ], [ "gfxterm console", $text{'defaults_terminal_gfxterm_console'} ], [ "serial", $text{'defaults_terminal_serial'} ], ]) ); print &ui_table_row( &hlink($text{'defaults_gfxmode'}, "gfxmode"), &gfxmode_select(&field_value($values->{'GRUB_GFXMODE'})) ); print &ui_table_row( &hlink($text{'defaults_background'}, "background"), &ui_textbox("background", &field_value($values->{'GRUB_BACKGROUND'}), 60). " ".&file_chooser_button("background"). &ui_tag('div', &ui_note($text{'defaults_background_note'}, 0)) ); print &ui_table_row( &hlink($text{'defaults_color_normal'}, "color_normal"), &color_pair_select("color_normal", $values->{'GRUB_COLOR_NORMAL'}, "white", "black") ); print &ui_table_row( &hlink($text{'defaults_color_highlight'}, "color_highlight"), &color_pair_select("color_highlight", $values->{'GRUB_COLOR_HIGHLIGHT'}, "black", "light-gray") ); print &ui_table_end(); print &ui_form_end([ [ undef, $text{'save'} ] ]); print &color_mode_script(); &ui_print_footer("index.cgi", $text{'index_return'}); # color_pair_select(name, value, default-foreground, default-background) # Returns foreground/background selectors for GRUB menu colors. sub color_pair_select { my ($name, $value, $default_fg, $default_bg) = @_; my ($fg, $bg) = ($default_fg, $default_bg); my $mode = "default"; if (defined($value) && $value =~ /^([^\/]+)\/([^\/]+)\z/) { # Existing GRUB colors are stored as foreground/background pairs. ($fg, $bg) = ($1, $2); $mode = "set"; } return &ui_select($name."_mode", $mode, [ [ "default", $text{'defaults_color_default'} ], [ "set", $text{'defaults_color_custom'} ], ]). &ui_tag('span', " ".&html_escape($text{'defaults_color_text'})." ". &ui_select($name."_fg", $fg, &color_options())." ". " ".&html_escape($text{'defaults_color_background'}). " ".&ui_select($name."_bg", $bg, &color_options()), { 'id' => $name."_custom_colors", 'style' => 'white-space: nowrap; visibility: '. ($mode eq 'set' ? 'visible' : 'hidden').';', }); } # color_mode_script() # Shows foreground/background selectors only for custom color pairs. sub color_mode_script { return &ui_tag('script', <<'EOF', { 'type' => 'application/javascript' }); function grub2_color_mode_select(name) { // Theme reloads may replace IDs; fall back to the stable field name. return document.getElementById(name + '_mode') || document.querySelector('select[name="' + name + '_mode"]'); } function grub2_color_mode_changed(name) { const mode = grub2_color_mode_select(name); const custom = document.getElementById(name + '_custom_colors'); if (!mode || !custom) { return; } // Visibility avoids layout jumps when a custom color pair is enabled. custom.style.visibility = mode.value === 'set' ? 'visible' : 'hidden'; } function grub2_color_modes_refresh() { grub2_color_mode_changed('color_normal'); grub2_color_mode_changed('color_highlight'); } document.addEventListener('change', function(event) { const target = event.target; if (!target || !target.name) { return; } if (target.name === 'color_normal_mode') { grub2_color_mode_changed('color_normal'); } else if (target.name === 'color_highlight_mode') { grub2_color_mode_changed('color_highlight'); } }); grub2_color_modes_refresh(); document.addEventListener('DOMContentLoaded', grub2_color_modes_refresh); if (window.MutationObserver && document.body) { // Re-apply after theme JavaScript re-renders form controls. new MutationObserver(grub2_color_modes_refresh).observe(document.body, { childList: true, subtree: true }); } EOF } # gfxmode_select(value) # Returns a dropdown of common GRUB graphical resolutions. sub gfxmode_select { my ($value) = @_; return &ui_select("gfxmode", $value, &gfxmode_options(), undef, undef, 1); } # gfxmode_options() # Returns common GRUB graphical resolution choices. sub gfxmode_options { return [ [ "", $text{'defaults_gfxmode_default'} ], [ "auto", $text{'defaults_gfxmode_auto'} ], map { [ $_, $_ ] } qw( 640x480 800x600 1024x768 1280x720 1280x800 1366x768 1440x900 1600x900 1680x1050 1920x1080 1920x1200 2560x1440 3840x2160 ), ]; } # color_options() # Returns GRUB color choices. sub color_options { return [ map { [ $_, $text{'color_'.$_} || $_ ] } &grub2_color_names() ]; } # field_value(value, [default]) # Returns a form value without treating the string 0 as empty. sub field_value { my ($value, $default) = @_; return defined($value) ? $value : ($default || ''); }