From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1J6Y55-0005zr-Ln for mharc-grub-devel@gnu.org; Sun, 23 Dec 2007 16:09:55 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1J6Y53-0005zN-O5 for grub-devel@gnu.org; Sun, 23 Dec 2007 16:09:53 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1J6Y52-0005zB-5S for grub-devel@gnu.org; Sun, 23 Dec 2007 16:09:52 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1J6Y51-0005z8-VR for grub-devel@gnu.org; Sun, 23 Dec 2007 16:09:52 -0500 Received: from aybabtu.com ([69.60.117.155]) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1J6Y51-0006v6-B4 for grub-devel@gnu.org; Sun, 23 Dec 2007 16:09:51 -0500 Received: from [192.168.10.6] (helo=thorin) by aybabtu.com with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.63) (envelope-from ) id 1J6Y4y-0002jE-QP for grub-devel@gnu.org; Sun, 23 Dec 2007 22:09:50 +0100 Received: from rmh by thorin with local (Exim 4.63) (envelope-from ) id 1J6Y4m-0007Hr-8n for grub-devel@gnu.org; Sun, 23 Dec 2007 22:09:36 +0100 Date: Sun, 23 Dec 2007 22:09:36 +0100 From: Robert Millan To: grub-devel@gnu.org Message-ID: <20071223210936.GA27776@thorin> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="XsQoSWH+UP9D9v3l" Content-Disposition: inline Organization: free as in freedom X-Message-Flag: Worried about Outlook viruses? Switch to Thunderbird! www.mozilla.com/thunderbird X-Debbugs-No-Ack: true User-Agent: Mutt/1.5.13 (2006-08-11) X-detected-kernel: by monty-python.gnu.org: Genre and OS details not recognized. Subject: [PATCH] colored menu X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GRUB 2 List-Id: The development of GRUB 2 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 23 Dec 2007 21:09:54 -0000 --XsQoSWH+UP9D9v3l Content-Type: text/plain; charset=us-ascii Content-Disposition: inline This patch adds a nice looking colored menu like the one you'd obtain on GRUB Legacy with "color cyan/blue white/blue" command. Screenshot is attached as well. A pair of notes: - The *_setcolor function stubs are being removed from some terminals because grub_setcolor() from kernel already skips undefined *_setcolor implementations so there's no need for an empty stub. In fact, not needed for this patch but adds confusion (I had to inspect all them to see if *_getcolor() had to be added). - I know that hardcoding colors is not so nice, but I was unsure how would the selection interface have to look like (and lacking time to implement it), and in comparison with defaulting to hardcoded 0x07 (grey on black) I see it as an improvement. -- Robert Millan I know my rights; I want my phone call! What use is a phone call, if you are unable to speak? (as seen on /.) --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="colored_menu.diff" * include/grub/term.h (struct grub_term): Add `getcolor' function. (grub_getcolor): New function. * kern/term.c (grub_getcolor): New function. * normal/menu.c (GRUB_COLOR_MENU_NORMAL): New macro. (GRUB_COLOR_MENU_HIGHLIGHT): New macro. (print_entry): Set normal and highlight colors to `GRUB_COLOR_MENU_NORMAL' and `GRUB_COLOR_MENU_HIGHLIGHT', respectively, before printing and restore them to old values afterwards. (run_menu): Likewise. * term/efi/console.c (grub_console_getcolor): New function. (struct grub_console_term.getcolor): New variable. * term/gfxterm.c (grub_virtual_screen_getcolor): New function. (struct grub_console_term.getcolor): New variable. * term/i386/pc/console.c (grub_console_getcolor): New function. (struct grub_console_term.getcolor): New variable. * term/ieee1275/ofconsole.c (grub_ofconsole_getcolor): New function. (struct grub_console_term.getcolor): New variable. * term/i386/pc/serial.c (grub_serial_setcolor): Remove function. (struct grub_console_term.setcolor): Remove variable. * term/i386/pc/vesafb.c (grub_virtual_screen_setcolor): Remove function. (struct grub_console_term.setcolor): Remove variable. * term/i386/pc/vga.c (grub_vga_setcolor): Remove function. (struct grub_console_term.setcolor): Remove variable. diff -x '*~' -x configure -Nurp ../grub2/include/grub/term.h ./include/grub/term.h --- ../grub2/include/grub/term.h 2007-07-22 01:32:22.000000000 +0200 +++ ./include/grub/term.h 2007-12-23 21:20:42.000000000 +0100 @@ -164,6 +164,10 @@ struct grub_term color is VGA's. */ void (*setcolor) (grub_uint8_t normal_color, grub_uint8_t highlight_color); + /* Get the normal color and the highlight color. The format of each + color is VGA's. */ + void (*getcolor) (grub_uint8_t *normal_color, grub_uint8_t *highlight_color); + /* Turn on/off the cursor. */ void (*setcursor) (int on); @@ -197,6 +201,8 @@ void EXPORT_FUNC(grub_cls) (void); void EXPORT_FUNC(grub_setcolorstate) (grub_term_color_state state); void EXPORT_FUNC(grub_setcolor) (grub_uint8_t normal_color, grub_uint8_t highlight_color); +void EXPORT_FUNC(grub_getcolor) (grub_uint8_t *normal_color, + grub_uint8_t *highlight_color); int EXPORT_FUNC(grub_setcursor) (int on); int EXPORT_FUNC(grub_getcursor) (void); void EXPORT_FUNC(grub_refresh) (void); diff -x '*~' -x configure -Nurp ../grub2/kern/term.c ./kern/term.c --- ../grub2/kern/term.c 2007-07-22 01:32:26.000000000 +0200 +++ ./kern/term.c 2007-12-23 21:08:10.000000000 +0100 @@ -230,6 +230,13 @@ grub_setcolor (grub_uint8_t normal_color (grub_cur_term->setcolor) (normal_color, highlight_color); } +void +grub_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_color) +{ + if (grub_cur_term->getcolor) + (grub_cur_term->getcolor) (normal_color, highlight_color); +} + int grub_setcursor (int on) { diff -x '*~' -x configure -Nurp ../grub2/normal/menu.c ./normal/menu.c --- ../grub2/normal/menu.c 2007-11-10 21:32:32.000000000 +0100 +++ ./normal/menu.c 2007-12-23 21:35:23.000000000 +0100 @@ -25,6 +25,9 @@ #include #include +#define GRUB_COLOR_MENU_NORMAL 0x13 +#define GRUB_COLOR_MENU_HIGHLIGHT 0x1f + static void draw_border (void) { @@ -105,7 +108,8 @@ print_entry (int y, int highlight, grub_ grub_ssize_t len; grub_uint32_t *unicode_title; grub_ssize_t i; - + grub_uint8_t normal_code, highlight_code; + title = entry ? entry->title : ""; unicode_title = grub_malloc (grub_strlen (title) * sizeof (*unicode_title)); if (! unicode_title) @@ -121,6 +125,8 @@ print_entry (int y, int highlight, grub_ return; } + grub_getcolor (&normal_code, &highlight_code); + grub_setcolor (GRUB_COLOR_MENU_NORMAL, GRUB_COLOR_MENU_HIGHLIGHT); grub_setcolorstate (highlight ? GRUB_TERM_COLOR_HIGHLIGHT : GRUB_TERM_COLOR_NORMAL); @@ -128,7 +134,7 @@ print_entry (int y, int highlight, grub_ grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y); for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0; - x < GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - GRUB_TERM_MARGIN; + x <= GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - GRUB_TERM_MARGIN; i++) { if (i < len @@ -155,6 +161,7 @@ print_entry (int y, int highlight, grub_ } grub_gotoxy (GRUB_TERM_CURSOR_X, y); + grub_setcolor (normal_code, highlight_code); grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); grub_free (unicode_title); } @@ -279,6 +286,7 @@ run_menu (grub_menu_t menu, int nested) int first, offset; unsigned long saved_time; int default_entry; + grub_uint8_t normal_code, highlight_code; first = 0; @@ -301,8 +309,11 @@ run_menu (grub_menu_t menu, int nested) refresh: grub_setcursor (0); + grub_getcolor (&normal_code, &highlight_code); + grub_setcolor (GRUB_COLOR_MENU_NORMAL, GRUB_COLOR_MENU_HIGHLIGHT); grub_menu_init_page (nested, 0); print_entries (menu, first, offset); + grub_setcolor (normal_code, highlight_code); grub_refresh (); while (1) diff -x '*~' -x configure -Nurp ../grub2/term/efi/console.c ./term/efi/console.c --- ../grub2/term/efi/console.c 2007-07-22 01:32:30.000000000 +0200 +++ ./term/efi/console.c 2007-12-23 21:42:35.000000000 +0100 @@ -260,6 +260,13 @@ grub_console_setcolor (grub_uint8_t norm } static void +grub_console_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_color) +{ + *normal_color = grub_console_normal_color; + *highlight_color = grub_console_highlight_color; +} + +static void grub_console_setcursor (int on) { grub_efi_simple_text_output_interface_t *o; @@ -283,6 +290,7 @@ static struct grub_term grub_console_ter .cls = grub_console_cls, .setcolorstate = grub_console_setcolorstate, .setcolor = grub_console_setcolor, + .getcolor = grub_console_getcolor, .setcursor = grub_console_setcursor, .flags = 0, .next = 0 diff -x '*~' -x configure -Nurp ../grub2/term/gfxterm.c ./term/gfxterm.c --- ../grub2/term/gfxterm.c 2007-07-22 01:32:30.000000000 +0200 +++ ./term/gfxterm.c 2007-12-23 21:43:40.000000000 +0100 @@ -848,6 +848,13 @@ grub_virtual_screen_setcolor (grub_uint8 } static void +grub_virtual_screen_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_color) +{ + *normal_color = virtual_screen.fg_color_setting; + *highlight_color = virtual_screen.bg_color_setting; +} + +static void grub_gfxterm_setcursor (int on) { if (virtual_screen.cursor_state != on) @@ -883,6 +890,7 @@ static struct grub_term grub_video_term .cls = grub_gfxterm_cls, .setcolorstate = grub_virtual_screen_setcolorstate, .setcolor = grub_virtual_screen_setcolor, + .getcolor = grub_virtual_screen_getcolor, .setcursor = grub_gfxterm_setcursor, .refresh = grub_gfxterm_refresh, .flags = 0, diff -x '*~' -x configure -Nurp ../grub2/term/i386/pc/console.c ./term/i386/pc/console.c --- ../grub2/term/i386/pc/console.c 2007-07-22 01:32:30.000000000 +0200 +++ ./term/i386/pc/console.c 2007-12-23 21:09:59.000000000 +0100 @@ -117,6 +117,13 @@ grub_console_setcolor (grub_uint8_t norm grub_console_highlight_color = highlight_color; } +static void +grub_console_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_color) +{ + *normal_color = grub_console_normal_color; + *highlight_color = grub_console_highlight_color; +} + static struct grub_term grub_console_term = { .name = "console", @@ -132,6 +139,7 @@ static struct grub_term grub_console_ter .cls = grub_console_cls, .setcolorstate = grub_console_setcolorstate, .setcolor = grub_console_setcolor, + .getcolor = grub_console_getcolor, .setcursor = grub_console_setcursor, .flags = 0, .next = 0 diff -x '*~' -x configure -Nurp ../grub2/term/i386/pc/serial.c ./term/i386/pc/serial.c --- ../grub2/term/i386/pc/serial.c 2007-11-10 21:23:14.000000000 +0100 +++ ./term/i386/pc/serial.c 2007-12-23 21:41:22.000000000 +0100 @@ -454,13 +454,6 @@ grub_serial_setcolorstate (const grub_te } static void -grub_serial_setcolor (grub_uint8_t normal_color __attribute__ ((unused)), - grub_uint8_t highlight_color __attribute__ ((unused))) -{ - /* FIXME */ -} - -static void grub_serial_setcursor (const int on) { if (on) @@ -483,7 +476,6 @@ static struct grub_term grub_serial_term .gotoxy = grub_serial_gotoxy, .cls = grub_serial_cls, .setcolorstate = grub_serial_setcolorstate, - .setcolor = grub_serial_setcolor, .setcursor = grub_serial_setcursor, .flags = 0, .next = 0 diff -x '*~' -x configure -Nurp ../grub2/term/i386/pc/vesafb.c ./term/i386/pc/vesafb.c --- ../grub2/term/i386/pc/vesafb.c 2007-07-22 01:32:31.000000000 +0200 +++ ./term/i386/pc/vesafb.c 2007-12-23 21:41:09.000000000 +0100 @@ -565,13 +565,6 @@ grub_virtual_screen_setcolorstate (grub_ } static void -grub_virtual_screen_setcolor (grub_uint8_t normal_color __attribute__ ((unused)), - grub_uint8_t highlight_color __attribute__ ((unused))) -{ - /* FIXME */ -} - -static void grub_vesafb_setcursor (int on) { if (virtual_screen.cursor_state != on) @@ -599,7 +592,6 @@ static struct grub_term grub_vesafb_term .gotoxy = grub_vesafb_gotoxy, .cls = grub_vesafb_cls, .setcolorstate = grub_virtual_screen_setcolorstate, - .setcolor = grub_virtual_screen_setcolor, .setcursor = grub_vesafb_setcursor, .flags = 0, .next = 0 diff -x '*~' -x configure -Nurp ../grub2/term/i386/pc/vga.c ./term/i386/pc/vga.c --- ../grub2/term/i386/pc/vga.c 2007-11-10 19:34:48.000000000 +0100 +++ ./term/i386/pc/vga.c 2007-12-23 21:40:50.000000000 +0100 @@ -460,13 +460,6 @@ grub_vga_setcolorstate (grub_term_color_ } static void -grub_vga_setcolor (grub_uint8_t normal_color __attribute__ ((unused)), - grub_uint8_t highlight_color __attribute__ ((unused))) -{ - /* FIXME */ -} - -static void grub_vga_setcursor (int on) { if (cursor_state != on) @@ -494,7 +487,6 @@ static struct grub_term grub_vga_term = .gotoxy = grub_vga_gotoxy, .cls = grub_vga_cls, .setcolorstate = grub_vga_setcolorstate, - .setcolor = grub_vga_setcolor, .setcursor = grub_vga_setcursor, .flags = 0, .next = 0 diff -x '*~' -x configure -Nurp ../grub2/term/ieee1275/ofconsole.c ./term/ieee1275/ofconsole.c --- ../grub2/term/ieee1275/ofconsole.c 2007-07-22 11:05:11.000000000 +0200 +++ ./term/ieee1275/ofconsole.c 2007-12-23 21:45:11.000000000 +0100 @@ -129,6 +129,13 @@ grub_ofconsole_setcolor (grub_uint8_t no bgcolor = highlight_color; } +static void +grub_ofconsole_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_color) +{ + *normal_color = fgcolor; + *highlight_color = bgcolor; +} + static int grub_ofconsole_readkey (int *key) { @@ -364,6 +371,7 @@ static struct grub_term grub_ofconsole_t .cls = grub_ofconsole_cls, .setcolorstate = grub_ofconsole_setcolorstate, .setcolor = grub_ofconsole_setcolor, + .getcolor = grub_ofconsole_getcolor, .setcursor = grub_ofconsole_setcursor, .refresh = grub_ofconsole_refresh, .flags = 0, --XsQoSWH+UP9D9v3l Content-Type: image/png Content-Disposition: attachment; filename="colored_menu.png" Content-Transfer-Encoding: base64 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 UWLNl6IfvgAAAABJRU5ErkJggg== --XsQoSWH+UP9D9v3l--