From 1f56d837883e066a8791af4c297bc809934e7409 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 14 Nov 2009 17:00:39 +0100 Subject: [PATCH 01/67] Initial reimport of double buffering --- ChangeLog.video | 31 ++++++ commands/minicmd.c | 1 - include/grub/video.h | 5 + include/grub/video_fb.h | 11 ++ kern/misc.c | 4 - kern/term.c | 1 + normal/cmdline.c | 10 +- term/gfxterm.c | 7 ++ video/fb/video_fb.c | 52 ++++++++++ video/i386/pc/vbe.c | 219 +++++++++++++++++++++++++++++++++++++--- 10 files changed, 318 insertions(+), 23 deletions(-) create mode 100644 ChangeLog.video diff --git a/ChangeLog.video b/ChangeLog.video new file mode 100644 index 000000000..c088b7f36 --- /dev/null +++ b/ChangeLog.video @@ -0,0 +1,31 @@ +2009-08-24 Colin D Bennett +2009-08-24 Vladimir Serbinenko + + Double buffering support. + + * commands/i386/pc/videotest.c (grub_cmd_videotest): Swap doublebuffers. + * include/grub/video.h: Update comment. + * include/grub/video_fb.h (grub_video_fb_doublebuf_update_screen_t): + New type. + (grub_video_fb_doublebuf_blit_init): New prototype. + * term/gfxterm.c (scroll_up): Support double buffering. + (grub_gfxterm_refresh): Likewise. + * video/fb/video_fb.c (doublebuf_blit_update_screen): New function. + (grub_video_fb_doublebuf_blit_init): Likewise. + * video/i386/pc/vbe.c (framebuffer): Remove 'render_target'. Add + 'front_target', 'back_target', 'offscreen_buffer', 'page_size', + 'displayed_page', 'render_page' and 'update_screen'. + (grub_video_vbe_fini): Free offscreen buffer. + (doublebuf_pageflipping_commit): New function. + (doublebuf_pageflipping_update_screen): Likewise. + (doublebuf_pageflipping_init): Likewise. + (double_buffering_init): Likewise. + (grub_video_vbe_setup): Enable doublebuffering. + (grub_video_vbe_swap_buffers): Implement. + (grub_video_vbe_set_active_render_target): Handle double buffering. + (grub_video_vbe_get_active_render_target): Likewise. + (grub_video_vbe_get_info_and_fini): Likewise. Free offscreen_buffer. + (grub_video_vbe_adapter): Use grub_video_vbe_get_active_render_target. + (grub_video_vbe_enable_double_buffering): Likewise. + (grub_video_vbe_swap_buffers): Use update_screen. + (grub_video_set_mode): Use double buffering. diff --git a/commands/minicmd.c b/commands/minicmd.c index 6c9c33a0e..7a1695838 100644 --- a/commands/minicmd.c +++ b/commands/minicmd.c @@ -315,7 +315,6 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)), grub_printf ("%s", dep->mod->name); } grub_putchar ('\n'); - grub_refresh (); return 0; } diff --git a/include/grub/video.h b/include/grub/video.h index 53fe67c4e..4f8b5cf7b 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -34,6 +34,9 @@ struct grub_video_render_target; struct grub_video_bitmap; /* Defines used to describe video mode or rendering target. */ +/* If following is set render target contains previously displayed image + after swapping buffers (otherwise it contains newly displayedd image). + */ #define GRUB_VIDEO_MODE_TYPE_PURE_TEXT 0x00000040 #define GRUB_VIDEO_MODE_TYPE_ALPHA 0x00000020 #define GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED 0x00000010 @@ -48,6 +51,8 @@ struct grub_video_bitmap; #define GRUB_VIDEO_MODE_TYPE_DEPTH_MASK 0x0000ff00 #define GRUB_VIDEO_MODE_TYPE_DEPTH_POS 8 +/* The basic render target representing the whole display. This always + renders to the back buffer when double-buffering is in use. */ #define GRUB_VIDEO_RENDER_TARGET_DISPLAY \ ((struct grub_video_render_target *) 0) diff --git a/include/grub/video_fb.h b/include/grub/video_fb.h index 17debd69f..3046a597b 100644 --- a/include/grub/video_fb.h +++ b/include/grub/video_fb.h @@ -115,4 +115,15 @@ grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **targ grub_err_t grub_video_fb_set_active_render_target (struct grub_video_fbrender_target *target); +typedef grub_err_t +(*grub_video_fb_doublebuf_update_screen_t) (struct grub_video_fbrender_target *front, + struct grub_video_fbrender_target *back); + +grub_err_t +grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **front, + struct grub_video_fbrender_target **back, + grub_video_fb_doublebuf_update_screen_t *update_screen, + struct grub_video_mode_info mode_info, + void *framebuf); + #endif /* ! GRUB_VIDEO_FB_HEADER */ diff --git a/kern/misc.c b/kern/misc.c index cacfbc753..38a5638b3 100644 --- a/kern/misc.c +++ b/kern/misc.c @@ -161,7 +161,6 @@ grub_vprintf (const char *fmt, va_list args) int ret; ret = grub_vsprintf (0, fmt, args); - grub_refresh (); return ret; } @@ -818,9 +817,6 @@ grub_vsprintf (char *str, const char *fmt, va_list args) if (str) *str = '\0'; - if (count && !str) - grub_refresh (); - return count; } diff --git a/kern/term.c b/kern/term.c index 94d5a9e1d..8c4e1e339 100644 --- a/kern/term.c +++ b/kern/term.c @@ -131,6 +131,7 @@ grub_getcharwidth (grub_uint32_t code) int grub_getkey (void) { + grub_refresh (); return (grub_cur_term_input->getkey) (); } diff --git a/normal/cmdline.c b/normal/cmdline.c index 7a5b6ec84..3816ce9d6 100644 --- a/normal/cmdline.c +++ b/normal/cmdline.c @@ -199,8 +199,6 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, xpos = (plen + lpos) % 79; ypos = ystart + (plen + lpos) / 79; grub_gotoxy (xpos, ypos); - - grub_refresh (); } void cl_print (int pos, int c) @@ -241,8 +239,6 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, cl_print (lpos - len, echo_char); cl_set_pos (); } - - grub_refresh (); } void cl_delete (unsigned len) @@ -262,8 +258,6 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, cl_print (lpos, echo_char); cl_set_pos (); } - - grub_refresh (); } plen = grub_strlen (prompt); @@ -283,6 +277,8 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, if (history && hist_used == 0) grub_history_add (buf); + grub_refresh (); + while ((key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && key != '\r') { if (readline) @@ -457,6 +453,8 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, } break; } + + grub_refresh (); } grub_putchar ('\n'); diff --git a/term/gfxterm.c b/term/gfxterm.c index 57c51cffa..1a46a867d 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -124,6 +124,8 @@ static unsigned int calculate_normal_character_width (grub_font_t font); static unsigned char calculate_character_width (struct grub_font_glyph *glyph); +static void grub_gfxterm_refresh (void); + static void set_term_color (grub_uint8_t term_color) { @@ -815,6 +817,9 @@ grub_gfxterm_cls (void) /* Mark virtual screen to be redrawn. */ dirty_region_add_virtualscreen (); + + dirty_region_redraw (); + grub_gfxterm_refresh (); } static void @@ -877,6 +882,8 @@ grub_gfxterm_refresh (void) { /* Redraw only changed regions. */ dirty_region_redraw (); + + grub_video_swap_buffers (); } static grub_err_t diff --git a/video/fb/video_fb.c b/video/fb/video_fb.c index 5f2917da6..b7323b5b7 100644 --- a/video/fb/video_fb.c +++ b/video/fb/video_fb.c @@ -66,6 +66,8 @@ grub_video_fb_init (void) grub_err_t grub_video_fb_fini (void) { + /* TODO: destroy render targets. */ + grub_free (palette); render_target = 0; palette = 0; @@ -1182,3 +1184,53 @@ grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **targ return GRUB_ERR_NONE; } + +static grub_err_t +doublebuf_blit_update_screen (struct grub_video_fbrender_target *front, + struct grub_video_fbrender_target *back) +{ + grub_memcpy (front->data, back->data, + front->mode_info.pitch * front->mode_info.height); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **front, + struct grub_video_fbrender_target **back, + grub_video_fb_doublebuf_update_screen_t *update_screen, + struct grub_video_mode_info mode_info, + void *framebuf) +{ + grub_err_t err; + int page_size = mode_info.pitch * mode_info.height; + void *offscreen_buffer; + + err = grub_video_fb_create_render_target_from_pointer (front, &mode_info, + framebuf); + if (err) + return err; + + offscreen_buffer = grub_malloc (page_size); + if (! offscreen_buffer) + { + grub_video_fb_delete_render_target (*front); + *front = 0; + return grub_errno; + } + + err = grub_video_fb_create_render_target_from_pointer (back, &mode_info, + offscreen_buffer); + + if (err) + { + grub_video_fb_delete_render_target (*front); + grub_free (offscreen_buffer); + *front = 0; + return grub_errno; + } + (*back)->is_allocated = 1; + + *update_screen = doublebuf_blit_update_screen; + + return GRUB_ERR_NONE; +} diff --git a/video/i386/pc/vbe.c b/video/i386/pc/vbe.c index 8759ba652..f2c414a99 100644 --- a/video/i386/pc/vbe.c +++ b/video/i386/pc/vbe.c @@ -36,13 +36,25 @@ static struct grub_vbe_mode_info_block active_vbe_mode_info; static struct { struct grub_video_mode_info mode_info; - struct grub_video_render_target *render_target; + struct grub_video_render_target *front_target; + struct grub_video_render_target *back_target; unsigned int bytes_per_scan_line; unsigned int bytes_per_pixel; grub_uint32_t active_vbe_mode; grub_uint8_t *ptr; int index_color_mode; + + char *offscreen_buffer; + + grub_size_t page_size; /* The size of a page in bytes. */ + + /* For page flipping strategy. */ + int displayed_page; /* The page # that is the front buffer. */ + int render_page; /* The page # that is the back buffer. */ + + /* Virtual functions. */ + grub_video_fb_doublebuf_update_screen_t update_screen; } framebuffer; static grub_uint32_t initial_vbe_mode; @@ -344,6 +356,7 @@ static grub_err_t grub_video_vbe_fini (void) { grub_vbe_status_t status; + grub_err_t err; /* Restore old video mode. */ status = grub_vbe_bios_set_mode (initial_vbe_mode, 0); @@ -355,11 +368,170 @@ grub_video_vbe_fini (void) grub_free (vbe_mode_list); vbe_mode_list = NULL; - /* TODO: destroy render targets. */ - - return grub_video_fb_fini (); + err = grub_video_fb_fini (); + grub_free (framebuffer.offscreen_buffer); + return err; } +/* + Set framebuffer render target page and display the proper page, based on + `doublebuf_state.render_page' and `doublebuf_state.displayed_page', + respectively. +*/ +static grub_err_t +doublebuf_pageflipping_commit (void) +{ + /* Tell the video adapter to display the new front page. */ + int display_start_line + = framebuffer.mode_info.height * framebuffer.displayed_page; + + grub_vbe_status_t vbe_err = + grub_vbe_bios_set_display_start (0, display_start_line); + + if (vbe_err != GRUB_VBE_STATUS_OK) + return grub_error (GRUB_ERR_IO, "couldn't commit pageflip"); + + return 0; +} + +static grub_err_t +doublebuf_pageflipping_update_screen (struct grub_video_fbrender_target *front + __attribute__ ((unused)), + struct grub_video_fbrender_target *back + __attribute__ ((unused))) +{ + int new_displayed_page; + struct grub_video_fbrender_target *target; + grub_err_t err; + + /* Swap the page numbers in the framebuffer struct. */ + new_displayed_page = framebuffer.render_page; + framebuffer.render_page = framebuffer.displayed_page; + framebuffer.displayed_page = new_displayed_page; + + err = doublebuf_pageflipping_commit (); + if (err) + { + /* Restore previous state. */ + framebuffer.render_page = framebuffer.displayed_page; + framebuffer.displayed_page = new_displayed_page; + return err; + } + + grub_memcpy (framebuffer.ptr + framebuffer.render_page + * framebuffer.page_size, framebuffer.ptr + + framebuffer.displayed_page * framebuffer.page_size, + framebuffer.page_size); + + target = framebuffer.back_target; + framebuffer.back_target = framebuffer.front_target; + framebuffer.front_target = target; + + err = grub_video_fb_get_active_render_target (&target); + if (err) + return err; + + if (target == framebuffer.back_target) + err = grub_video_fb_set_active_render_target (framebuffer.front_target); + else if (target == framebuffer.front_target) + err = grub_video_fb_set_active_render_target (framebuffer.back_target); + + return err; +} + +static grub_err_t +doublebuf_pageflipping_init (void) +{ + /* Get video RAM size in bytes. */ + grub_size_t vram_size = controller_info.total_memory << 16; + grub_err_t err; + + framebuffer.page_size = + framebuffer.mode_info.pitch * framebuffer.mode_info.height; + + if (2 * framebuffer.page_size > vram_size) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "Not enough video memory for double buffering."); + + framebuffer.displayed_page = 0; + framebuffer.render_page = 1; + + framebuffer.update_screen = doublebuf_pageflipping_update_screen; + + err = grub_video_fb_create_render_target_from_pointer (&framebuffer.front_target, &framebuffer.mode_info, framebuffer.ptr); + if (err) + return err; + + err = grub_video_fb_create_render_target_from_pointer (&framebuffer.back_target, &framebuffer.mode_info, framebuffer.ptr + framebuffer.page_size); + if (err) + { + grub_video_fb_delete_render_target (framebuffer.front_target); + return err; + } + + /* Set the framebuffer memory data pointer and display the right page. */ + err = doublebuf_pageflipping_commit (); + if (err) + { + grub_video_fb_delete_render_target (framebuffer.front_target); + grub_video_fb_delete_render_target (framebuffer.back_target); + return err; + } + + return GRUB_ERR_NONE; +} + +/* Select the best double buffering mode available. */ +static grub_err_t +double_buffering_init (unsigned int mode_type, unsigned int mode_mask) +{ + grub_err_t err; + + if (grub_video_check_mode_flag (mode_type, mode_mask, + GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED, 1)) + { + err = doublebuf_pageflipping_init (); + if (!err) + { + framebuffer.mode_info.mode_type + |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; + return GRUB_ERR_NONE; + } + + grub_errno = GRUB_ERR_NONE; + + err = grub_video_fb_doublebuf_blit_init (&framebuffer.front_target, + &framebuffer.back_target, + &framebuffer.update_screen, + framebuffer.mode_info, + framebuffer.ptr); + + if (!err) + { + framebuffer.mode_info.mode_type + |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; + return GRUB_ERR_NONE; + } + + grub_errno = GRUB_ERR_NONE; + } + + /* Fall back to no double buffering. */ + err = grub_video_fb_create_render_target_from_pointer (&framebuffer.front_target, &framebuffer.mode_info, framebuffer.ptr); + + if (err) + return err; + + framebuffer.back_target = framebuffer.front_target; + framebuffer.update_screen = 0; + + framebuffer.mode_info.mode_type &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; + + return GRUB_ERR_NONE; +} + + + static grub_err_t grub_video_vbe_setup (unsigned int width, unsigned int height, unsigned int mode_type, unsigned int mode_mask) @@ -488,12 +660,12 @@ grub_video_vbe_setup (unsigned int width, unsigned int height, framebuffer.mode_info.blit_format = grub_video_get_blit_format (&framebuffer.mode_info); - err = grub_video_fb_create_render_target_from_pointer (&framebuffer.render_target, &framebuffer.mode_info, framebuffer.ptr); - + /* Set up double buffering and targets. */ + err = double_buffering_init (mode_type, mode_mask); if (err) return err; - err = grub_video_fb_set_active_render_target (framebuffer.render_target); + err = grub_video_fb_set_active_render_target (framebuffer.back_target); if (err) return err; @@ -530,7 +702,15 @@ grub_video_vbe_set_palette (unsigned int start, unsigned int count, static grub_err_t grub_video_vbe_swap_buffers (void) { - /* TODO: Implement buffer swapping. */ + grub_err_t err; + if (!framebuffer.update_screen) + return GRUB_ERR_NONE; + + err = framebuffer.update_screen (framebuffer.front_target, + framebuffer.back_target); + if (err) + return err; + return GRUB_ERR_NONE; } @@ -538,27 +718,42 @@ static grub_err_t grub_video_vbe_set_active_render_target (struct grub_video_render_target *target) { if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY) - target = framebuffer.render_target; + target = framebuffer.back_target; return grub_video_fb_set_active_render_target (target); } +static grub_err_t +grub_video_vbe_get_active_render_target (struct grub_video_render_target **target) +{ + grub_err_t err; + err = grub_video_fb_get_active_render_target (target); + if (err) + return err; + + if (*target == framebuffer.back_target) + *target = GRUB_VIDEO_RENDER_TARGET_DISPLAY; + + return GRUB_ERR_NONE; +} + static grub_err_t grub_video_vbe_get_info_and_fini (struct grub_video_mode_info *mode_info, void **framebuf) { grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info)); - *framebuf = (char *) framebuffer.ptr; + *framebuf = (char *) framebuffer.ptr + + framebuffer.displayed_page * framebuffer.page_size; grub_free (vbe_mode_list); vbe_mode_list = NULL; grub_video_fb_fini (); + grub_free (framebuffer.offscreen_buffer); return GRUB_ERR_NONE; } - static struct grub_video_adapter grub_video_vbe_adapter = { .name = "VESA BIOS Extension Video Driver", @@ -584,7 +779,7 @@ static struct grub_video_adapter grub_video_vbe_adapter = .create_render_target = grub_video_fb_create_render_target, .delete_render_target = grub_video_fb_delete_render_target, .set_active_render_target = grub_video_vbe_set_active_render_target, - .get_active_render_target = grub_video_fb_get_active_render_target, + .get_active_render_target = grub_video_vbe_get_active_render_target, .next = 0 }; From bbe73b09954b3d82a039c6a88bd5a58114354b13 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 14 Nov 2009 17:59:11 +0100 Subject: [PATCH 02/67] Improved performance by not requiring updating swap in gfxterm --- include/grub/video.h | 5 ++-- term/gfxterm.c | 55 +++++++++++++++++++++++++++++++------------- video/i386/pc/vbe.c | 50 ++++++++++++++++++++++++++++------------ 3 files changed, 77 insertions(+), 33 deletions(-) diff --git a/include/grub/video.h b/include/grub/video.h index 4f8b5cf7b..a1882f57b 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -34,9 +34,10 @@ struct grub_video_render_target; struct grub_video_bitmap; /* Defines used to describe video mode or rendering target. */ -/* If following is set render target contains previously displayed image - after swapping buffers (otherwise it contains newly displayedd image). +/* If following is set render target contains currenly displayed image + after swapping buffers (otherwise it contains previously displayed image). */ +#define GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP 0x00000080 #define GRUB_VIDEO_MODE_TYPE_PURE_TEXT 0x00000040 #define GRUB_VIDEO_MODE_TYPE_ALPHA 0x00000020 #define GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED 0x00000010 diff --git a/term/gfxterm.c b/term/gfxterm.c index 1a46a867d..6906b77a1 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -474,8 +474,6 @@ dirty_region_redraw (void) height = dirty_region.bottom_right_y - y + 1; redraw_screen_rect (x, y, width, height); - - dirty_region_reset (); } static void @@ -566,9 +564,6 @@ scroll_up (void) { /* Remove cursor. */ draw_cursor (0); - - /* Redraw only changed regions. */ - dirty_region_redraw (); } /* Scroll text buffer with one line to up. */ @@ -584,28 +579,52 @@ scroll_up (void) i++) clear_char (&(virtual_screen.text_buffer[i])); - /* Scroll physical screen. */ - grub_video_set_active_render_target (text_layer); - color = virtual_screen.bg_color; - grub_video_scroll (color, 0, -virtual_screen.normal_char_height); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); - /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */ if (bitmap) { + /* Scroll physical screen. */ + grub_video_set_active_render_target (text_layer); + color = virtual_screen.bg_color; + grub_video_scroll (color, 0, -virtual_screen.normal_char_height); + /* Mark virtual screen to be redrawn. */ dirty_region_add_virtualscreen (); } else { - /* Clear new border area. */ - grub_video_fill_rect (color, - virtual_screen.offset_x, virtual_screen.offset_y, - virtual_screen.width, virtual_screen.normal_char_height); + int i = 1; + if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP)) + i++; + + color = virtual_screen.bg_color; + + while (i--) + { + /* Clear new border area. */ + grub_video_fill_rect (color, + virtual_screen.offset_x, + virtual_screen.offset_y, + virtual_screen.width, + virtual_screen.normal_char_height); + + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + dirty_region_redraw (); + + /* Scroll physical screen. */ + grub_video_scroll (color, 0, -virtual_screen.normal_char_height); + + if (i) + grub_video_swap_buffers (); + } + dirty_region_reset (); /* Scroll physical screen. */ + grub_video_set_active_render_target (text_layer); + color = virtual_screen.bg_color; grub_video_scroll (color, 0, -virtual_screen.normal_char_height); + /* Draw cursor if visible. */ if (virtual_screen.cursor_state) draw_cursor (1); @@ -818,7 +837,6 @@ grub_gfxterm_cls (void) /* Mark virtual screen to be redrawn. */ dirty_region_add_virtualscreen (); - dirty_region_redraw (); grub_gfxterm_refresh (); } @@ -884,6 +902,11 @@ grub_gfxterm_refresh (void) dirty_region_redraw (); grub_video_swap_buffers (); + + if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP)) + dirty_region_redraw (); + dirty_region_reset (); } static grub_err_t diff --git a/video/i386/pc/vbe.c b/video/i386/pc/vbe.c index f2c414a99..a039710a2 100644 --- a/video/i386/pc/vbe.c +++ b/video/i386/pc/vbe.c @@ -418,10 +418,11 @@ doublebuf_pageflipping_update_screen (struct grub_video_fbrender_target *front return err; } - grub_memcpy (framebuffer.ptr + framebuffer.render_page - * framebuffer.page_size, framebuffer.ptr - + framebuffer.displayed_page * framebuffer.page_size, - framebuffer.page_size); + if (framebuffer.mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP) + grub_memcpy (framebuffer.ptr + framebuffer.render_page + * framebuffer.page_size, framebuffer.ptr + + framebuffer.displayed_page * framebuffer.page_size, + framebuffer.page_size); target = framebuffer.back_target; framebuffer.back_target = framebuffer.front_target; @@ -486,19 +487,38 @@ static grub_err_t double_buffering_init (unsigned int mode_type, unsigned int mode_mask) { grub_err_t err; + int updating_swap_needed; + updating_swap_needed + = grub_video_check_mode_flag (mode_type, mode_mask, + GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP, 0); + + /* Do double buffering only if it's either requested or efficient. */ if (grub_video_check_mode_flag (mode_type, mode_mask, - GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED, 1)) + GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED, + !updating_swap_needed)) { + framebuffer.mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; + if (updating_swap_needed) + framebuffer.mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP; err = doublebuf_pageflipping_init (); if (!err) - { - framebuffer.mode_info.mode_type - |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; - return GRUB_ERR_NONE; - } + return GRUB_ERR_NONE; + + framebuffer.mode_info.mode_type + &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); grub_errno = GRUB_ERR_NONE; + } + + if (grub_video_check_mode_flag (mode_type, mode_mask, + GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED, + 0)) + { + framebuffer.mode_info.mode_type + |= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); err = grub_video_fb_doublebuf_blit_init (&framebuffer.front_target, &framebuffer.back_target, @@ -507,11 +527,11 @@ double_buffering_init (unsigned int mode_type, unsigned int mode_mask) framebuffer.ptr); if (!err) - { - framebuffer.mode_info.mode_type - |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; - return GRUB_ERR_NONE; - } + return GRUB_ERR_NONE; + + framebuffer.mode_info.mode_type + &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); grub_errno = GRUB_ERR_NONE; } From 85536ab717ff52e6d0b6e146811b923f367e1853 Mon Sep 17 00:00:00 2001 From: Colin D Bennet Date: Sat, 14 Nov 2009 23:11:55 +0100 Subject: [PATCH 03/67] 2009-11-14 Colin D Bennet Trigonometry support. * include/grub/trig.h: New file. * lib/trig.c: Likewise. * maintainance/gentrigtables.py: Likewise. * conf/common.rmk (pkglib_MODULES): Add trig.mod. (trig_mod_SOURCES): New variable. (trig_mod_CFLAGS): Likewise. (trig_mod_LDFLAGS): Likewise. --- conf/common.rmk | 6 +++ include/grub/trig.h | 44 +++++++++++++++++++ lib/trig.c | 83 +++++++++++++++++++++++++++++++++++ maintainance/gentrigtables.py | 58 ++++++++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 include/grub/trig.h create mode 100644 lib/trig.c create mode 100644 maintainance/gentrigtables.py diff --git a/conf/common.rmk b/conf/common.rmk index 3dddeb66d..4ec0dab1e 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -638,6 +638,12 @@ xnu_uuid_mod_SOURCES = commands/xnu_uuid.c xnu_uuid_mod_CFLAGS = $(COMMON_CFLAGS) xnu_uuid_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For trig.mod. +pkglib_MODULES += trig.mod +trig_mod_SOURCES = lib/trig.c +trig_mod_CFLAGS = $(COMMON_CFLAGS) +trig_mod_LDFLAGS = $(COMMON_LDFLAGS) + pkglib_MODULES += setjmp.mod setjmp_mod_SOURCES = lib/$(target_cpu)/setjmp.S setjmp_mod_ASFLAGS = $(COMMON_ASFLAGS) diff --git a/include/grub/trig.h b/include/grub/trig.h new file mode 100644 index 000000000..2512a5f07 --- /dev/null +++ b/include/grub/trig.h @@ -0,0 +1,44 @@ +/* trig.h - Trigonometric function support. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_TRIG_HEADER +#define GRUB_TRIG_HEADER 1 + +#define GRUB_TRIG_ANGLE_MAX 256 +#define GRUB_TRIG_ANGLE_MASK 255 +#define GRUB_TRIG_FRACTION_SCALE 16384 + +extern short grub_trig_sintab[]; +extern short grub_trig_costab[]; + +static __inline int +grub_sin (int x) +{ + x &= GRUB_TRIG_ANGLE_MASK; + return grub_trig_sintab[x]; +} + +static __inline int +grub_cos (int x) +{ + x &= GRUB_TRIG_ANGLE_MASK; + return grub_trig_costab[x]; +} + +#endif /* ! GRUB_TRIG_HEADER */ diff --git a/lib/trig.c b/lib/trig.c new file mode 100644 index 000000000..e36aa38ef --- /dev/null +++ b/lib/trig.c @@ -0,0 +1,83 @@ +/* trig.c - Trigonometric table definitions. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include + +/* These tables were generated with `gentrigtables.py'. */ + +short grub_trig_sintab[] = +{ + 0,402,804,1205,1606,2006,2404,2801,3196,3590, + 3981,4370,4756,5139,5520,5897,6270,6639,7005,7366, + 7723,8076,8423,8765,9102,9434,9760,10080,10394,10702, + 11003,11297,11585,11866,12140,12406,12665,12916,13160,13395, + 13623,13842,14053,14256,14449,14635,14811,14978,15137,15286, + 15426,15557,15679,15791,15893,15986,16069,16143,16207,16261, + 16305,16340,16364,16379,16384,16379,16364,16340,16305,16261, + 16207,16143,16069,15986,15893,15791,15679,15557,15426,15286, + 15137,14978,14811,14635,14449,14256,14053,13842,13623,13395, + 13160,12916,12665,12406,12140,11866,11585,11297,11003,10702, + 10394,10080,9760,9434,9102,8765,8423,8076,7723,7366, + 7005,6639,6270,5897,5520,5139,4756,4370,3981,3590, + 3196,2801,2404,2006,1606,1205,804,402,0,-402, + -804,-1205,-1606,-2006,-2404,-2801,-3196,-3590,-3981,-4370, + -4756,-5139,-5520,-5897,-6270,-6639,-7005,-7366,-7723,-8076, + -8423,-8765,-9102,-9434,-9760,-10080,-10394,-10702,-11003,-11297, + -11585,-11866,-12140,-12406,-12665,-12916,-13160,-13395,-13623,-13842, + -14053,-14256,-14449,-14635,-14811,-14978,-15137,-15286,-15426,-15557, + -15679,-15791,-15893,-15986,-16069,-16143,-16207,-16261,-16305,-16340, + -16364,-16379,-16384,-16379,-16364,-16340,-16305,-16261,-16207,-16143, + -16069,-15986,-15893,-15791,-15679,-15557,-15426,-15286,-15137,-14978, + -14811,-14635,-14449,-14256,-14053,-13842,-13623,-13395,-13160,-12916, + -12665,-12406,-12140,-11866,-11585,-11297,-11003,-10702,-10394,-10080, + -9760,-9434,-9102,-8765,-8423,-8076,-7723,-7366,-7005,-6639, + -6270,-5897,-5520,-5139,-4756,-4370,-3981,-3590,-3196,-2801, + -2404,-2006,-1606,-1205,-804,-402 +}; + +short grub_trig_costab[] = +{ + 16384,16379,16364,16340,16305,16261,16207,16143,16069,15986, + 15893,15791,15679,15557,15426,15286,15137,14978,14811,14635, + 14449,14256,14053,13842,13623,13395,13160,12916,12665,12406, + 12140,11866,11585,11297,11003,10702,10394,10080,9760,9434, + 9102,8765,8423,8076,7723,7366,7005,6639,6270,5897, + 5520,5139,4756,4370,3981,3590,3196,2801,2404,2006, + 1606,1205,804,402,0,-402,-804,-1205,-1606,-2006, + -2404,-2801,-3196,-3590,-3981,-4370,-4756,-5139,-5520,-5897, + -6270,-6639,-7005,-7366,-7723,-8076,-8423,-8765,-9102,-9434, + -9760,-10080,-10394,-10702,-11003,-11297,-11585,-11866,-12140,-12406, + -12665,-12916,-13160,-13395,-13623,-13842,-14053,-14256,-14449,-14635, + -14811,-14978,-15137,-15286,-15426,-15557,-15679,-15791,-15893,-15986, + -16069,-16143,-16207,-16261,-16305,-16340,-16364,-16379,-16384,-16379, + -16364,-16340,-16305,-16261,-16207,-16143,-16069,-15986,-15893,-15791, + -15679,-15557,-15426,-15286,-15137,-14978,-14811,-14635,-14449,-14256, + -14053,-13842,-13623,-13395,-13160,-12916,-12665,-12406,-12140,-11866, + -11585,-11297,-11003,-10702,-10394,-10080,-9760,-9434,-9102,-8765, + -8423,-8076,-7723,-7366,-7005,-6639,-6270,-5897,-5520,-5139, + -4756,-4370,-3981,-3590,-3196,-2801,-2404,-2006,-1606,-1205, + -804,-402,0,402,804,1205,1606,2006,2404,2801, + 3196,3590,3981,4370,4756,5139,5520,5897,6270,6639, + 7005,7366,7723,8076,8423,8765,9102,9434,9760,10080, + 10394,10702,11003,11297,11585,11866,12140,12406,12665,12916, + 13160,13395,13623,13842,14053,14256,14449,14635,14811,14978, + 15137,15286,15426,15557,15679,15791,15893,15986,16069,16143, + 16207,16261,16305,16340,16364,16379 +}; + diff --git a/maintainance/gentrigtables.py b/maintainance/gentrigtables.py new file mode 100644 index 000000000..7c069f833 --- /dev/null +++ b/maintainance/gentrigtables.py @@ -0,0 +1,58 @@ +#!/usr/bin/python +# Script to generate trigonometric function tables. +# +# GRUB -- GRand Unified Bootloader +# Copyright (C) 2008 Free Software Foundation, Inc. +# +# GRUB 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. +# +# GRUB 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 GRUB. If not, see . + +from math import * +from sys import stdout + +def write(x): + stdout.write(x) + +def writeTable(arr, name): + indent = ' ' * 4 + write("short ") + write(name) + write("[] =\n{\n") + write(indent) + for i in range(len(arr)): + if i != 0: + write(",") + if i % 10 == 0: + write("\n") + write(indent) + write("%d" % arr[i]) + write("\n};\n") + +def main(): + sintab = [] + costab = [] + for i in range(256): + # Convert to an angle in 1/256 of a circle. + x = i * 2 * pi / 256 + sintab.append(int(round(sin(x) * 16384))) + costab.append(int(round(cos(x) * 16384))) + + write("#define TRIG_ANGLE_MAX 256\n") + write("#define TRIG_FRACTION_SCALE 16384\n") + writeTable(sintab, "sintab") + writeTable(costab, "costab") + +if __name__ == "__main__": + main() + +# vim:ai et sw=4 ts=4 From c51a5caeab7dcbc9f9f49b923543bbb1645de70e Mon Sep 17 00:00:00 2001 From: Colin D Bennet Date: Sun, 15 Nov 2009 00:03:03 +0100 Subject: [PATCH 04/67] 2009-11-14 Colin D Bennet 2009-11-14 Vladimir Serbinenko Support for gfxterm in a window. * include/grub/gfxterm.h: New file. * include/grub/video.h (struct grub_video_rect): New declaration. (grub_video_rect_t): Likewise. * term/gfxterm.c (struct grub_gfxterm_window): New type. (refcount): New variable. (render_target): Likewise. (window): Likewise. (repaint_callback): Likewise. (grub_virtual_screen_setup): Use 'render_target'. (init_window): New function. (grub_gfxterm_init_window): Likewise. (grub_gfxterm_init): Check reference counter. Use init_window. (destroy_window): New function. (grub_gfxterm_destroy_window): Likewise. (grub_gfxterm_fini): Check reference counter. Use destroy_window. (redraw_screen_rect): Restore viewport. Use 'render_target' and 'window'. Call 'repaint_callback'. (write_char): Use 'render_target'. (draw_cursor): Likewise. (scroll_up): Restore viewport. Use 'render_target' and 'window'. Call 'repaint_callback'. (grub_gfxterm_cls): Likewise. (grub_gfxterm_refresh): Use 'window'. (grub_gfxterm_set_repaint_callback): New function. (grub_gfxterm_background_image_cmd): Use 'window'. (grub_gfxterm_get_term): New function. (GRUB_MOD_INIT(term_gfxterm)): Set 'refcount' to 0. Also-By: Vladimir Serbinenko --- ChangeLog.gfxtermwindow | 36 +++++++ include/grub/gfxterm.h | 42 ++++++++ include/grub/video.h | 10 ++ term/gfxterm.c | 226 ++++++++++++++++++++++++++++++++-------- 4 files changed, 269 insertions(+), 45 deletions(-) create mode 100644 ChangeLog.gfxtermwindow create mode 100644 include/grub/gfxterm.h diff --git a/ChangeLog.gfxtermwindow b/ChangeLog.gfxtermwindow new file mode 100644 index 000000000..d23038ba7 --- /dev/null +++ b/ChangeLog.gfxtermwindow @@ -0,0 +1,36 @@ +2009-11-14 Colin D Bennet +2009-11-14 Vladimir Serbinenko + + Support for gfxterm in a window. + + * include/grub/gfxterm.h: New file. + * include/grub/video.h (struct grub_video_rect): New declaration. + (grub_video_rect_t): Likewise. + * term/gfxterm.c (struct grub_gfxterm_window): New type. + (refcount): New variable. + (render_target): Likewise. + (window): Likewise. + (repaint_callback): Likewise. + (grub_virtual_screen_setup): Use 'render_target'. + (init_window): New function. + (grub_gfxterm_init_window): Likewise. + (grub_gfxterm_init): Check reference counter. + Use init_window. + (destroy_window): New function. + (grub_gfxterm_destroy_window): Likewise. + (grub_gfxterm_fini): Check reference counter. + Use destroy_window. + (redraw_screen_rect): Restore viewport. + Use 'render_target' and 'window'. + Call 'repaint_callback'. + (write_char): Use 'render_target'. + (draw_cursor): Likewise. + (scroll_up): Restore viewport. + Use 'render_target' and 'window'. + Call 'repaint_callback'. + (grub_gfxterm_cls): Likewise. + (grub_gfxterm_refresh): Use 'window'. + (grub_gfxterm_set_repaint_callback): New function. + (grub_gfxterm_background_image_cmd): Use 'window'. + (grub_gfxterm_get_term): New function. + (GRUB_MOD_INIT(term_gfxterm)): Set 'refcount' to 0. diff --git a/include/grub/gfxterm.h b/include/grub/gfxterm.h new file mode 100644 index 000000000..e607bd5e1 --- /dev/null +++ b/include/grub/gfxterm.h @@ -0,0 +1,42 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_GFXTERM_HEADER +#define GRUB_GFXTERM_HEADER 1 + +#include +#include +#include +#include + +grub_err_t +grub_gfxterm_init_window (struct grub_video_render_target *target, + int x, int y, int width, int height, + int double_repaint, + const char *font_name, int border_width); + +void grub_gfxterm_destroy_window (void); + +const struct grub_term_output *grub_gfxterm_get_term (void); + +typedef void (*grub_gfxterm_repaint_callback_t)(int x, int y, + int width, int height); + +void grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func); + +#endif /* ! GRUB_GFXTERM_HEADER */ diff --git a/include/grub/video.h b/include/grub/video.h index a1882f57b..833df04c8 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -157,6 +157,16 @@ struct grub_video_mode_info grub_uint8_t fg_alpha; }; +/* A 2D rectangle type. */ +struct grub_video_rect +{ + int x; + int y; + int width; + int height; +}; +typedef struct grub_video_rect grub_video_rect_t; + struct grub_video_palette_data { grub_uint8_t r; /* Red color value (0-255). */ diff --git a/term/gfxterm.c b/term/gfxterm.c index 62cf98416..3fc151c8b 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -103,9 +104,28 @@ struct grub_virtual_screen struct grub_colored_char *text_buffer; }; -static struct grub_virtual_screen virtual_screen; +struct grub_gfxterm_window +{ + unsigned x; + unsigned y; + unsigned width; + unsigned height; + int double_repaint; +}; + +static int refcount; +static struct grub_video_render_target *render_target; +static struct grub_gfxterm_window window; +static struct grub_virtual_screen virtual_screen; +static grub_gfxterm_repaint_callback_t repaint_callback; + +static grub_err_t init_window (struct grub_video_render_target *target, + int x, int y, int width, int height, + int double_repaint, + const char *font_name, int border_width); + +static void destroy_window (void); -static struct grub_video_mode_info mode_info; static struct grub_video_render_target *text_layer; @@ -239,7 +259,7 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, set_term_color (virtual_screen.term_color); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + grub_video_set_active_render_target (render_target); /* Clear out text buffer. */ for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++) @@ -248,21 +268,71 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, return grub_errno; } +static grub_err_t +init_window (struct grub_video_render_target *target, + int x, int y, int width, int height, int double_repaint, + const char *font_name, int border_width) +{ + /* Clean up any prior instance. */ + destroy_window (); + + /* Set the render target. */ + render_target = target; + + /* Create virtual screen. */ + if (grub_virtual_screen_setup (border_width, border_width, + width - 2 * border_width, + height - 2 * border_width, + font_name) + != GRUB_ERR_NONE) + { + return grub_errno; + } + + /* Set window bounds. */ + window.x = x; + window.y = y; + window.width = width; + window.height = height; + window.double_repaint = double_repaint; + + /* Mark whole window as dirty. */ + dirty_region_reset (); + dirty_region_add (0, 0, width, height); + + return grub_errno; +} + +grub_err_t +grub_gfxterm_init_window (struct grub_video_render_target *target, + int x, int y, int width, int height, + int double_repaint, + const char *font_name, int border_width) +{ + if (refcount++ == 0) + init_window (target, x, y, width, height, double_repaint, + font_name, border_width); + return grub_errno; +} + static grub_err_t grub_gfxterm_init (void) { - char *font_name; - char *modevar; + const char *font_name; + const char *modevar; + struct grub_video_mode_info mode_info; char *tmp; - grub_video_color_t color; - int width; - int height; grub_err_t err; - /* Select the font to use. */ + /* If gfxterm has already been initialized by calling the init_window + function, then leave it alone when it is set as the current terminal. */ + if (refcount++ != 0) + return GRUB_ERR_NONE; + + /* Select the font to use. */ font_name = grub_env_get ("gfxterm_font"); if (! font_name) - font_name = ""; /* Allow fallback to any font. */ + font_name = ""; /* Allow fallback to any font. */ /* Parse gfxmode environment variable if set. */ modevar = grub_env_get ("gfxmode"); @@ -273,6 +343,8 @@ grub_gfxterm_init (void) { tmp = grub_malloc (grub_strlen (modevar) + sizeof (DEFAULT_VIDEO_MODE) + 1); + if (! tmp) + return grub_errno; grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar); err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); @@ -292,27 +364,29 @@ grub_gfxterm_init (void) grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height); bitmap = 0; - /* Leave borders for virtual screen. */ - width = mode_info.width - (2 * DEFAULT_BORDER_WIDTH); - height = mode_info.height - (2 * DEFAULT_BORDER_WIDTH); + /* Select the font to use. */ + font_name = grub_env_get ("gfxterm_font"); + if (! font_name) + font_name = ""; /* Allow fallback to any font. */ - /* Create virtual screen. */ - if (grub_virtual_screen_setup (DEFAULT_BORDER_WIDTH, DEFAULT_BORDER_WIDTH, - width, height, font_name) != GRUB_ERR_NONE) + /* Leave borders for virtual screen. */ + if (init_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, + 0, 0, mode_info.width, mode_info.height, + mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + && !(mode_info.mode_type + & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP), + font_name, + DEFAULT_BORDER_WIDTH) != GRUB_ERR_NONE) { grub_video_restore (); return grub_errno; } - /* Mark whole screen as dirty. */ - dirty_region_reset (); - dirty_region_add (0, 0, mode_info.width, mode_info.height); - - return (grub_errno = GRUB_ERR_NONE); + return grub_errno; } -static grub_err_t -grub_gfxterm_fini (void) +static void +destroy_window (void) { if (bitmap) { @@ -320,11 +394,30 @@ grub_gfxterm_fini (void) bitmap = 0; } + repaint_callback = 0; grub_virtual_screen_free (); +} - grub_video_restore (); +void +grub_gfxterm_destroy_window (void) +{ + if (--refcount == 0) + destroy_window (); +} - return GRUB_ERR_NONE; +static grub_err_t +grub_gfxterm_fini (void) +{ + /* Don't destroy an explicitly initialized terminal instance when it is + unset as the current terminal. */ + if (--refcount == 0) + { + destroy_window (); + grub_video_restore (); + } + + /* Clear error state. */ + return (grub_errno = GRUB_ERR_NONE); } static void @@ -332,9 +425,15 @@ redraw_screen_rect (unsigned int x, unsigned int y, unsigned int width, unsigned int height) { grub_video_color_t color; + grub_video_rect_t saved_view; - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); - + grub_video_set_active_render_target (render_target); + /* Save viewport and set it to our window. */ + grub_video_get_viewport ((unsigned *) &saved_view.x, + (unsigned *) &saved_view.y, + (unsigned *) &saved_view.width, + (unsigned *) &saved_view.height); + grub_video_set_viewport (window.x, window.y, window.width, window.height); if (bitmap) { @@ -401,6 +500,14 @@ redraw_screen_rect (unsigned int x, unsigned int y, y - virtual_screen.offset_y, width, height); } + + /* Restore saved viewport. */ + grub_video_set_viewport (saved_view.x, saved_view.y, + saved_view.width, saved_view.height); + grub_video_set_active_render_target (render_target); + + if (repaint_callback) + repaint_callback (x, y, width, height); } static void @@ -515,7 +622,7 @@ write_char (void) grub_video_set_active_render_target (text_layer); grub_video_fill_rect (bgcolor, x, y, width, height); grub_font_draw_glyph (glyph, color, x, y + ascent); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + grub_video_set_active_render_target (render_target); /* Mark character to be drawn. */ dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y, @@ -546,7 +653,7 @@ draw_cursor (int show) /* Render cursor to text layer. */ grub_video_set_active_render_target (text_layer); grub_video_fill_rect (color, x, y, width, height); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + grub_video_set_active_render_target (render_target); /* Mark cursor to be redrawn. */ dirty_region_add (virtual_screen.offset_x + x, @@ -594,10 +701,18 @@ scroll_up (void) } else { - int i = 1; - if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED - && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP)) - i++; + grub_video_rect_t saved_view; + int i; + + grub_video_set_active_render_target (render_target); + /* Save viewport and set it to our window. */ + grub_video_get_viewport ((unsigned *) &saved_view.x, + (unsigned *) &saved_view.y, + (unsigned *) &saved_view.width, + (unsigned *) &saved_view.height); + grub_video_set_viewport (window.x, window.y, window.width, window.height); + + i = window.double_repaint ? 2 : 1; color = virtual_screen.bg_color; @@ -610,7 +725,7 @@ scroll_up (void) virtual_screen.width, virtual_screen.normal_char_height); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + grub_video_set_active_render_target (render_target); dirty_region_redraw (); /* Scroll physical screen. */ @@ -626,11 +741,18 @@ scroll_up (void) color = virtual_screen.bg_color; grub_video_scroll (color, 0, -virtual_screen.normal_char_height); + /* Restore saved viewport. */ + grub_video_set_viewport (saved_view.x, saved_view.y, + saved_view.width, saved_view.height); + grub_video_set_active_render_target (render_target); /* Draw cursor if visible. */ if (virtual_screen.cursor_state) draw_cursor (1); } + + if (repaint_callback) + repaint_callback (window.x, window.y, window.width, window.height); } static void @@ -833,8 +955,9 @@ grub_gfxterm_cls (void) /* Clear text layer. */ grub_video_set_active_render_target (text_layer); color = virtual_screen.bg_color; - grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + grub_video_fill_rect (color, 0, 0, + virtual_screen.width, virtual_screen.height); + grub_video_set_active_render_target (render_target); /* Mark virtual screen to be redrawn. */ dirty_region_add_virtualscreen (); @@ -905,12 +1028,17 @@ grub_gfxterm_refresh (void) grub_video_swap_buffers (); - if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED - && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP)) + if (window.double_repaint) dirty_region_redraw (); dirty_region_reset (); } +void +grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func) +{ + repaint_callback = func; +} + /* Option array indices. */ #define BACKGROUND_CMD_ARGINDEX_MODE 0 @@ -940,7 +1068,7 @@ grub_gfxterm_background_image_cmd (grub_extcmd_t cmd __attribute__ ((unused)), /* Mark whole screen as dirty. */ dirty_region_reset (); - dirty_region_add (0, 0, mode_info.width, mode_info.height); + dirty_region_add (0, 0, window.width, window.height); } /* If filename was provided, try to load that. */ @@ -956,13 +1084,13 @@ grub_gfxterm_background_image_cmd (grub_extcmd_t cmd __attribute__ ((unused)), || grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_MODE].arg, "stretch") == 0) { - if (mode_info.width != grub_video_bitmap_get_width (bitmap) - || mode_info.height != grub_video_bitmap_get_height (bitmap)) + if (window.width != grub_video_bitmap_get_width (bitmap) + || window.height != grub_video_bitmap_get_height (bitmap)) { struct grub_video_bitmap *scaled_bitmap; grub_video_bitmap_create_scaled (&scaled_bitmap, - mode_info.width, - mode_info.height, + window.width, + window.height, bitmap, GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); if (grub_errno == GRUB_ERR_NONE) @@ -979,11 +1107,11 @@ grub_gfxterm_background_image_cmd (grub_extcmd_t cmd __attribute__ ((unused)), { /* Determine bitmap dimensions. */ bitmap_width = grub_video_bitmap_get_width (bitmap); - bitmap_height = grub_video_bitmap_get_width (bitmap); + bitmap_height = grub_video_bitmap_get_height (bitmap); /* Mark whole screen as dirty. */ dirty_region_reset (); - dirty_region_add (0, 0, mode_info.width, mode_info.height); + dirty_region_add (0, 0, window.width, window.height); } } @@ -1012,10 +1140,18 @@ static struct grub_term_output grub_video_term = .next = 0 }; +const struct grub_term_output * +grub_gfxterm_get_term (void) +{ + return &grub_video_term; +} + static grub_extcmd_t background_image_cmd_handle; GRUB_MOD_INIT(term_gfxterm) { + refcount = 0; + grub_term_register_output ("gfxterm", &grub_video_term); background_image_cmd_handle = grub_register_extcmd ("background_image", From 927d0134c72432fd1cdff4591cc5eee6a509d60f Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Nov 2009 10:28:42 +0100 Subject: [PATCH 05/67] SDL --- Makefile.in | 2 + conf/i386-pc.rmk | 6 ++ configure.ac | 34 ++++++ util/sdl.c | 263 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 305 insertions(+) create mode 100644 util/sdl.c diff --git a/Makefile.in b/Makefile.in index 7706cd26b..f2b4e7fc0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -107,12 +107,14 @@ endif AWK = @AWK@ LIBCURSES = @LIBCURSES@ LIBUSB = @LIBUSB@ +LIBSDL = @LIBSDL@ YACC = @YACC@ UNIFONT_BDF = @UNIFONT_BDF@ # Options. enable_grub_emu = @enable_grub_emu@ enable_grub_emu_usb = @enable_grub_emu_usb@ +enable_grub_emu_sdl = @enable_grub_emu_sdl@ enable_grub_fstest = @enable_grub_fstest@ enable_grub_pe2elf = @enable_grub_pe2elf@ enable_grub_mkfont = @enable_grub_mkfont@ diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index e1688ccd5..382c45ca3 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -153,6 +153,12 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \ fs/befs.c fs/befs_be.c fs/tar.c \ \ + video/video.c video/fb/video_fb.c video/fb/fbblit.c \ + video/fb/fbfill.c video/fb/fbutil.c commands/videotest.c \ + video/bitmap.c video/readers/tga.c video/readers/jpeg.c \ + video/readers/png.c font/font_cmd.c font/font.c term/gfxterm.c \ + io/bufio.c \ + \ util/console.c util/hostfs.c util/grub-emu.c util/misc.c \ util/hostdisk.c util/getroot.c \ \ diff --git a/configure.ac b/configure.ac index 587f2118d..d2b281639 100644 --- a/configure.ac +++ b/configure.ac @@ -519,6 +519,10 @@ if test x"$enable_grub_emu" = xno ; then grub_emu_excuse="explicitly disabled" fi +AC_ARG_ENABLE([grub-emu-sdl], + [AS_HELP_STRING([--enable-grub-emu-sdl], + [build and install the `grub-emu' debugging utility with SDL support (default=guessed)])]) + [# Check for curses libraries.] [if [ x"$grub_emu_excuse" = x ]; then ] AC_CHECK_LIB([ncurses], [wgetch], [LIBCURSES="-lncurses"], @@ -567,6 +571,31 @@ enable_grub_emu_usb=no fi AC_SUBST([enable_grub_emu]) + +if test x"$enable_grub_emu_sdl" = xno ; then + grub_emu_sdl_excuse="explicitely disabled" +fi +[if [ x"$grub_emu_sdl_excuse" = x ]; then + # Check for libSDL libraries.] +AC_CHECK_LIB([SDL], [SDL_Init], [LIBSDL="-lSDL"], + [grub_emu_sdl_excuse=["libSDL libraries are required to build \`grub-emu' with SDL support"]]) + AC_SUBST([LIBSDL]) +[fi] +[if [ x"$grub_emu_sdl_excuse" = x ]; then + # Check for headers.] + AC_CHECK_HEADERS([SDL/SDL.h], [], + [grub_emu_sdl_excuse=["libSDL header file is required to build \`grub-emu' with SDL support"]]) +[fi] +if test x"enable_grub_emu_sdl" = xyes && test x"$grub_emu_sdl_excuse" != x ; then + AC_MSG_ERROR([SDL support for grub-emu was explicitely requested but can't be compiled]) +fi +if test x"$grub_emu_sdl_excuse" = x ; then +enable_grub_emu_sdl=yes +else +enable_grub_emu_sdl=no +fi + +AC_SUBST([enable_grub_emu_sdl]) AC_SUBST([enable_grub_emu_usb]) AC_ARG_ENABLE([grub-fstest], @@ -641,6 +670,11 @@ echo USB support for grub-emu: Yes else echo USB support for grub-emu: No "($grub_emu_usb_excuse)" fi +if [ x"$grub_emu_sdl_excuse" = x ]; then +echo SDL support for grub-emu: Yes +else +echo SDL support for grub-emu: No "($grub_emu_sdl_excuse)" +fi if [ x"$enable_mm_debug" = xyes ]; then echo With memory debugging: Yes else diff --git a/util/sdl.c b/util/sdl.c new file mode 100644 index 000000000..a5a310518 --- /dev/null +++ b/util/sdl.c @@ -0,0 +1,263 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#define grub_video_render_target grub_video_fbrender_target + +#include +#include +#include +#include +#include +#include +#include +#include + +static SDL_Surface *window = 0; +static struct grub_video_render_target *sdl_render_target; +static struct grub_video_mode_info mode_info; + +static grub_err_t +grub_video_sdl_set_palette (unsigned int start, unsigned int count, + struct grub_video_palette_data *palette_data); + +static grub_err_t +grub_video_sdl_init (void) +{ + window = 0; + + if (SDL_Init (SDL_INIT_VIDEO) < 0) + return grub_error (GRUB_ERR_BAD_DEVICE, "Couldn't init SDL: %s", + SDL_GetError ()); + + grub_memset (&mode_info, 0, sizeof (mode_info)); + + return grub_video_fb_init (); +} + +static grub_err_t +grub_video_sdl_fini (void) +{ + SDL_Quit (); + window = 0; + + grub_memset (&mode_info, 0, sizeof (mode_info)); + + return grub_video_fb_fini (); +} + +static inline unsigned int +get_mask_size (grub_uint32_t mask) +{ + unsigned i; + for (i = 0; mask > 1U << i; i++); + return i; +} + +static grub_err_t +grub_video_sdl_setup (unsigned int width, unsigned int height, + unsigned int mode_type, unsigned int mode_mask) +{ + int depth; + int flags = 0; + grub_err_t err; + + /* Decode depth from mode_type. If it is zero, then autodetect. */ + depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK) + >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS; + + if (depth == 0) + depth = 32; + + if (width == 0 && height == 0) + { + width = 800; + height = 600; + } + + if ((mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED) + || !(mode_mask & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED)) + flags |= SDL_DOUBLEBUF; + + window = SDL_SetVideoMode (width, height, depth, flags | SDL_HWSURFACE); + if (! window) + window = SDL_SetVideoMode (width, height, depth, flags | SDL_SWSURFACE); + if (! window) + return grub_error (GRUB_ERR_BAD_DEVICE, "Couldn't open window: %s", + SDL_GetError ()); + + grub_memset (&sdl_render_target, 0, sizeof (sdl_render_target)); + + mode_info.width = window->w; + mode_info.height = window->h; + mode_info.mode_type = 0; + if (window->flags & SDL_DOUBLEBUF) + mode_info.mode_type + |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; + if (window->format->palette) + mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + else + mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_RGB; + + mode_info.bpp = window->format->BitsPerPixel; + mode_info.bytes_per_pixel = window->format->BytesPerPixel; + mode_info.pitch = window->pitch; + + /* In index color mode, number of colors. In RGB mode this is 256. */ + if (window->format->palette) + mode_info.number_of_colors + = 1 << window->format->BitsPerPixel; + else + mode_info.number_of_colors = 256; + + if (! window->format->palette) + { + mode_info.red_mask_size + = get_mask_size (window->format->Rmask >> window->format->Rshift); + mode_info.red_field_pos = window->format->Rshift; + mode_info.green_mask_size + = get_mask_size (window->format->Gmask >> window->format->Gshift); + mode_info.green_field_pos = window->format->Gshift; + mode_info.blue_mask_size + = get_mask_size (window->format->Bmask >> window->format->Bshift); + mode_info.blue_field_pos = window->format->Bshift; + mode_info.reserved_mask_size + = get_mask_size (window->format->Amask >> window->format->Ashift); + mode_info.reserved_field_pos = window->format->Ashift; + mode_info.blit_format + = grub_video_get_blit_format (&mode_info); + } + + err = grub_video_fb_create_render_target_from_pointer (&sdl_render_target, + &mode_info, + window->pixels); + if (err) + return err; + + /* Copy default palette to initialize emulated palette. */ + grub_video_sdl_set_palette (0, (sizeof (grub_video_fbstd_colors) + / sizeof (grub_video_fbstd_colors[0])), + grub_video_fbstd_colors); + + /* Reset render target to SDL one. */ + return grub_video_fb_set_active_render_target (sdl_render_target); +} + +static grub_err_t +grub_video_sdl_set_palette (unsigned int start, unsigned int count, + struct grub_video_palette_data *palette_data) +{ + unsigned i; + if (window->format->palette) + { + SDL_Color *tmp = grub_malloc (count * sizeof (tmp[0])); + for (i = 0; i < count; i++) + { + tmp[i].r = palette_data[i].r; + tmp[i].g = palette_data[i].g; + tmp[i].b = palette_data[i].b; + tmp[i].unused = palette_data[i].a; + } + SDL_SetColors (window, tmp, start, count); + grub_free (tmp); + } + + return grub_video_fb_set_palette (start, count, palette_data); +} + +grub_err_t +grub_video_sdl_set_viewport (unsigned int x, unsigned int y, + unsigned int width, unsigned int height) +{ + /* Make sure viewport is withing screen dimensions. If viewport was set + to be out of the region, mark its size as zero. */ + if (x > (unsigned) window->w) + { + x = 0; + width = 0; + } + + if (y > (unsigned) window->h) + { + y = 0; + height = 0; + } + + if (x + width > (unsigned) window->w) + width = window->w - x; + + if (y + height > (unsigned) window->h) + height = window->h - y; + return grub_video_fb_set_viewport (x, y, width, height); +} + +static grub_err_t +grub_video_sdl_swap_buffers (void) +{ + if (SDL_Flip (window) < 0) + return grub_error (GRUB_ERR_BAD_DEVICE, "couldn't swap buffers: %s", + SDL_GetError ()); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_sdl_set_active_render_target (struct grub_video_render_target *target) +{ + if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY) + return grub_video_fb_set_active_render_target (sdl_render_target); + + return grub_video_fb_set_active_render_target (target); +} + +static struct grub_video_adapter grub_video_sdl_adapter = + { + .name = "SDL Video Driver", + + .init = grub_video_sdl_init, + .fini = grub_video_sdl_fini, + .setup = grub_video_sdl_setup, + .get_info = grub_video_fb_get_info, + .set_palette = grub_video_sdl_set_palette, + .get_palette = grub_video_fb_get_palette, + .set_viewport = grub_video_fb_set_viewport, + .get_viewport = grub_video_fb_get_viewport, + .map_color = grub_video_fb_map_color, + .map_rgb = grub_video_fb_map_rgb, + .map_rgba = grub_video_fb_map_rgba, + .unmap_color = grub_video_fb_unmap_color, + .fill_rect = grub_video_fb_fill_rect, + .blit_bitmap = grub_video_fb_blit_bitmap, + .blit_render_target = grub_video_fb_blit_render_target, + .scroll = grub_video_fb_scroll, + .swap_buffers = grub_video_sdl_swap_buffers, + .create_render_target = grub_video_fb_create_render_target, + .delete_render_target = grub_video_fb_delete_render_target, + .set_active_render_target = grub_video_sdl_set_active_render_target, + .get_active_render_target = grub_video_fb_get_active_render_target, + + .next = 0 + }; + +GRUB_MOD_INIT(sdl) +{ + grub_video_register (&grub_video_sdl_adapter); +} + +GRUB_MOD_FINI(sdl) +{ + grub_video_unregister (&grub_video_sdl_adapter); +} From a9d407a81e6761a24f4816d43035e7accdc1ad4d Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Nov 2009 10:46:30 +0100 Subject: [PATCH 06/67] Reimported scaling --- ChangeLog.scale | 16 ++ conf/common.rmk | 6 + include/grub/bitmap_scale.h | 48 ++++++ include/grub/xnu.h | 3 + loader/i386/pc/xnu.c | 45 ++++-- loader/xnu.c | 37 ++++- term/gfxterm.c | 53 ++++++- video/bitmap_scale.c | 308 ++++++++++++++++++++++++++++++++++++ 8 files changed, 490 insertions(+), 26 deletions(-) create mode 100644 ChangeLog.scale create mode 100644 include/grub/bitmap_scale.h create mode 100644 video/bitmap_scale.c diff --git a/ChangeLog.scale b/ChangeLog.scale new file mode 100644 index 000000000..eb12d3b21 --- /dev/null +++ b/ChangeLog.scale @@ -0,0 +1,16 @@ +2009-08-24 Colin D Bennett + + Bitmap scaling support. + + * conf/common.rmk (pkglib_MODULES): Add bitmap_scale.mod. + (bitmap_scale_mod_SOURCES): New variable. + (bitmap_scale_mod_CFLAGS): Likewise. + (bitmap_scale_mod_LDFLAGS): Likewise. + * include/grub/bitmap_scale.h: New file. + * term/gfxterm.c (BACKGROUND_CMD_ARGINDEX_MODE): New definiton. + (background_image_cmd_options): New variable. + (grub_gfxterm_background_image_cmd): Support bitmap stretching. + (cmd): Rename and change type to ... + (background_image_cmd_handle): ... this. All users updated. + (GRUB_MOD_INIT(term_gfxterm)): Make background_image extended command. + * video/bitmap_scale.c: New file. diff --git a/conf/common.rmk b/conf/common.rmk index 173f24b62..98681bc1c 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -567,6 +567,12 @@ bitmap_mod_SOURCES = video/bitmap.c bitmap_mod_CFLAGS = $(COMMON_CFLAGS) bitmap_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For bitmap_scale.mod +pkglib_MODULES += bitmap_scale.mod +bitmap_scale_mod_SOURCES = video/bitmap_scale.c +bitmap_scale_mod_CFLAGS = $(COMMON_CFLAGS) +bitmap_scale_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For tga.mod tga_mod_SOURCES = video/readers/tga.c tga_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/include/grub/bitmap_scale.h b/include/grub/bitmap_scale.h new file mode 100644 index 000000000..7ea9d7914 --- /dev/null +++ b/include/grub/bitmap_scale.h @@ -0,0 +1,48 @@ +/* bitmap_scale.h - Bitmap scaling functions. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_BITMAP_SCALE_HEADER +#define GRUB_BITMAP_SCALE_HEADER 1 + +#include +#include +#include + +enum grub_video_bitmap_scale_method +{ + /* Choose the fastest interpolation algorithm. */ + GRUB_VIDEO_BITMAP_SCALE_METHOD_FASTEST, + /* Choose the highest quality interpolation algorithm. */ + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST, + + /* Specific algorithms: */ + /* Nearest neighbor interpolation. */ + GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST, + /* Bilinear interpolation. */ + GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR +}; + +grub_err_t +grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst, + int dst_width, int dst_height, + struct grub_video_bitmap *src, + enum + grub_video_bitmap_scale_method scale_method); + +#endif /* ! GRUB_BITMAP_SCALE_HEADER */ diff --git a/include/grub/xnu.h b/include/grub/xnu.h index c3902e670..b058bd1b9 100644 --- a/include/grub/xnu.h +++ b/include/grub/xnu.h @@ -104,4 +104,7 @@ extern grub_uint32_t grub_xnu_heap_real_start; extern grub_size_t grub_xnu_heap_size; extern char *grub_xnu_heap_start; extern struct grub_video_bitmap *grub_xnu_bitmap; +typedef enum {GRUB_XNU_BITMAP_CENTER, GRUB_XNU_BITMAP_STRETCH} + grub_xnu_bitmap_mode_t; +extern grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode; #endif diff --git a/loader/i386/pc/xnu.c b/loader/i386/pc/xnu.c index 839d0ad44..1a222e6e5 100644 --- a/loader/i386/pc/xnu.c +++ b/loader/i386/pc/xnu.c @@ -22,6 +22,7 @@ #include #include #include +#include #define min(a,b) (((a) < (b)) ? (a) : (b)) #define max(a,b) (((a) > (b)) ? (a) : (b)) @@ -37,6 +38,7 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) char *tmp, *modevar; void *framebuffer; grub_err_t err; + struct grub_video_bitmap *bitmap = NULL; modevar = grub_env_get ("gfxpayload"); /* Consider only graphical 32-bit deep modes. */ @@ -63,31 +65,46 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) if (err) return err; + ret = grub_video_get_info (&mode_info); + if (ret) + return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters"); + if (grub_xnu_bitmap) + { + if (grub_xnu_bitmap_mode == GRUB_XNU_BITMAP_STRETCH) + err = grub_video_bitmap_create_scaled (&bitmap, + mode_info.width, + mode_info.height, + grub_xnu_bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + else + bitmap = grub_xnu_bitmap; + } + + if (bitmap) { int x, y; - x = mode_info.width - grub_xnu_bitmap->mode_info.width; + x = mode_info.width - bitmap->mode_info.width; x /= 2; - y = mode_info.height - grub_xnu_bitmap->mode_info.height; + y = mode_info.height - bitmap->mode_info.height; y /= 2; - err = grub_video_blit_bitmap (grub_xnu_bitmap, + err = grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_REPLACE, x > 0 ? x : 0, y > 0 ? y : 0, x < 0 ? -x : 0, y < 0 ? -y : 0, - min (grub_xnu_bitmap->mode_info.width, + min (bitmap->mode_info.width, mode_info.width), - min (grub_xnu_bitmap->mode_info.height, + min (bitmap->mode_info.height, mode_info.height)); - if (err) - { - grub_print_error (); - grub_errno = GRUB_ERR_NONE; - grub_xnu_bitmap = 0; - } - err = GRUB_ERR_NONE; + } + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + bitmap = 0; } ret = grub_video_get_info_and_fini (&mode_info, &framebuffer); @@ -100,8 +117,8 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) params->lfb_line_len = mode_info.pitch; params->lfb_base = PTR_TO_UINT32 (framebuffer); - params->lfb_mode = grub_xnu_bitmap - ? GRUB_XNU_VIDEO_SPLASH : GRUB_XNU_VIDEO_TEXT_IN_VIDEO; + params->lfb_mode = bitmap ? GRUB_XNU_VIDEO_SPLASH + : GRUB_XNU_VIDEO_TEXT_IN_VIDEO; return GRUB_ERR_NONE; } diff --git a/loader/xnu.c b/loader/xnu.c index aac4ae372..e0ae9cefe 100644 --- a/loader/xnu.c +++ b/loader/xnu.c @@ -31,6 +31,7 @@ #include #include #include +#include struct grub_xnu_devtree_key *grub_xnu_devtree_root = 0; static int driverspackagenum = 0; @@ -1272,18 +1273,37 @@ grub_cmd_xnu_kextdir (grub_command_t cmd __attribute__ ((unused)), } struct grub_video_bitmap *grub_xnu_bitmap = 0; +grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode; + +/* Option array indices. */ +#define XNU_SPLASH_CMD_ARGINDEX_MODE 0 + +static const struct grub_arg_option xnu_splash_cmd_options[] = + { + {"mode", 'm', 0, "Background image mode.", "stretch|normal", + ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; static grub_err_t -grub_cmd_xnu_splash (grub_command_t cmd __attribute__ ((unused)), +grub_cmd_xnu_splash (grub_extcmd_t cmd, int argc, char *args[]) { grub_err_t err; if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + if (cmd->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set && + grub_strcmp (cmd->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg, + "stretch") == 0) + grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH; + else + grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_CENTER; + err = grub_video_bitmap_load (&grub_xnu_bitmap, args[0]); if (err) grub_xnu_bitmap = 0; + return err; } @@ -1316,8 +1336,10 @@ grub_xnu_unlock () locked = 0; } -static grub_command_t cmd_kernel, cmd_mkext, cmd_kext, cmd_kextdir, - cmd_ramdisk, cmd_devtree, cmd_resume, cmd_splash; +static grub_command_t cmd_kernel, cmd_mkext, cmd_kext, ; +static grub_command_t cmd_devtree; +static grub_command_t cmd_kextdir, cmd_ramdisk, cmd_resume; +static grub_extcmd_t cmd_splash; GRUB_MOD_INIT(xnu) { @@ -1335,8 +1357,11 @@ GRUB_MOD_INIT(xnu) "It will be seen as md0"); cmd_devtree = grub_register_command ("xnu_devtree", grub_cmd_xnu_devtree, 0, "Load XNU devtree"); - cmd_splash = grub_register_command ("xnu_splash", grub_cmd_xnu_splash, 0, - "Load a splash image for XNU"); + cmd_splash = grub_register_extcmd ("xnu_splash", + grub_cmd_xnu_splash, + GRUB_COMMAND_FLAG_BOTH, 0, + "Load a splash image for XNU", + xnu_splash_cmd_options); #ifndef GRUB_UTIL cmd_resume = grub_register_command ("xnu_resume", grub_cmd_xnu_resume, @@ -1356,5 +1381,5 @@ GRUB_MOD_FINI(xnu) grub_unregister_command (cmd_devtree); grub_unregister_command (cmd_ramdisk); grub_unregister_command (cmd_kernel); - grub_unregister_command (cmd_splash); + grub_unregister_extcmd (cmd_splash); } diff --git a/term/gfxterm.c b/term/gfxterm.c index 6906b77a1..62cf98416 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #define DEFAULT_VIDEO_MODE "auto" #define DEFAULT_BORDER_WIDTH 10 @@ -909,11 +911,23 @@ grub_gfxterm_refresh (void) dirty_region_reset (); } +/* Option array indices. */ +#define BACKGROUND_CMD_ARGINDEX_MODE 0 + +static const struct grub_arg_option background_image_cmd_options[] = + { + {"mode", 'm', 0, "Background image mode.", "stretch|normal", + ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + static grub_err_t -grub_gfxterm_background_image_cmd (grub_command_t cmd __attribute__ ((unused)), +grub_gfxterm_background_image_cmd (grub_extcmd_t cmd __attribute__ ((unused)), int argc, char **args) { + struct grub_arg_list *state = cmd->state; + /* Check that we have video adapter active. */ if (grub_video_get_info(NULL) != GRUB_ERR_NONE) return grub_errno; @@ -937,6 +951,29 @@ grub_gfxterm_background_image_cmd (grub_command_t cmd __attribute__ ((unused)), if (grub_errno != GRUB_ERR_NONE) return grub_errno; + /* Determine if the bitmap should be scaled to fit the screen. */ + if (!state[BACKGROUND_CMD_ARGINDEX_MODE].set + || grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_MODE].arg, + "stretch") == 0) + { + if (mode_info.width != grub_video_bitmap_get_width (bitmap) + || mode_info.height != grub_video_bitmap_get_height (bitmap)) + { + struct grub_video_bitmap *scaled_bitmap; + grub_video_bitmap_create_scaled (&scaled_bitmap, + mode_info.width, + mode_info.height, + bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + if (grub_errno == GRUB_ERR_NONE) + { + /* Replace the original bitmap with the scaled one. */ + grub_video_bitmap_destroy (bitmap); + bitmap = scaled_bitmap; + } + } + } + /* If bitmap was loaded correctly, display it. */ if (bitmap) { @@ -975,18 +1012,22 @@ static struct grub_term_output grub_video_term = .next = 0 }; -static grub_command_t cmd; +static grub_extcmd_t background_image_cmd_handle; GRUB_MOD_INIT(term_gfxterm) { grub_term_register_output ("gfxterm", &grub_video_term); - cmd = grub_register_command ("background_image", - grub_gfxterm_background_image_cmd, - 0, "Load background image for active terminal"); + background_image_cmd_handle = + grub_register_extcmd ("background_image", + grub_gfxterm_background_image_cmd, + GRUB_COMMAND_FLAG_BOTH, + "background_image [-m (stretch|normal)] FILE", + "Load background image for active terminal.", + background_image_cmd_options); } GRUB_MOD_FINI(term_gfxterm) { - grub_unregister_command (cmd); + grub_unregister_extcmd (background_image_cmd_handle); grub_term_unregister_output (&grub_video_term); } diff --git a/video/bitmap_scale.c b/video/bitmap_scale.c new file mode 100644 index 000000000..6f8ff247e --- /dev/null +++ b/video/bitmap_scale.c @@ -0,0 +1,308 @@ +/* bitmap_scale.c - Bitmap scaling. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +/* Prototypes for module-local functions. */ +static grub_err_t scale_nn (struct grub_video_bitmap *dst, + struct grub_video_bitmap *src); +static grub_err_t scale_bilinear (struct grub_video_bitmap *dst, + struct grub_video_bitmap *src); + +/* This function creates a new scaled version of the bitmap SRC. The new + bitmap has dimensions DST_WIDTH by DST_HEIGHT. The scaling algorithm + is given by SCALE_METHOD. If an error is encountered, the return code is + not equal to GRUB_ERR_NONE, and the bitmap DST is either not created, or + it is destroyed before this function returns. + + Supports only direct color modes which have components separated + into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color). + But because of this simplifying assumption, the implementation is + greatly simplified. */ +grub_err_t +grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst, + int dst_width, int dst_height, + struct grub_video_bitmap *src, + enum grub_video_bitmap_scale_method + scale_method) +{ + *dst = 0; + + /* Verify the simplifying assumptions. */ + if (src == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "null src bitmap in grub_video_bitmap_create_scaled"); + if (src->mode_info.red_field_pos % 8 != 0 + || src->mode_info.green_field_pos % 8 != 0 + || src->mode_info.blue_field_pos % 8 != 0 + || src->mode_info.reserved_field_pos % 8 != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "src format not supported for scale"); + if (src->mode_info.width == 0 || src->mode_info.height == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "source bitmap has a zero dimension"); + if (dst_width <= 0 || dst_height <= 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "requested to scale to a size w/ a zero dimension"); + if (src->mode_info.bytes_per_pixel * 8 != src->mode_info.bpp) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "bitmap to scale has inconsistent Bpp and bpp"); + + /* Create the new bitmap. */ + grub_err_t ret; + ret = grub_video_bitmap_create (dst, dst_width, dst_height, + src->mode_info.blit_format); + if (ret != GRUB_ERR_NONE) + return ret; /* Error. */ + + switch (scale_method) + { + case GRUB_VIDEO_BITMAP_SCALE_METHOD_FASTEST: + case GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST: + ret = scale_nn (*dst, src); + break; + case GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST: + case GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR: + ret = scale_bilinear (*dst, src); + break; + default: + ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid scale_method value"); + break; + } + + if (ret == GRUB_ERR_NONE) + { + /* Success: *dst is now a pointer to the scaled bitmap. */ + return GRUB_ERR_NONE; + } + else + { + /* Destroy the bitmap and return the error code. */ + grub_video_bitmap_destroy (*dst); + *dst = 0; + return ret; + } +} + +/* Nearest neighbor bitmap scaling algorithm. + + Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the + dimensions of DST. This function uses the nearest neighbor algorithm to + interpolate the pixels. + + Supports only direct color modes which have components separated + into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color). + But because of this simplifying assumption, the implementation is + greatly simplified. */ +static grub_err_t +scale_nn (struct grub_video_bitmap *dst, struct grub_video_bitmap *src) +{ + /* Verify the simplifying assumptions. */ + if (dst == 0 || src == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "null bitmap in scale_nn"); + if (dst->mode_info.red_field_pos % 8 != 0 + || dst->mode_info.green_field_pos % 8 != 0 + || dst->mode_info.blue_field_pos % 8 != 0 + || dst->mode_info.reserved_field_pos % 8 != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst format not supported"); + if (src->mode_info.red_field_pos % 8 != 0 + || src->mode_info.green_field_pos % 8 != 0 + || src->mode_info.blue_field_pos % 8 != 0 + || src->mode_info.reserved_field_pos % 8 != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "src format not supported"); + if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos + || dst->mode_info.red_mask_size != src->mode_info.red_mask_size + || dst->mode_info.green_field_pos != src->mode_info.green_field_pos + || dst->mode_info.green_mask_size != src->mode_info.green_mask_size + || dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos + || dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size + || dst->mode_info.reserved_field_pos != + src->mode_info.reserved_field_pos + || dst->mode_info.reserved_mask_size != + src->mode_info.reserved_mask_size) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible"); + if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible"); + if (dst->mode_info.width == 0 || dst->mode_info.height == 0 + || src->mode_info.width == 0 || src->mode_info.height == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension"); + + grub_uint8_t *ddata = dst->data; + grub_uint8_t *sdata = src->data; + int dw = dst->mode_info.width; + int dh = dst->mode_info.height; + int sw = src->mode_info.width; + int sh = src->mode_info.height; + int dstride = dst->mode_info.pitch; + int sstride = src->mode_info.pitch; + /* bytes_per_pixel is the same for both src and dst. */ + int bytes_per_pixel = dst->mode_info.bytes_per_pixel; + + int dy; + for (dy = 0; dy < dh; dy++) + { + int dx; + for (dx = 0; dx < dw; dx++) + { + grub_uint8_t *dptr; + grub_uint8_t *sptr; + int sx; + int sy; + int comp; + + /* Compute the source coordinate that the destination coordinate + maps to. Note: sx/sw = dx/dw => sx = sw*dx/dw. */ + sx = sw * dx / dw; + sy = sh * dy / dh; + + /* Get the address of the pixels in src and dst. */ + dptr = ddata + dy * dstride + dx * bytes_per_pixel; + sptr = sdata + sy * sstride + sx * bytes_per_pixel; + + /* Copy the pixel color value. */ + for (comp = 0; comp < bytes_per_pixel; comp++) + dptr[comp] = sptr[comp]; + } + } + return GRUB_ERR_NONE; +} + +/* Bilinear interpolation image scaling algorithm. + + Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the + dimensions of DST. This function uses the bilinear interpolation algorithm + to interpolate the pixels. + + Supports only direct color modes which have components separated + into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color). + But because of this simplifying assumption, the implementation is + greatly simplified. */ +static grub_err_t +scale_bilinear (struct grub_video_bitmap *dst, struct grub_video_bitmap *src) +{ + /* Verify the simplifying assumptions. */ + if (dst == 0 || src == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "null bitmap in scale func"); + if (dst->mode_info.red_field_pos % 8 != 0 + || dst->mode_info.green_field_pos % 8 != 0 + || dst->mode_info.blue_field_pos % 8 != 0 + || dst->mode_info.reserved_field_pos % 8 != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst format not supported"); + if (src->mode_info.red_field_pos % 8 != 0 + || src->mode_info.green_field_pos % 8 != 0 + || src->mode_info.blue_field_pos % 8 != 0 + || src->mode_info.reserved_field_pos % 8 != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "src format not supported"); + if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos + || dst->mode_info.red_mask_size != src->mode_info.red_mask_size + || dst->mode_info.green_field_pos != src->mode_info.green_field_pos + || dst->mode_info.green_mask_size != src->mode_info.green_mask_size + || dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos + || dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size + || dst->mode_info.reserved_field_pos != + src->mode_info.reserved_field_pos + || dst->mode_info.reserved_mask_size != + src->mode_info.reserved_mask_size) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible"); + if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible"); + if (dst->mode_info.width == 0 || dst->mode_info.height == 0 + || src->mode_info.width == 0 || src->mode_info.height == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension"); + + grub_uint8_t *ddata = dst->data; + grub_uint8_t *sdata = src->data; + int dw = dst->mode_info.width; + int dh = dst->mode_info.height; + int sw = src->mode_info.width; + int sh = src->mode_info.height; + int dstride = dst->mode_info.pitch; + int sstride = src->mode_info.pitch; + /* bytes_per_pixel is the same for both src and dst. */ + int bytes_per_pixel = dst->mode_info.bytes_per_pixel; + + int dy; + for (dy = 0; dy < dh; dy++) + { + int dx; + for (dx = 0; dx < dw; dx++) + { + grub_uint8_t *dptr; + grub_uint8_t *sptr; + int sx; + int sy; + int comp; + + /* Compute the source coordinate that the destination coordinate + maps to. Note: sx/sw = dx/dw => sx = sw*dx/dw. */ + sx = sw * dx / dw; + sy = sh * dy / dh; + + /* Get the address of the pixels in src and dst. */ + dptr = ddata + dy * dstride + dx * bytes_per_pixel; + sptr = sdata + sy * sstride + sx * bytes_per_pixel; + + /* If we have enough space to do so, use bilinear interpolation. + Otherwise, fall back to nearest neighbor for this pixel. */ + if (sx < sw - 1 && sy < sh - 1) + { + /* Do bilinear interpolation. */ + + /* Fixed-point .8 numbers representing the fraction of the + distance in the x (u) and y (v) direction within the + box of 4 pixels in the source. */ + int u = (256 * sw * dx / dw) - (sx * 256); + int v = (256 * sh * dy / dh) - (sy * 256); + + for (comp = 0; comp < bytes_per_pixel; comp++) + { + /* Get the component's values for the + four source corner pixels. */ + grub_uint8_t f00 = sptr[comp]; + grub_uint8_t f10 = sptr[comp + bytes_per_pixel]; + grub_uint8_t f01 = sptr[comp + sstride]; + grub_uint8_t f11 = sptr[comp + sstride + bytes_per_pixel]; + + /* Do linear interpolations along the top and bottom + rows of the box. */ + grub_uint8_t f0y = (256 - v) * f00 / 256 + v * f01 / 256; + grub_uint8_t f1y = (256 - v) * f10 / 256 + v * f11 / 256; + + /* Interpolate vertically. */ + grub_uint8_t fxy = (256 - u) * f0y / 256 + u * f1y / 256; + + dptr[comp] = fxy; + } + } + else + { + /* Fall back to nearest neighbor interpolation. */ + /* Copy the pixel color value. */ + for (comp = 0; comp < bytes_per_pixel; comp++) + dptr[comp] = sptr[comp]; + } + } + } + return GRUB_ERR_NONE; +} From 1488fac7ef235d579972822b1cbc6e2e2932fc8b Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Nov 2009 13:53:36 +0100 Subject: [PATCH 07/67] Fixed missing make directives --- conf/i386-pc.rmk | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 382c45ca3..4c2aec617 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -155,7 +155,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ \ video/video.c video/fb/video_fb.c video/fb/fbblit.c \ video/fb/fbfill.c video/fb/fbutil.c commands/videotest.c \ - video/bitmap.c video/readers/tga.c video/readers/jpeg.c \ + video/bitmap.c video/bitmap_scale.c video/readers/tga.c video/readers/jpeg.c \ video/readers/png.c font/font_cmd.c font/font.c term/gfxterm.c \ io/bufio.c \ \ @@ -175,6 +175,11 @@ grub_emu_SOURCES += disk/usbms.c util/usb.c bus/usb/usb.c \ grub_emu_LDFLAGS += $(LIBCURSES) $(LIBUSB) endif +ifeq ($(enable_grub_emu_sdl), yes) +grub_emu_SOURCES += util/sdl.c +grub_emu_LDFLAGS += $(LIBSDL) +endif + sbin_SCRIPTS += grub-install grub_install_SOURCES = util/grub-install.in From 71bc82683468a4c3bfd63aedbf0155bd5957eea2 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Nov 2009 13:55:43 +0100 Subject: [PATCH 08/67] Fixed syntax error --- loader/xnu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/xnu.c b/loader/xnu.c index e0ae9cefe..ab88317d2 100644 --- a/loader/xnu.c +++ b/loader/xnu.c @@ -1336,7 +1336,7 @@ grub_xnu_unlock () locked = 0; } -static grub_command_t cmd_kernel, cmd_mkext, cmd_kext, ; +static grub_command_t cmd_kernel, cmd_mkext, cmd_kext; static grub_command_t cmd_devtree; static grub_command_t cmd_kextdir, cmd_ramdisk, cmd_resume; static grub_extcmd_t cmd_splash; From a8287184e360c8f198fc3174f99e8032df44881a Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Nov 2009 14:19:20 +0100 Subject: [PATCH 09/67] renamed ChangeLog --- ChangeLog.video => ChangeLog.doublebuf | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ChangeLog.video => ChangeLog.doublebuf (100%) diff --git a/ChangeLog.video b/ChangeLog.doublebuf similarity index 100% rename from ChangeLog.video rename to ChangeLog.doublebuf From b49991d823c428b4daf69c877d15fcc31e99c950 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Nov 2009 14:27:52 +0100 Subject: [PATCH 10/67] ChangeLog --- ChangeLog.sdl | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 ChangeLog.sdl diff --git a/ChangeLog.sdl b/ChangeLog.sdl new file mode 100644 index 000000000..8bf8c082a --- /dev/null +++ b/ChangeLog.sdl @@ -0,0 +1,11 @@ +2009-11-20 Vladimir Serbinenko + + SDL support. + + * Makefile.in (LIBSDL): New variable. + (enable_grub_emu_sdl): Likewise. + * conf/i386-pc.rmk (grub_emu_SOURCES): Add video files. + (grub_emu_SOURCES) [enable_grub_emu_sdl]: Add util/sdl.c. + (grub_emu_LDFLAGS) [enable_grub_emu_sdl]: Add $(LIBSDL). + * configure.ac: Detect SDL availability and add --enable-grub-emu-sdl + * util/sdl.c: New file. From b4dae692eb6afc9aed7bd7d6ee47824086def7e4 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Nov 2009 14:30:58 +0100 Subject: [PATCH 11/67] Fixed variable declarations --- term/gfxterm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/term/gfxterm.c b/term/gfxterm.c index 3fc151c8b..5330c4ac4 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -323,6 +323,7 @@ grub_gfxterm_init (void) struct grub_video_mode_info mode_info; char *tmp; grub_err_t err; + grub_video_color_t color; /* If gfxterm has already been initialized by calling the init_window function, then leave it alone when it is set as the current terminal. */ @@ -702,7 +703,6 @@ scroll_up (void) else { grub_video_rect_t saved_view; - int i; grub_video_set_active_render_target (render_target); /* Save viewport and set it to our window. */ From ac3b7128d6d7e89fd103d6ad4054ce3db56195d6 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Nov 2009 14:45:33 +0100 Subject: [PATCH 12/67] 2009-11-20 Colin D Bennett * normal/menu_text.c (get_entry_number): Move from here ... * normal/menu.c (get_entry_number): ... moved here. * include/grub/menu.h (grub_menu_get_default_entry_index): New prototype. * normal/menu.c (grub_menu_get_default_entry_index): New function. * normal/menu_text.c (run_menu): Use grub_menu_get_default_entry_index. --- ChangeLog.menu | 9 ++++++++ include/grub/menu.h | 1 + normal/menu.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ normal/menu_text.c | 50 +---------------------------------------- 4 files changed, 65 insertions(+), 49 deletions(-) create mode 100644 ChangeLog.menu diff --git a/ChangeLog.menu b/ChangeLog.menu new file mode 100644 index 000000000..cb048bc9f --- /dev/null +++ b/ChangeLog.menu @@ -0,0 +1,9 @@ +2009-11-20 Colin D Bennett + + * normal/menu_text.c (get_entry_number): Move from here ... + * normal/menu.c (get_entry_number): ... moved here. + * include/grub/menu.h (grub_menu_get_default_entry_index): + New prototype. + * normal/menu.c (grub_menu_get_default_entry_index): New function. + * normal/menu_text.c (run_menu): Use grub_menu_get_default_entry_index. + diff --git a/include/grub/menu.h b/include/grub/menu.h index c7114a93b..cfe7e7cec 100644 --- a/include/grub/menu.h +++ b/include/grub/menu.h @@ -93,5 +93,6 @@ void grub_menu_execute_with_fallback (grub_menu_t menu, grub_menu_execute_callback_t callback, void *callback_data); void grub_menu_entry_run (grub_menu_entry_t entry); +int grub_menu_get_default_entry_index (grub_menu_t menu); #endif /* GRUB_MENU_HEADER */ diff --git a/normal/menu.c b/normal/menu.c index b9f74b7d7..282dddae5 100644 --- a/normal/menu.c +++ b/normal/menu.c @@ -180,3 +180,57 @@ grub_menu_execute_with_fallback (grub_menu_t menu, callback->notify_failure (callback_data); } + +/* Get the entry number from the variable NAME. */ +static int +get_entry_number (grub_menu_t menu, const char *name) +{ + char *val; + int entry; + + val = grub_env_get (name); + if (! val) + return -1; + + grub_error_push (); + + entry = (int) grub_strtoul (val, 0, 0); + + if (grub_errno == GRUB_ERR_BAD_NUMBER) + { + /* See if the variable matches the title of a menu entry. */ + grub_menu_entry_t e = menu->entry_list; + int i; + + grub_errno = GRUB_ERR_NONE; + + for (i = 0; e; i++) + { + if (grub_strcmp (e->title, val) == 0) + { + entry = i; + break; + } + e = e->next; + } + + if (! e) + entry = -1; + } + + if (grub_errno != GRUB_ERR_NONE) + { + grub_errno = GRUB_ERR_NONE; + entry = -1; + } + + grub_error_pop (); + + return entry; +} + +int +grub_menu_get_default_entry_index (grub_menu_t menu) +{ + return get_entry_number (menu, "default"); +} diff --git a/normal/menu_text.c b/normal/menu_text.c index 19f9cf756..d02230a8f 100644 --- a/normal/menu_text.c +++ b/normal/menu_text.c @@ -235,54 +235,6 @@ grub_menu_init_page (int nested, int edit) print_message (nested, edit); } -/* Get the entry number from the variable NAME. */ -static int -get_entry_number (grub_menu_t menu, const char *name) -{ - char *val; - int entry; - - val = grub_env_get (name); - if (! val) - return -1; - - grub_error_push (); - - entry = (int) grub_strtoul (val, 0, 0); - - if (grub_errno == GRUB_ERR_BAD_NUMBER) - { - /* See if the variable matches the title of a menu entry. */ - grub_menu_entry_t e = menu->entry_list; - int i; - - grub_errno = GRUB_ERR_NONE; - - for (i = 0; e; i++) - { - if (grub_strcmp (e->title, val) == 0) - { - entry = i; - break; - } - e = e->next; - } - - if (! e) - entry = -1; - } - - if (grub_errno != GRUB_ERR_NONE) - { - grub_errno = GRUB_ERR_NONE; - entry = -1; - } - - grub_error_pop (); - - return entry; -} - static void print_timeout (int timeout, int offset, int second_stage) { @@ -313,7 +265,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) first = 0; - default_entry = get_entry_number (menu, "default"); + default_entry = grub_menu_get_default_entry_index (menu); /* If DEFAULT_ENTRY is not within the menu entries, fall back to the first entry. */ From cbf97a87d9d63c46e8057f163238cec42fa4ec43 Mon Sep 17 00:00:00 2001 From: Colin D Bennett Date: Fri, 20 Nov 2009 14:51:01 +0100 Subject: [PATCH 13/67] * include/grub/menu_viewer.h (grub_menu_viewer_init): New prototype. (grub_menu_viewer_should_return): Likewise. * normal/main.c (GRUB_MOD_INIT (normal)): Call grub_menu_viewer_init. * normal/menu_text.c (run_menu): Enable menu switching. * normal/menu_viewer.c (should_return): New variable. (menu_viewer_changed): Likewise. (grub_menu_viewer_show_menu): Handle menu viewer changes. (grub_menu_viewer_should_return): New function. (menuviewer_write_hook): Likewise. (grub_menu_viewer_init): Likewise. --- ChangeLog.menu | 10 ++++++++++ include/grub/menu_viewer.h | 5 +++++ normal/main.c | 2 ++ normal/menu_text.c | 9 +++++++-- normal/menu_viewer.c | 37 ++++++++++++++++++++++++++++++++++--- 5 files changed, 58 insertions(+), 5 deletions(-) diff --git a/ChangeLog.menu b/ChangeLog.menu index cb048bc9f..32c0a85d5 100644 --- a/ChangeLog.menu +++ b/ChangeLog.menu @@ -6,4 +6,14 @@ New prototype. * normal/menu.c (grub_menu_get_default_entry_index): New function. * normal/menu_text.c (run_menu): Use grub_menu_get_default_entry_index. + * include/grub/menu_viewer.h (grub_menu_viewer_init): New prototype. + (grub_menu_viewer_should_return): Likewise. + * normal/main.c (GRUB_MOD_INIT (normal)): Call grub_menu_viewer_init. + * normal/menu_text.c (run_menu): Enable menu switching. + * normal/menu_viewer.c (should_return): New variable. + (menu_viewer_changed): Likewise. + (grub_menu_viewer_show_menu): Handle menu viewer changes. + (grub_menu_viewer_should_return): New function. + (menuviewer_write_hook): Likewise. + (grub_menu_viewer_init): Likewise. diff --git a/include/grub/menu_viewer.h b/include/grub/menu_viewer.h index 725c97548..211f6e3e9 100644 --- a/include/grub/menu_viewer.h +++ b/include/grub/menu_viewer.h @@ -36,8 +36,13 @@ struct grub_menu_viewer }; typedef struct grub_menu_viewer *grub_menu_viewer_t; +void grub_menu_viewer_init (void); + void grub_menu_viewer_register (grub_menu_viewer_t viewer); grub_err_t grub_menu_viewer_show_menu (grub_menu_t menu, int nested); +/* Return nonzero iff the menu viewer should clean up and return ASAP. */ +int grub_menu_viewer_should_return (void); + #endif /* GRUB_MENU_VIEWER_HEADER */ diff --git a/normal/main.c b/normal/main.c index 748eef805..736c20e47 100644 --- a/normal/main.c +++ b/normal/main.c @@ -584,6 +584,8 @@ GRUB_MOD_INIT(normal) /* Preserve hooks after context changes. */ grub_env_export ("color_normal"); grub_env_export ("color_highlight"); + + grub_menu_viewer_init (); } GRUB_MOD_FINI(normal) diff --git a/normal/menu_text.c b/normal/menu_text.c index d02230a8f..68c7afeee 100644 --- a/normal/menu_text.c +++ b/normal/menu_text.c @@ -300,7 +300,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) if (timeout > 0) print_timeout (timeout, offset, 0); - while (1) + while (! grub_menu_viewer_should_return ()) { int c; timeout = grub_menu_get_timeout (); @@ -473,6 +473,10 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) } goto refresh; + case 't': + grub_env_set ("menuviewer", "gfxmenu"); + goto refresh; + default: break; } @@ -481,7 +485,8 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) } } - /* Never reach here. */ + /* Exit menu without activating an item. This occurs if the user presses + * 't', switching to the graphical menu viewer. */ return -1; } diff --git a/normal/menu_viewer.c b/normal/menu_viewer.c index 1bd271a21..7a547a764 100644 --- a/normal/menu_viewer.c +++ b/normal/menu_viewer.c @@ -26,6 +26,9 @@ /* The list of menu viewers. */ static grub_menu_viewer_t menu_viewer_list; +static int should_return; +static int menu_viewer_changed; + void grub_menu_viewer_register (grub_menu_viewer_t viewer) { @@ -55,16 +58,23 @@ static grub_menu_viewer_t get_current_menu_viewer (void) grub_err_t grub_menu_viewer_show_menu (grub_menu_t menu, int nested) { - grub_menu_viewer_t cur = get_current_menu_viewer (); grub_err_t err1, err2; - if (!cur) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available."); while (1) { + grub_menu_viewer_t cur = get_current_menu_viewer (); + if (!cur) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available."); + + menu_viewer_changed = 0; + should_return = 0; + err1 = cur->show_menu (menu, nested); grub_print_error (); + if (menu_viewer_changed) + continue; + err2 = grub_auth_check_authentication (NULL); if (err2) { @@ -79,3 +89,24 @@ grub_menu_viewer_show_menu (grub_menu_t menu, int nested) return err1; } +int +grub_menu_viewer_should_return (void) +{ + return should_return; +} + +static char * +menuviewer_write_hook (struct grub_env_var *var __attribute__ ((unused)), + const char *val) +{ + menu_viewer_changed = 1; + should_return = 1; + return grub_strdup (val); +} + +void +grub_menu_viewer_init (void) +{ + grub_register_variable_hook ("menuviewer", 0, menuviewer_write_hook); +} + From bd86691a07c81cab2ba6f364cdfdedb34914ef37 Mon Sep 17 00:00:00 2001 From: Colin D Bennett Date: Fri, 20 Nov 2009 15:09:48 +0100 Subject: [PATCH 14/67] 2009-11-20 Colin D Bennett * include/grub/misc.h (grub_iscntrl): New inline function. (grub_isalnum): Likewise. (grub_strtol): Likewise. --- ChangeLog.gfxmenumisc | 6 ++++++ include/grub/misc.h | 49 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 ChangeLog.gfxmenumisc diff --git a/ChangeLog.gfxmenumisc b/ChangeLog.gfxmenumisc new file mode 100644 index 000000000..ace9862ba --- /dev/null +++ b/ChangeLog.gfxmenumisc @@ -0,0 +1,6 @@ +2009-11-20 Colin D Bennett + + * include/grub/misc.h (grub_iscntrl): New inline function. + (grub_isalnum): Likewise. + (grub_strtol): Likewise. + diff --git a/include/grub/misc.h b/include/grub/misc.h index faa2d5c42..b843b9202 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -94,6 +94,12 @@ char *EXPORT_FUNC(grub_strstr) (const char *haystack, const char *needle); int EXPORT_FUNC(grub_isspace) (int c); int EXPORT_FUNC(grub_isprint) (int c); +static inline int +grub_iscntrl (int c) +{ + return (c >= 0x00 && c <= 0x1F) || c == 0x7F; +} + static inline int grub_isalpha (int c) { @@ -112,6 +118,12 @@ grub_isdigit (int c) return (c >= '0' && c <= '9'); } +static inline int +grub_isalnum (int c) +{ + return grub_isalpha (c) || grub_isdigit (c); +} + static inline int grub_tolower (int c) { @@ -166,6 +178,43 @@ grub_strncasecmp (const char *s1, const char *s2, grub_size_t n) unsigned long EXPORT_FUNC(grub_strtoul) (const char *str, char **end, int base); unsigned long long EXPORT_FUNC(grub_strtoull) (const char *str, char **end, int base); + +static inline long +grub_strtol (const char *str, char **end, int base) +{ + int negative = 0; + unsigned long magnitude; + + while (*str && grub_isspace (*str)) + str++; + + if (*str == '-') + { + negative = 1; + str++; + } + + magnitude = grub_strtoull (str, end, base); + if (negative) + { + if (magnitude > (unsigned long) GRUB_LONG_MAX + 1) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "negative overflow"); + return GRUB_LONG_MIN; + } + return -((long) magnitude); + } + else + { + if (magnitude > GRUB_LONG_MAX) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "positive overflow"); + return GRUB_LONG_MAX; + } + return (long) magnitude; + } +} + char *EXPORT_FUNC(grub_strdup) (const char *s); char *EXPORT_FUNC(grub_strndup) (const char *s, grub_size_t n); void *EXPORT_FUNC(grub_memset) (void *s, int c, grub_size_t n); From 1f1551457faf627f0c310f514c597da93138f0c1 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Nov 2009 16:00:13 +0100 Subject: [PATCH 15/67] ChangeLog --- ChangeLog.trig | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 ChangeLog.trig diff --git a/ChangeLog.trig b/ChangeLog.trig new file mode 100644 index 000000000..c3cd73594 --- /dev/null +++ b/ChangeLog.trig @@ -0,0 +1,11 @@ +2009-11-14 Colin D Bennet + + Trigonometry support. + + * include/grub/trig.h: New file. + * lib/trig.c: Likewise. + * maintainance/gentrigtables.py: Likewise. + * conf/common.rmk (pkglib_MODULES): Add trig.mod. + (trig_mod_SOURCES): New variable. + (trig_mod_CFLAGS): Likewise. + (trig_mod_LDFLAGS): Likewise. From d920a32ab688df7cce1667434cc6785ebc840386 Mon Sep 17 00:00:00 2001 From: Colin D Bennett Date: Fri, 20 Nov 2009 16:02:58 +0100 Subject: [PATCH 16/67] gfxmenu import --- conf/common.rmk | 22 + docs/gfxmenu-theme-example.txt | 128 ++++++ gfxmenu/gfxmenu.c | 235 +++++++++++ gfxmenu/gui_box.c | 372 +++++++++++++++++ gfxmenu/gui_canvas.c | 268 ++++++++++++ gfxmenu/gui_circular_progress.c | 339 +++++++++++++++ gfxmenu/gui_image.c | 270 ++++++++++++ gfxmenu/gui_label.c | 248 +++++++++++ gfxmenu/gui_list.c | 625 +++++++++++++++++++++++++++ gfxmenu/gui_progress_bar.c | 378 +++++++++++++++++ gfxmenu/gui_string_util.c | 358 ++++++++++++++++ gfxmenu/gui_util.c | 101 +++++ gfxmenu/icon_manager.c | 258 ++++++++++++ gfxmenu/model.c | 191 +++++++++ gfxmenu/named_colors.c | 209 +++++++++ gfxmenu/theme_loader.c | 720 ++++++++++++++++++++++++++++++++ gfxmenu/view.c | 497 ++++++++++++++++++++++ gfxmenu/widget-box.c | 313 ++++++++++++++ include/grub/gfxmenu_model.h | 59 +++ include/grub/gfxmenu_view.h | 91 ++++ include/grub/gfxwidgets.h | 49 +++ include/grub/gui.h | 165 ++++++++ include/grub/gui_string_util.h | 39 ++ include/grub/icon_manager.h | 41 ++ include/grub/term.h | 2 +- 25 files changed, 5977 insertions(+), 1 deletion(-) create mode 100644 docs/gfxmenu-theme-example.txt create mode 100644 gfxmenu/gfxmenu.c create mode 100644 gfxmenu/gui_box.c create mode 100644 gfxmenu/gui_canvas.c create mode 100644 gfxmenu/gui_circular_progress.c create mode 100644 gfxmenu/gui_image.c create mode 100644 gfxmenu/gui_label.c create mode 100644 gfxmenu/gui_list.c create mode 100644 gfxmenu/gui_progress_bar.c create mode 100644 gfxmenu/gui_string_util.c create mode 100644 gfxmenu/gui_util.c create mode 100644 gfxmenu/icon_manager.c create mode 100644 gfxmenu/model.c create mode 100644 gfxmenu/named_colors.c create mode 100644 gfxmenu/theme_loader.c create mode 100644 gfxmenu/view.c create mode 100644 gfxmenu/widget-box.c create mode 100644 include/grub/gfxmenu_model.h create mode 100644 include/grub/gfxmenu_view.h create mode 100644 include/grub/gfxwidgets.h create mode 100644 include/grub/gui.h create mode 100644 include/grub/gui_string_util.h create mode 100644 include/grub/icon_manager.h diff --git a/conf/common.rmk b/conf/common.rmk index 3dddeb66d..4c1b845df 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -417,6 +417,28 @@ hello_mod_SOURCES = hello/hello.c hello_mod_CFLAGS = $(COMMON_CFLAGS) hello_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For gfxmenu.mod. +pkglib_MODULES += gfxmenu.mod +gfxmenu_mod_SOURCES = \ + gfxmenu/gfxmenu.c \ + gfxmenu/model.c \ + gfxmenu/view.c \ + gfxmenu/icon_manager.c \ + gfxmenu/theme_loader.c \ + gfxmenu/widget-box.c \ + gfxmenu/gui_canvas.c \ + gfxmenu/gui_circular_progress.c \ + gfxmenu/gui_box.c \ + gfxmenu/gui_label.c \ + gfxmenu/gui_list.c \ + gfxmenu/gui_image.c \ + gfxmenu/gui_progress_bar.c \ + gfxmenu/gui_util.c \ + gfxmenu/gui_string_util.c \ + gfxmenu/named_colors.c +gfxmenu_mod_CFLAGS = $(COMMON_CFLAGS) +gfxmenu_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For parttool.mod. parttool_mod_SOURCES = commands/parttool.c parttool_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/docs/gfxmenu-theme-example.txt b/docs/gfxmenu-theme-example.txt new file mode 100644 index 000000000..4363dc8df --- /dev/null +++ b/docs/gfxmenu-theme-example.txt @@ -0,0 +1,128 @@ +# GRUB gfxmenu theme "winter". +# Uses background image from: +# http://www.cyberpunkcafe.com/e107_plugins/autogallery/autogallery.php?show=1.Open%20Source%20Wallpaper +# "without-leaves.png" was called "Without Leafs in Winter.png" + +lua-script: "winter.lua" +title-text: "" +title-font: "Helvetica Bold 18" +status-font: "Helvetica 8" +terminal-font: "Fixed 9" +title-color: "40, 40, 40" +status-color: "#FFF" +status-bg-color: "0, 166, 183, 128" +desktop-image: "without-leaves.png" +desktop-color: "0, 154, 183" +terminal-box: "terminal_*.png" + ++ boot_menu { + position = (120, 60) + preferred_size = (400, -1) + item_font = "Helvetica Bold 14" + selected_item_font = "Helvetica Bold 14" + item_color = "0, 0, 0" + selected_item_color = "203, 251, 255" + menu_pixmap_style = "menu_*.png" + selected_item_pixmap_style = "select_*.png" + icon_width = 44 + icon_height = 44 + item_height = 32 + item_padding = 0 + item_icon_space = 3 + item_spacing = 11 +} + +# You can add text at arbitrary locations on the screen. +# The specification within the "+label {...}" block is free-form, +# so you can use as much or as little white space as you like. + ++ label { + position = (170, 50) + font = "smoothansi 13" + color = "0,0,128" + text = "This is the Winter theme ... brought to you by GRUB!" +} + +# Show the text alignment supported by labels. ++ vbox { + position = (220, 347) + preferred_size = (200, -1) # A preferred size of -1 means automatic. + + label { text="Text alignment demo" align="center" font="aqui 11" } + + label { text="Left" align="left" font="cure 11" } + + label { text="Center" align="center" font="cure 11" } + + label { text="Right" align="right" font="cure 11" } +} + ++ vbox { + position = (580, 10) + + label { text="GNU" font="gelly 11" color="0, 0, 0" } + + label { text="GRUB" font="aqui 11" color="0, 0, 0" } + + label { text="boot loader" font="cure 11" color="0, 0, 0" } +} + ++ hbox { + position = (80, 10) + + label { text="GNU" font="gelly 11" color="0, 0, 0" } + + label { text="GRUB" font="aqui 11" color="0, 0, 0" } + + label { text="boot loader" font="cure 11" color="0, 0, 0" } +} + +# Demonstration of a compound layout: boxes within boxes. ++ hbox +{ + position = (480, 3) + + + vbox + { + # Note: We can't just use 'size' to set the image's size, + # since the vbox will resize the component according to its + # preferred size, which for images is the native image size. + + + image { file="/boot/grub/themes/icons/ubuntu.png" + preferred_size = (20, 20) } + + image { file="/boot/grub/themes/icons/gentoo.png" + preferred_size = (20, 20) } + } + + + vbox + { + + label { text="GRand" font="cure 11" color=#99F } + + label { text="Unified" font="cure 11" color=#BBF } + + label { text="Bootloader" font="cure 11" color=#DDF } + } +} + +# By defining a 'progress_bar' type component with an ID of '__timeout__', +# the progress bar will be used to display the time remaining before an +# the default entry is automatically booted. ++ progress_bar +{ + id = "__timeout__" + position = (80, 393) + preferred_size = (500, 24) + font = "cure 11" + text_color = #000 + fg_color = #CCF + bg_color = #66B + border_color = #006 + show_text = false +} + +# Although the progress_bar component is normally used to indicate the +# time remaining, it's also possible to create other components with an ID +# of '__timeout__'. All components with and ID of 'timeout_bar' will have +# the following properties set based on the timeout value: +# text, value, start, end, visible. +# In this case, we have set 'show_text=false' on the progress bar, and use +# the following label's 'text' property to display the message. ++ label +{ + id = "__timeout__" + position = (80, 420) + preferred_size = (500, 24) + font = "lime 11" + color = #117 + align = "center" +} + + diff --git a/gfxmenu/gfxmenu.c b/gfxmenu/gfxmenu.c new file mode 100644 index 000000000..85ce5879d --- /dev/null +++ b/gfxmenu/gfxmenu.c @@ -0,0 +1,235 @@ +/* gfxmenu.c - Graphical menu interface controller. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void switch_to_text_menu (void) +{ + grub_env_set ("menuviewer", "text"); +} + +static void +process_key_press (int c, + grub_gfxmenu_model_t model, + grub_gfxmenu_view_t view, + int nested, + int *should_exit) +{ + /* When a key is pressed, stop the timeout. */ + grub_gfxmenu_model_clear_timeout (model); + + if (c == 'j' || c == GRUB_TERM_DOWN) + { + int i = grub_gfxmenu_model_get_selected_index (model); + int num_items = grub_gfxmenu_model_get_num_entries (model); + if (i < num_items - 1) + { + i++; + grub_gfxmenu_model_set_selected_index (model, i); + } + } + else if (c == 'k' || c == GRUB_TERM_UP) + { + int i = grub_gfxmenu_model_get_selected_index (model); + if (i > 0) + { + i--; + grub_gfxmenu_model_set_selected_index (model, i); + } + } + else if (c == '\r' || c == '\n' || c == GRUB_TERM_RIGHT) + { + int selected = grub_gfxmenu_model_get_selected_index (model); + int num_entries = grub_gfxmenu_model_get_num_entries (model); + if (selected >= 0 && selected < num_entries) + { + grub_menu_entry_t entry = + grub_gfxmenu_model_get_entry (model, selected); + grub_gfxmenu_view_execute_entry (view, entry); + } + } + else if (c == 'c') + { + grub_gfxmenu_view_run_terminal (view); + } + else if (c == 't') + { + /* The write hook for 'menuviewer' will cause + * grub_menu_viewer_should_return to return nonzero. */ + switch_to_text_menu (); + *should_exit = 1; + } + else if (c == '1') + { + grub_gfxmenu_view_load_theme (view, + "/boot/grub/themes/proto/theme.txt"); + } + else if (c == '2') + { + grub_gfxmenu_view_load_theme (view, + "/boot/grub/themes/winter/theme.txt"); + } + else if (c == '3') + { + grub_gfxmenu_view_load_theme (view, + "/boot/grub/themes/ubuntu1/theme.txt"); + } + else if (c == '4') + { + grub_gfxmenu_view_load_theme (view, + "/boot/grub/themes/ubuntu2/theme.txt"); + } + else if (nested && c == GRUB_TERM_ESC) + { + *should_exit = 1; + } + + if (grub_errno != GRUB_ERR_NONE) + *should_exit = 1; +} + +static void +handle_key_events (grub_gfxmenu_model_t model, + grub_gfxmenu_view_t view, + int nested, + int *should_exit) +{ + while ((! *should_exit) && (grub_checkkey () != -1)) + { + int key = grub_getkey (); + int c = GRUB_TERM_ASCII_CHAR (key); + process_key_press (c, model, view, nested, should_exit); + } +} + +static grub_err_t +show_menu (grub_menu_t menu, int nested) +{ + grub_gfxmenu_model_t model; + + model = grub_gfxmenu_model_new (menu); + if (! model) + { + grub_print_error (); + grub_printf ("Initializing menu data for graphical menu failed;\n" + "falling back to text based menu.\n"); + grub_wait_after_message (); + switch_to_text_menu (); + return grub_errno; + } + + grub_gfxmenu_view_t view; + + /* Create the view. */ + const char *theme_path = grub_env_get ("theme"); + if (! theme_path) + theme_path = "/boot/grub/themes/proto/theme.txt"; + + view = grub_gfxmenu_view_new (theme_path, model); + if (! view) + { + grub_print_error (); + grub_printf ("Starting graphical menu failed;\n" + "falling back to text based menu.\n"); + grub_wait_after_message (); + grub_gfxmenu_model_destroy (model); + switch_to_text_menu (); + return grub_errno; + } + + /* Initially select the default menu entry. */ + int default_index = grub_menu_get_default_entry_index (menu); + grub_gfxmenu_model_set_selected_index (model, default_index); + + /* Start the timer to execute the default entry. */ + grub_gfxmenu_model_set_timeout (model); + + /* Main event loop. */ + int exit_requested = 0; + while ((! exit_requested) && (! grub_menu_viewer_should_return ())) + { + if (grub_gfxmenu_model_timeout_expired (model)) + { + grub_gfxmenu_model_clear_timeout (model); + int i = grub_gfxmenu_model_get_selected_index (model); + grub_menu_entry_t e = grub_gfxmenu_model_get_entry (model, i); + grub_gfxmenu_view_execute_with_fallback (view, e); + continue; + } + + grub_gfxmenu_view_draw (view); + grub_video_swap_buffers (); + handle_key_events (model, view, nested, &exit_requested); + } + + grub_gfxmenu_view_destroy (view); + grub_gfxmenu_model_destroy (model); + + return grub_errno; +} + +static grub_err_t +grub_cmd_gfxmenu (grub_command_t cmd UNUSED, + int argc UNUSED, char **args UNUSED) +{ + grub_menu_t menu = grub_env_get_data_slot ("menu"); + if (! menu) + return grub_error (GRUB_ERR_MENU, "no menu context"); + + return show_menu (menu, 1); +} + +static struct grub_menu_viewer menu_viewer = +{ + .name = "gfxmenu", + .show_menu = show_menu +}; + +static grub_command_t cmd; + +GRUB_MOD_INIT (gfxmenu) +{ + (void) mod; /* To stop warning. */ + grub_menu_viewer_register (&menu_viewer); + cmd = grub_register_command ("gfxmenu", grub_cmd_gfxmenu, + "gfxmenu", + "Show graphical menu interface"); +} + +GRUB_MOD_FINI (gfxmenu) +{ + grub_unregister_command (cmd); +} diff --git a/gfxmenu/gui_box.c b/gfxmenu/gui_box.c new file mode 100644 index 000000000..876d0733f --- /dev/null +++ b/gfxmenu/gui_box.c @@ -0,0 +1,372 @@ +/* gui_box.c - GUI container that stack components. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include + +struct component_node +{ + grub_gui_component_t component; + struct component_node *next; + struct component_node *prev; +}; + +typedef struct grub_gui_box *grub_gui_box_t; + +typedef void (*layout_func_t) (grub_gui_box_t self, int modify_layout, + int *width, int *height); + +struct grub_gui_box +{ + struct grub_gui_container_ops *container; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int preferred_width; + int preferred_height; + + /* Doubly linked list of components with dummy head & tail nodes. */ + struct component_node chead; + struct component_node ctail; + + /* The layout function: differs for vertical and horizontal boxes. */ + layout_func_t layout_func; +}; + +static void +box_destroy (void *vself) +{ + grub_gui_box_t self = vself; + struct component_node *cur; + struct component_node *next; + for (cur = self->chead.next; cur != &self->ctail; cur = next) + { + /* Copy the 'next' pointer, since we need it for the next iteration, + and we're going to free the memory it is stored in. */ + next = cur->next; + /* Destroy the child component. */ + cur->component->ops->destroy (cur->component); + /* Free the linked list node. */ + grub_free (cur); + } + grub_free (self); +} + +static const char * +box_get_id (void *vself) +{ + grub_gui_box_t self = vself; + return self->id; +} + +static int +box_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return (grub_strcmp (type, "component") == 0 + || grub_strcmp (type, "container") == 0); +} + +static void +layout_horizontally (grub_gui_box_t self, int modify_layout, + int *width, int *height) +{ + /* Start at the left (chead) and set the x coordinates as we go right. */ + /* All components have their width set to the box's width. */ + + struct component_node *cur; + int x = 0; + if (height) + *height = 0; + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { + grub_gui_component_t c = cur->component; + grub_video_rect_t r; + + c->ops->get_preferred_size (c, &r.width, &r.height); + + /* Check and possibly update the maximum width, if non-null. */ + if (height && r.height > *height) + *height = r.height; + + /* Set the component's bounds, if the flag is set. */ + if (modify_layout) + { + r.x = x; + r.y = 0; + /* Width comes from the component's preferred size. */ + r.height = self->bounds.height; + c->ops->set_bounds (c, &r); + } + + x += r.width; + } + + /* Return the sum of the children's preferred widths. */ + if (width) + *width = x; +} + +static void +layout_vertically (grub_gui_box_t self, int modify_layout, + int *width, int *height) +{ + /* Start at the top (chead) and set the y coordinates as we go down. */ + /* All components have their width set to the vbox's width. */ + + struct component_node *cur; + int y = 0; + if (width) + *width = 0; + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { + grub_gui_component_t c = cur->component; + grub_video_rect_t r; + + c->ops->get_preferred_size (c, &r.width, &r.height); + + /* Check and possibly update the maximum width, if non-null. */ + if (width && r.width > *width) + *width = r.width; + + /* Set the component's bounds, if the flag is set. */ + if (modify_layout) + { + r.x = 0; + r.y = y; + r.width = self->bounds.width; + /* Height comes from the component's preferred size. */ + c->ops->set_bounds (c, &r); + } + + y += r.height; + } + + /* Return the sum of the children's preferred heights. */ + if (height) + *height = y; +} + +static void +box_paint (void *vself) +{ + grub_gui_box_t self = vself; + struct component_node *cur; + grub_video_rect_t vpsave; + + grub_gui_set_viewport (&self->bounds, &vpsave); + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { + grub_gui_component_t comp = cur->component; + comp->ops->paint (comp); + } + grub_gui_restore_viewport (&vpsave); +} + +static void +box_set_parent (void *vself, grub_gui_container_t parent) +{ + grub_gui_box_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +box_get_parent (void *vself) +{ + grub_gui_box_t self = vself; + return self->parent; +} + +static void +box_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + grub_gui_box_t self = vself; + self->bounds = *bounds; + self->layout_func (self, 1, 0, 0); /* Relayout the children. */ +} + +static void +box_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + grub_gui_box_t self = vself; + *bounds = self->bounds; +} + +/* The box's preferred size is based on the preferred sizes + of its children. */ +static void +box_get_preferred_size (void *vself, int *width, int *height) +{ + grub_gui_box_t self = vself; + self->layout_func (self, 0, width, height); /* Just calculate the size. */ + + /* Allow preferred dimensions to override the computed dimensions. */ + if (self->preferred_width >= 0) + *width = self->preferred_width; + if (self->preferred_height >= 0) + *height = self->preferred_height; +} + +static grub_err_t +box_set_property (void *vself, const char *name, const char *value) +{ + grub_gui_box_t self = vself; + if (grub_strcmp (name, "id") == 0) + { + grub_free (self->id); + if (value) + { + self->id = grub_strdup (value); + if (! self->id) + return grub_errno; + } + else + self->id = 0; + } + else if (grub_strcmp (name, "preferred_size") == 0) + { + int w; + int h; + if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) + return grub_errno; + self->preferred_width = w; + self->preferred_height = h; + } + + return grub_errno; +} + +static void +box_add (void *vself, grub_gui_component_t comp) +{ + grub_gui_box_t self = vself; + struct component_node *node; + node = grub_malloc (sizeof (*node)); + if (! node) + return; /* Note: probably should handle the error. */ + node->component = comp; + /* Insert the node before the tail. */ + node->prev = self->ctail.prev; + node->prev->next = node; + node->next = &self->ctail; + node->next->prev = node; + + comp->ops->set_parent (comp, (grub_gui_container_t) self); + self->layout_func (self, 1, 0, 0); /* Relayout the children. */ +} + +static void +box_remove (void *vself, grub_gui_component_t comp) +{ + grub_gui_box_t self = vself; + struct component_node *cur; + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { + if (cur->component == comp) + { + /* Unlink 'cur' from the list. */ + cur->prev->next = cur->next; + cur->next->prev = cur->prev; + /* Free the node's memory (but don't destroy the component). */ + grub_free (cur); + /* Must not loop again, since 'cur' would be dereferenced! */ + return; + } + } +} + +static void +box_iterate_children (void *vself, + grub_gui_component_callback cb, void *userdata) +{ + grub_gui_box_t self = vself; + struct component_node *cur; + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + cb (cur->component, userdata); +} + +static struct grub_gui_container_ops box_ops = +{ + .component = + { + .destroy = box_destroy, + .get_id = box_get_id, + .is_instance = box_is_instance, + .paint = box_paint, + .set_parent = box_set_parent, + .get_parent = box_get_parent, + .set_bounds = box_set_bounds, + .get_bounds = box_get_bounds, + .get_preferred_size = box_get_preferred_size, + .set_property = box_set_property + }, + .add = box_add, + .remove = box_remove, + .iterate_children = box_iterate_children +}; + +/* Box constructor. Specify the appropriate layout function to create + a horizontal or vertical stacking box. */ +static grub_gui_box_t +box_new (layout_func_t layout_func) +{ + grub_gui_box_t box; + box = grub_malloc (sizeof (*box)); + if (! box) + return 0; + box->container = &box_ops; + box->parent = 0; + box->bounds.x = 0; + box->bounds.y = 0; + box->bounds.width = 0; + box->bounds.height = 0; + box->id = 0; + box->preferred_width = -1; + box->preferred_height = -1; + box->chead.component = 0; + box->chead.prev = 0; + box->chead.next = &box->ctail; + box->ctail.component = 0; + box->ctail.prev = &box->chead; + box->ctail.next = 0; + box->layout_func = layout_func; + return box; +} + +/* Create a new container that stacks its child components horizontally, + from left to right. Each child get a width corresponding to its + preferred width. The height of each child is set the maximum of the + preferred heights of all children. */ +grub_gui_container_t +grub_gui_hbox_new (void) +{ + return (grub_gui_container_t) box_new (layout_horizontally); +} + +/* Create a new container that stacks its child components verticallyj, + from top to bottom. Each child get a height corresponding to its + preferred height. The width of each child is set the maximum of the + preferred widths of all children. */ +grub_gui_container_t +grub_gui_vbox_new (void) +{ + return (grub_gui_container_t) box_new (layout_vertically); +} diff --git a/gfxmenu/gui_canvas.c b/gfxmenu/gui_canvas.c new file mode 100644 index 000000000..a2cd77df6 --- /dev/null +++ b/gfxmenu/gui_canvas.c @@ -0,0 +1,268 @@ +/* gui_canvas.c - GUI container allowing manually placed components. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include + +/* TODO Add layering so that components can be properly overlaid. */ + +struct component_node +{ + grub_gui_component_t component; + struct component_node *next; +}; + +struct grub_gui_canvas +{ + struct grub_gui_container_ops *container; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int preferred_width; + int preferred_height; + /* Component list (dummy head node). */ + struct component_node components; +}; + +typedef struct grub_gui_canvas *grub_gui_canvas_t; + +static void +canvas_destroy (void *vself) +{ + grub_gui_canvas_t self = vself; + struct component_node *cur; + struct component_node *next; + for (cur = self->components.next; cur; cur = next) + { + /* Copy the 'next' pointer, since we need it for the next iteration, + and we're going to free the memory it is stored in. */ + next = cur->next; + /* Destroy the child component. */ + cur->component->ops->destroy (cur->component); + /* Free the linked list node. */ + grub_free (cur); + } + grub_free (self); +} + +static const char * +canvas_get_id (void *vself) +{ + grub_gui_canvas_t self = vself; + return self->id; +} + +static int +canvas_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return (grub_strcmp (type, "component") == 0 + || grub_strcmp (type, "container") == 0); +} + +static void +canvas_paint (void *vself) +{ + grub_gui_canvas_t self = vself; + struct component_node *cur; + grub_video_rect_t vpsave; + + grub_gui_set_viewport (&self->bounds, &vpsave); + for (cur = self->components.next; cur; cur = cur->next) + { + int pw; + int ph; + grub_video_rect_t r; + grub_gui_component_t comp; + + comp = cur->component; + + /* Give the child its preferred size. */ + comp->ops->get_preferred_size (comp, &pw, &ph); + comp->ops->get_bounds (comp, &r); + if (r.width != pw || r.height != ph) + { + r.width = pw; + r.height = ph; + comp->ops->set_bounds (comp, &r); + } + + /* Paint the child. */ + comp->ops->paint (comp); + } + grub_gui_restore_viewport (&vpsave); +} + +static void +canvas_set_parent (void *vself, grub_gui_container_t parent) +{ + grub_gui_canvas_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +canvas_get_parent (void *vself) +{ + grub_gui_canvas_t self = vself; + return self->parent; +} + +static void +canvas_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + grub_gui_canvas_t self = vself; + self->bounds = *bounds; +} + +static void +canvas_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + grub_gui_canvas_t self = vself; + *bounds = self->bounds; +} + +static void +canvas_get_preferred_size (void *vself, int *width, int *height) +{ + grub_gui_canvas_t self = vself; + *width = 0; + *height = 0; + + /* Allow preferred dimensions to override the empty dimensions. */ + if (self->preferred_width >= 0) + *width = self->preferred_width; + if (self->preferred_height >= 0) + *height = self->preferred_height; +} + +static grub_err_t +canvas_set_property (void *vself, const char *name, const char *value) +{ + grub_gui_canvas_t self = vself; + if (grub_strcmp (name, "id") == 0) + { + grub_free (self->id); + if (value) + { + self->id = grub_strdup (value); + if (! self->id) + return grub_errno; + } + else + self->id = 0; + } + else if (grub_strcmp (name, "preferred_size") == 0) + { + int w; + int h; + if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) + return grub_errno; + self->preferred_width = w; + self->preferred_height = h; + } + return grub_errno; +} + +static void +canvas_add (void *vself, grub_gui_component_t comp) +{ + grub_gui_canvas_t self = vself; + struct component_node *node; + node = grub_malloc (sizeof (*node)); + if (! node) + return; /* Note: probably should handle the error. */ + node->component = comp; + node->next = self->components.next; + self->components.next = node; + comp->ops->set_parent (comp, (grub_gui_container_t) self); +} + +static void +canvas_remove (void *vself, grub_gui_component_t comp) +{ + grub_gui_canvas_t self = vself; + struct component_node *cur; + struct component_node *prev; + prev = &self->components; + for (cur = self->components.next; cur; prev = cur, cur = cur->next) + { + if (cur->component == comp) + { + /* Unlink 'cur' from the list. */ + prev->next = cur->next; + /* Free the node's memory (but don't destroy the component). */ + grub_free (cur); + /* Must not loop again, since 'cur' would be dereferenced! */ + return; + } + } +} + +static void +canvas_iterate_children (void *vself, + grub_gui_component_callback cb, void *userdata) +{ + grub_gui_canvas_t self = vself; + struct component_node *cur; + for (cur = self->components.next; cur; cur = cur->next) + cb (cur->component, userdata); +} + +static struct grub_gui_container_ops canvas_ops = +{ + .component = + { + .destroy = canvas_destroy, + .get_id = canvas_get_id, + .is_instance = canvas_is_instance, + .paint = canvas_paint, + .set_parent = canvas_set_parent, + .get_parent = canvas_get_parent, + .set_bounds = canvas_set_bounds, + .get_bounds = canvas_get_bounds, + .get_preferred_size = canvas_get_preferred_size, + .set_property = canvas_set_property + }, + .add = canvas_add, + .remove = canvas_remove, + .iterate_children = canvas_iterate_children +}; + +grub_gui_container_t +grub_gui_canvas_new (void) +{ + grub_gui_canvas_t canvas; + canvas = grub_malloc (sizeof (*canvas)); + if (! canvas) + return 0; + canvas->container = &canvas_ops; + canvas->parent = 0; + canvas->bounds.x = 0; + canvas->bounds.y = 0; + canvas->bounds.width = 0; + canvas->bounds.height = 0; + canvas->id = 0; + canvas->preferred_width = -1; + canvas->preferred_height = -1; + canvas->components.component = 0; + canvas->components.next = 0; + return (grub_gui_container_t) canvas; +} diff --git a/gfxmenu/gui_circular_progress.c b/gfxmenu/gui_circular_progress.c new file mode 100644 index 000000000..cd95c51f9 --- /dev/null +++ b/gfxmenu/gui_circular_progress.c @@ -0,0 +1,339 @@ +/* gui_circular_process.c - GUI circular progress indicator component. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct grub_gui_circular_progress +{ + struct grub_gui_component_ops *circprog_ops; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int preferred_width; + int preferred_height; + int visible; + int start; + int end; + int value; + int num_ticks; + int start_angle; + int ticks_disappear; + char *theme_dir; + int need_to_load_pixmaps; + char *center_file; + char *tick_file; + struct grub_video_bitmap *center_bitmap; + struct grub_video_bitmap *tick_bitmap; +}; + +typedef struct grub_gui_circular_progress *circular_progress_t; + +static void +circprog_destroy (void *vself) +{ + circular_progress_t self = vself; + grub_free (self); +} + +static const char * +circprog_get_id (void *vself) +{ + circular_progress_t self = vself; + return self->id; +} + +static int +circprog_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return grub_strcmp (type, "component") == 0; +} + +static struct grub_video_bitmap * +load_bitmap (const char *dir, const char *file) +{ + struct grub_video_bitmap *bitmap; + char *abspath; + + /* Check arguments. */ + if (! dir || ! file) + return 0; + + /* Resolve to an absolute path. */ + abspath = grub_resolve_relative_path (dir, file); + if (! abspath) + return 0; + + /* Load the image. */ + grub_errno = GRUB_ERR_NONE; + grub_video_bitmap_load (&bitmap, abspath); + grub_errno = GRUB_ERR_NONE; + + grub_free (abspath); + return bitmap; +} + +static int +check_pixmaps (circular_progress_t self) +{ + if (self->need_to_load_pixmaps) + { + if (self->center_bitmap) + grub_video_bitmap_destroy (self->center_bitmap); + self->center_bitmap = load_bitmap (self->theme_dir, self->center_file); + self->tick_bitmap = load_bitmap (self->theme_dir, self->tick_file); + self->need_to_load_pixmaps = 0; + } + + return (self->center_bitmap != 0 && self->tick_bitmap != 0); +} + +static void +circprog_paint (void *vself) +{ + circular_progress_t self = vself; + + if (! self->visible) + return; + if (! check_pixmaps (self)) + return; + + grub_video_rect_t vpsave; + grub_gui_set_viewport (&self->bounds, &vpsave); + + int width = self->bounds.width; + int height = self->bounds.height; + int center_width = grub_video_bitmap_get_width (self->center_bitmap); + int center_height = grub_video_bitmap_get_height (self->center_bitmap); + int tick_width = grub_video_bitmap_get_width (self->tick_bitmap); + int tick_height = grub_video_bitmap_get_height (self->tick_bitmap); + grub_video_blit_bitmap (self->center_bitmap, GRUB_VIDEO_BLIT_BLEND, + (width - center_width) / 2, + (height - center_height) / 2, 0, 0, + center_width, center_height); + + int radius = width / 2 - tick_width / 2 - 1; + int nticks = (self->num_ticks + * (self->value - self->start) + / (self->end - self->start)); + int tick_begin; + int tick_end; + /* Do ticks appear or disappear as the value approached the end? */ + if (self->ticks_disappear) + { + tick_begin = nticks; + tick_end = self->num_ticks - 1; + } + else + { + tick_begin = 0; + tick_end = nticks - 1; + } + + int i; + for (i = tick_begin; i < tick_end; i++) + { + int x; + int y; + int angle; + + /* Calculate the location of the tick. */ + angle = self->start_angle + i * GRUB_TRIG_ANGLE_MAX / self->num_ticks; + x = width / 2 + (grub_cos (angle) * radius / GRUB_TRIG_FRACTION_SCALE); + y = height / 2 + (grub_sin (angle) * radius / GRUB_TRIG_FRACTION_SCALE); + + /* Adjust (x,y) so the tick is centered. */ + x -= tick_width / 2; + y -= tick_height / 2; + + /* Draw the tick. */ + grub_video_blit_bitmap (self->tick_bitmap, GRUB_VIDEO_BLIT_BLEND, + x, y, 0, 0, tick_width, tick_height); + } + + grub_gui_restore_viewport (&vpsave); +} + +static void +circprog_set_parent (void *vself, grub_gui_container_t parent) +{ + circular_progress_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +circprog_get_parent (void *vself) +{ + circular_progress_t self = vself; + return self->parent; +} + +static void +circprog_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + circular_progress_t self = vself; + self->bounds = *bounds; +} + +static void +circprog_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + circular_progress_t self = vself; + *bounds = self->bounds; +} + +static void +circprog_get_preferred_size (void *vself, int *width, int *height) +{ + circular_progress_t self = vself; + + *width = 0; + *height = 0; + + /* Allow preferred dimensions to override the circprog dimensions. */ + if (self->preferred_width >= 0) + *width = self->preferred_width; + if (self->preferred_height >= 0) + *height = self->preferred_height; +} + +static grub_err_t +circprog_set_property (void *vself, const char *name, const char *value) +{ + circular_progress_t self = vself; + if (grub_strcmp (name, "value") == 0) + { + self->value = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "start") == 0) + { + self->start = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "end") == 0) + { + self->end = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "num_ticks") == 0) + { + self->num_ticks = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "start_angle") == 0) + { + self->start_angle = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "ticks_disappear") == 0) + { + self->ticks_disappear = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "center_bitmap") == 0) + { + self->need_to_load_pixmaps = 1; + grub_free (self->center_file); + self->center_file = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "tick_bitmap") == 0) + { + self->need_to_load_pixmaps = 1; + grub_free (self->tick_file); + self->tick_file = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "theme_dir") == 0) + { + self->need_to_load_pixmaps = 1; + grub_free (self->theme_dir); + self->theme_dir = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "preferred_size") == 0) + { + int w; + int h; + if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) + return grub_errno; + self->preferred_width = w; + self->preferred_height = h; + } + else if (grub_strcmp (name, "visible") == 0) + { + self->visible = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "id") == 0) + { + grub_free (self->id); + if (value) + self->id = grub_strdup (value); + else + self->id = 0; + } + return grub_errno; +} + +static struct grub_gui_component_ops circprog_ops = +{ + .destroy = circprog_destroy, + .get_id = circprog_get_id, + .is_instance = circprog_is_instance, + .paint = circprog_paint, + .set_parent = circprog_set_parent, + .get_parent = circprog_get_parent, + .set_bounds = circprog_set_bounds, + .get_bounds = circprog_get_bounds, + .get_preferred_size = circprog_get_preferred_size, + .set_property = circprog_set_property +}; + +grub_gui_component_t +grub_gui_circular_progress_new (void) +{ + circular_progress_t self; + self = grub_malloc (sizeof (*self)); + if (! self) + return 0; + self->circprog_ops = &circprog_ops; + self->parent = 0; + self->bounds.x = 0; + self->bounds.y = 0; + self->bounds.width = 0; + self->bounds.height = 0; + self->id = 0; + self->preferred_width = -1; + self->preferred_height = -1; + self->visible = 1; + self->start = 0; + self->end = 0; + self->value = 0; + self->num_ticks = 64; + self->start_angle = -64; + self->ticks_disappear = 0; + + self->theme_dir = 0; + self->need_to_load_pixmaps = 0; + self->center_file = 0; + self->tick_file = 0; + self->center_bitmap = 0; + self->tick_bitmap = 0; + + return (grub_gui_component_t) self; +} diff --git a/gfxmenu/gui_image.c b/gfxmenu/gui_image.c new file mode 100644 index 000000000..1c58a535b --- /dev/null +++ b/gfxmenu/gui_image.c @@ -0,0 +1,270 @@ +/* gui_image.c - GUI component to display an image. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +struct grub_gui_image +{ + struct grub_gui_component_ops *image; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int preferred_width; + int preferred_height; + struct grub_video_bitmap *raw_bitmap; + struct grub_video_bitmap *bitmap; +}; + +typedef struct grub_gui_image *grub_gui_image_t; + +static void +image_destroy (void *vself) +{ + grub_gui_image_t self = vself; + + /* Free the scaled bitmap, unless it's a reference to the raw bitmap. */ + if (self->bitmap && (self->bitmap != self->raw_bitmap)) + grub_video_bitmap_destroy (self->bitmap); + if (self->raw_bitmap) + grub_video_bitmap_destroy (self->raw_bitmap); + + grub_free (self); +} + +static const char * +image_get_id (void *vself) +{ + grub_gui_image_t self = vself; + return self->id; +} + +static int +image_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return grub_strcmp (type, "component") == 0; +} + +static void +image_paint (void *vself) +{ + grub_gui_image_t self = vself; + if (! self->bitmap) + return; + grub_video_rect_t vpsave; + grub_gui_set_viewport (&self->bounds, &vpsave); + grub_video_blit_bitmap (self->bitmap, GRUB_VIDEO_BLIT_BLEND, + 0, 0, 0, 0, + grub_video_bitmap_get_width (self->bitmap), + grub_video_bitmap_get_height (self->bitmap)); + grub_gui_restore_viewport (&vpsave); +} + +static void +image_set_parent (void *vself, grub_gui_container_t parent) +{ + grub_gui_image_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +image_get_parent (void *vself) +{ + grub_gui_image_t self = vself; + return self->parent; +} + +static grub_err_t +rescale_image (grub_gui_image_t self) +{ + if (! self->raw_bitmap) + { + if (self->bitmap) + { + grub_video_bitmap_destroy (self->bitmap); + self->bitmap = 0; + } + return grub_errno; + } + + unsigned width = self->bounds.width; + unsigned height = self->bounds.height; + + if (self->bitmap + && (grub_video_bitmap_get_width (self->bitmap) == width) + && (grub_video_bitmap_get_height (self->bitmap) == height)) + { + /* Nothing to do; already the right size. */ + return grub_errno; + } + + /* Free any old scaled bitmap, + *unless* it's a reference to the raw bitmap. */ + if (self->bitmap && (self->bitmap != self->raw_bitmap)) + grub_video_bitmap_destroy (self->bitmap); + + self->bitmap = 0; + + /* Create a scaled bitmap, unless the requested size is the same + as the raw size -- in that case a reference is made. */ + if (grub_video_bitmap_get_width (self->raw_bitmap) == width + && grub_video_bitmap_get_height (self->raw_bitmap) == height) + { + self->bitmap = self->raw_bitmap; + return grub_errno; + } + + /* Don't scale to an invalid size. */ + if (width == 0 || height == 0) + return grub_errno; + + /* Create the scaled bitmap. */ + grub_video_bitmap_create_scaled (&self->bitmap, + width, + height, + self->raw_bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + if (grub_errno != GRUB_ERR_NONE) + { + grub_error_push (); + grub_error (grub_errno, "failed to scale bitmap for image component"); + } + return grub_errno; +} + +static void +image_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + grub_gui_image_t self = vself; + self->bounds = *bounds; + rescale_image (self); +} + +static void +image_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + grub_gui_image_t self = vself; + *bounds = self->bounds; +} + +static void +image_get_preferred_size (void *vself, int *width, int *height) +{ + grub_gui_image_t self = vself; + + if (self->raw_bitmap) + { + *width = grub_video_bitmap_get_width (self->raw_bitmap); + *height = grub_video_bitmap_get_height (self->raw_bitmap); + } + else + { + *width = 0; + *height = 0; + } + + /* Allow preferred dimensions to override the image dimensions. */ + if (self->preferred_width >= 0) + *width = self->preferred_width; + if (self->preferred_height >= 0) + *height = self->preferred_height; +} + +static grub_err_t +load_image (grub_gui_image_t self, const char *path) +{ + struct grub_video_bitmap *bitmap; + if (grub_video_bitmap_load (&bitmap, path) != GRUB_ERR_NONE) + return grub_errno; + + if (self->bitmap && (self->bitmap != self->raw_bitmap)) + grub_video_bitmap_destroy (self->bitmap); + if (self->raw_bitmap) + grub_video_bitmap_destroy (self->raw_bitmap); + + self->raw_bitmap = bitmap; + return rescale_image (self); +} + +static grub_err_t +image_set_property (void *vself, const char *name, const char *value) +{ + grub_gui_image_t self = vself; + if (grub_strcmp (name, "file") == 0) + return load_image (self, value); + else if (grub_strcmp (name, "preferred_size") == 0) + { + int w; + int h; + if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) + return grub_errno; + self->preferred_width = w; + self->preferred_height = h; + } + else if (grub_strcmp (name, "id") == 0) + { + grub_free (self->id); + if (value) + self->id = grub_strdup (value); + else + self->id = 0; + } + return grub_errno; +} + +static struct grub_gui_component_ops image_ops = +{ + .destroy = image_destroy, + .get_id = image_get_id, + .is_instance = image_is_instance, + .paint = image_paint, + .set_parent = image_set_parent, + .get_parent = image_get_parent, + .set_bounds = image_set_bounds, + .get_bounds = image_get_bounds, + .get_preferred_size = image_get_preferred_size, + .set_property = image_set_property +}; + +grub_gui_component_t +grub_gui_image_new (void) +{ + grub_gui_image_t image; + image = grub_malloc (sizeof (*image)); + if (! image) + return 0; + image->image = &image_ops; + image->parent = 0; + image->bounds.x = 0; + image->bounds.y = 0; + image->bounds.width = 0; + image->bounds.height = 0; + image->id = 0; + image->preferred_width = -1; + image->preferred_height = -1; + image->raw_bitmap = 0; + image->bitmap = 0; + return (grub_gui_component_t) image; +} + diff --git a/gfxmenu/gui_label.c b/gfxmenu/gui_label.c new file mode 100644 index 000000000..2e49c787e --- /dev/null +++ b/gfxmenu/gui_label.c @@ -0,0 +1,248 @@ +/* gui_label.c - GUI component to display a line of text. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +static const char *align_options[] = +{ + "left", + "center", + "right", + 0 +}; + +enum align_mode { + align_left, + align_center, + align_right +}; + +struct grub_gui_label +{ + struct grub_gui_component_ops *label; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int preferred_width; + int preferred_height; + int visible; + char *text; + grub_font_t font; + grub_gui_color_t color; + enum align_mode align; +}; + +typedef struct grub_gui_label *grub_gui_label_t; + +static void +label_destroy (void *vself) +{ + grub_gui_label_t self = vself; + grub_free (self->text); + grub_free (self); +} + +static const char * +label_get_id (void *vself) +{ + grub_gui_label_t self = vself; + return self->id; +} + +static int +label_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return grub_strcmp (type, "component") == 0; +} + +static void +label_paint (void *vself) +{ + grub_gui_label_t self = vself; + + if (! self->visible) + return; + + /* Calculate the starting x coordinate. */ + int left_x; + if (self->align == align_left) + left_x = 0; + else if (self->align == align_center) + left_x = ((self->bounds.width + - grub_font_get_string_width (self->font, self->text)) + ) / 2; + else if (self->align == align_right) + left_x = (self->bounds.width + - grub_font_get_string_width (self->font, self->text)); + else + return; /* Invalid alignment. */ + + grub_video_rect_t vpsave; + grub_gui_set_viewport (&self->bounds, &vpsave); + grub_font_draw_string (self->text, + self->font, + grub_gui_map_color (self->color), + left_x, + grub_font_get_ascent (self->font)); + grub_gui_restore_viewport (&vpsave); +} + +static void +label_set_parent (void *vself, grub_gui_container_t parent) +{ + grub_gui_label_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +label_get_parent (void *vself) +{ + grub_gui_label_t self = vself; + return self->parent; +} + +static void +label_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + grub_gui_label_t self = vself; + self->bounds = *bounds; +} + +static void +label_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + grub_gui_label_t self = vself; + *bounds = self->bounds; +} + +static void +label_get_preferred_size (void *vself, int *width, int *height) +{ + grub_gui_label_t self = vself; + *width = grub_font_get_string_width (self->font, self->text); + *height = (grub_font_get_ascent (self->font) + + grub_font_get_descent (self->font)); + + /* Allow preferred dimensions to override the computed dimensions. */ + if (self->preferred_width >= 0) + *width = self->preferred_width; + if (self->preferred_height >= 0) + *height = self->preferred_height; +} + +static void +label_set_property (void *vself, const char *name, const char *value) +{ + grub_gui_label_t self = vself; + if (grub_strcmp (name, "text") == 0) + { + grub_free (self->text); + if (! value) + value = ""; + self->text = grub_strdup (value); + } + else if (grub_strcmp (name, "font") == 0) + { + self->font = grub_font_get (value); + } + else if (grub_strcmp (name, "color") == 0) + { + grub_gui_parse_color (value, &self->color); + } + else if (grub_strcmp (name, "align") == 0) + { + int i; + for (i = 0; align_options[i]; i++) + { + if (grub_strcmp (align_options[i], value) == 0) + { + self->align = i; /* Set the alignment mode. */ + break; + } + } + } + else if (grub_strcmp (name, "visible") == 0) + { + self->visible = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "preferred_size") == 0) + { + int w; + int h; + if (grub_gui_parse_2_tuple (value, &w, &h) == GRUB_ERR_NONE) + { + self->preferred_width = w; + self->preferred_height = h; + } + } + else if (grub_strcmp (name, "id") == 0) + { + grub_free (self->id); + if (value) + self->id = grub_strdup (value); + else + self->id = 0; + } +} + +static struct grub_gui_component_ops label_ops = +{ + .destroy = label_destroy, + .get_id = label_get_id, + .is_instance = label_is_instance, + .paint = label_paint, + .set_parent = label_set_parent, + .get_parent = label_get_parent, + .set_bounds = label_set_bounds, + .get_bounds = label_get_bounds, + .get_preferred_size = label_get_preferred_size, + .set_property = label_set_property +}; + +grub_gui_component_t +grub_gui_label_new (void) +{ + grub_gui_label_t label; + label = grub_malloc (sizeof (*label)); + if (! label) + return 0; + label->label = &label_ops; + label->parent = 0; + label->bounds.x = 0; + label->bounds.y = 0; + label->bounds.width = 0; + label->bounds.height = 0; + label->id = 0; + label->preferred_width = -1; + label->preferred_height = -1; + label->visible = 1; + label->text = grub_strdup (""); + label->font = grub_font_get ("Helvetica 10"); + label->color.red = 0; + label->color.green = 0; + label->color.blue = 0; + label->color.alpha = 255; + label->align = align_left; + return (grub_gui_component_t) label; +} diff --git a/gfxmenu/gui_list.c b/gfxmenu/gui_list.c new file mode 100644 index 000000000..aa9655b45 --- /dev/null +++ b/gfxmenu/gui_list.c @@ -0,0 +1,625 @@ +/* gui_list.c - GUI component to display a selectable list of items. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +struct grub_gui_list_impl +{ + struct grub_gui_list_ops *list_ops; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int preferred_width; + int preferred_height; + int visible; + + int icon_width; + int icon_height; + int item_height; + int item_padding; + int item_icon_space; + int item_spacing; + grub_font_t item_font; + grub_font_t selected_item_font; + grub_gui_color_t item_color; + int selected_item_color_set; + grub_gui_color_t selected_item_color; + + int draw_scrollbar; + int need_to_recreate_scrollbar; + char *scrollbar_frame_pattern; + char *scrollbar_thumb_pattern; + grub_gfxmenu_box_t scrollbar_frame; + grub_gfxmenu_box_t scrollbar_thumb; + int scrollbar_width; + + int min_items_shown; + int max_items_shown; + int first_shown_index; + + int need_to_recreate_boxes; + char *theme_dir; + char *menu_box_pattern; + char *selected_item_box_pattern; + grub_gfxmenu_box_t menu_box; + grub_gfxmenu_box_t selected_item_box; + + grub_gfxmenu_icon_manager_t icon_manager; + grub_gfxmenu_model_t menu; +}; + +typedef struct grub_gui_list_impl *list_impl_t; + +static void +list_destroy (void *vself) +{ + list_impl_t self = vself; + + grub_free (self->theme_dir); + grub_free (self->menu_box_pattern); + grub_free (self->selected_item_box_pattern); + if (self->menu_box) + self->menu_box->destroy (self->menu_box); + if (self->selected_item_box) + self->selected_item_box->destroy (self->selected_item_box); + if (self->icon_manager) + grub_gfxmenu_icon_manager_destroy (self->icon_manager); + + grub_free (self); +} + +static int +get_num_shown_items (list_impl_t self) +{ + int n = grub_gfxmenu_model_get_num_entries (self->menu); + if (self->min_items_shown != -1 && n < self->min_items_shown) + n = self->min_items_shown; + if (self->max_items_shown != -1 && n > self->max_items_shown) + n = self->max_items_shown; + return n; +} + +static int +check_boxes (list_impl_t self) +{ + if (self->need_to_recreate_boxes) + { + grub_gui_recreate_box (&self->menu_box, + self->menu_box_pattern, + self->theme_dir); + + grub_gui_recreate_box (&self->selected_item_box, + self->selected_item_box_pattern, + self->theme_dir); + + self->need_to_recreate_boxes = 0; + } + + return (self->menu_box != 0 && self->selected_item_box != 0); +} + +static int +check_scrollbar (list_impl_t self) +{ + if (self->need_to_recreate_scrollbar) + { + grub_gui_recreate_box (&self->scrollbar_frame, + self->scrollbar_frame_pattern, + self->theme_dir); + + grub_gui_recreate_box (&self->scrollbar_thumb, + self->scrollbar_thumb_pattern, + self->theme_dir); + + self->need_to_recreate_scrollbar = 0; + } + + return (self->scrollbar_frame != 0 && self->scrollbar_thumb != 0); +} + +static const char * +list_get_id (void *vself) +{ + list_impl_t self = vself; + return self->id; +} + +static int +list_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return (grub_strcmp (type, "component") == 0 + || grub_strcmp (type, "list") == 0); +} + +static struct grub_video_bitmap * +get_item_icon (list_impl_t self, int item_index) +{ + grub_menu_entry_t entry; + entry = grub_gfxmenu_model_get_entry (self->menu, item_index); + if (! entry) + return 0; + + return grub_gfxmenu_icon_manager_get_icon (self->icon_manager, entry); +} + +static void +make_selected_item_visible (list_impl_t self) +{ + int selected_index = grub_gfxmenu_model_get_selected_index (self->menu); + if (selected_index < 0) + return; /* No item is selected. */ + int num_shown_items = get_num_shown_items (self); + int last_shown_index = self->first_shown_index + (num_shown_items - 1); + if (selected_index < self->first_shown_index) + self->first_shown_index = selected_index; + else if (selected_index > last_shown_index) + self->first_shown_index = selected_index - (num_shown_items - 1); +} + +/* Draw a scrollbar on the menu. */ +static void +draw_scrollbar (list_impl_t self, + int value, int extent, int min, int max, + int rightx, int topy, int height) +{ + grub_gfxmenu_box_t frame = self->scrollbar_frame; + grub_gfxmenu_box_t thumb = self->scrollbar_thumb; + int frame_vertical_pad = (frame->get_top_pad (frame) + + frame->get_bottom_pad (frame)); + int frame_horizontal_pad = (frame->get_left_pad (frame) + + frame->get_right_pad (frame)); + int tracktop = topy + frame->get_top_pad (frame); + int tracklen = height - frame_vertical_pad; + frame->set_content_size (frame, self->scrollbar_width, tracklen); + int thumby = tracktop + tracklen * (value - min) / (max - min); + int thumbheight = tracklen * extent / (max - min) + 1; + thumb->set_content_size (thumb, + self->scrollbar_width - frame_horizontal_pad, + thumbheight - (thumb->get_top_pad (thumb) + + thumb->get_bottom_pad (thumb))); + frame->draw (frame, + rightx - (self->scrollbar_width + frame_horizontal_pad), + topy); + thumb->draw (thumb, + rightx - (self->scrollbar_width - frame->get_right_pad (frame)), + thumby); +} + +/* Draw the list of items. */ +static void +draw_menu (list_impl_t self) +{ + if (! self->menu_box || ! self->selected_item_box) + return; + + int boxpad = self->item_padding; + int icon_text_space = self->item_icon_space; + int item_vspace = self->item_spacing; + + int ascent = grub_font_get_ascent (self->item_font); + int descent = grub_font_get_descent (self->item_font); + int item_height = self->item_height; + + int total_num_items = grub_gfxmenu_model_get_num_entries (self->menu); + int num_shown_items = get_num_shown_items (self); + grub_gfxmenu_box_t box = self->menu_box; + int width = self->bounds.width; + int height = self->bounds.height; + + int box_left_pad = box->get_left_pad (box); + int box_top_pad = box->get_top_pad (box); + int box_right_pad = box->get_right_pad (box); + int box_bottom_pad = box->get_bottom_pad (box); + + box->set_content_size (box, + width - box_left_pad - box_right_pad, + height - box_top_pad - box_bottom_pad); + + box->draw (box, 0, 0); + + make_selected_item_visible (self); + + int drawing_scrollbar = (self->draw_scrollbar + && (num_shown_items < total_num_items) + && check_scrollbar (self)); + + int scrollbar_h_space = drawing_scrollbar ? self->scrollbar_width : 0; + + int item_top = box_top_pad + boxpad; + int item_left = box_left_pad + boxpad; + int menu_index; + int visible_index; + + for (visible_index = 0, menu_index = self->first_shown_index; + visible_index < num_shown_items && menu_index < total_num_items; + visible_index++, menu_index++) + { + int is_selected = + (menu_index == grub_gfxmenu_model_get_selected_index (self->menu)); + + if (is_selected) + { + grub_gfxmenu_box_t selbox = self->selected_item_box; + int sel_leftpad = selbox->get_left_pad (selbox); + int sel_toppad = selbox->get_top_pad (selbox); + selbox->set_content_size (selbox, + (width - 2 * boxpad + - box_left_pad - box_right_pad + - scrollbar_h_space), + item_height); + selbox->draw (selbox, + item_left - sel_leftpad, + item_top - sel_toppad); + } + + struct grub_video_bitmap *icon; + if ((icon = get_item_icon (self, menu_index)) != 0) + grub_video_blit_bitmap (icon, GRUB_VIDEO_BLIT_BLEND, + item_left, + item_top + (item_height - self->icon_height) / 2, + 0, 0, self->icon_width, self->icon_height); + + const char *item_title = + grub_gfxmenu_model_get_entry_title (self->menu, menu_index); + grub_font_t font = + (is_selected && self->selected_item_font + ? self->selected_item_font + : self->item_font); + grub_gui_color_t text_color = + ((is_selected && self->selected_item_color_set) + ? self->selected_item_color + : self->item_color); + grub_font_draw_string (item_title, + font, + grub_gui_map_color (text_color), + item_left + self->icon_width + icon_text_space, + (item_top + (item_height - (ascent + descent)) + / 2 + ascent)); + + item_top += item_height + item_vspace; + } + + if (drawing_scrollbar) + draw_scrollbar (self, + self->first_shown_index, num_shown_items, + 0, total_num_items, + width - box_right_pad + self->scrollbar_width, + box_top_pad + boxpad, + height - box_top_pad - box_bottom_pad); +} + +static void +list_paint (void *vself) +{ + list_impl_t self = vself; + + if (! self->visible) + return; + + check_boxes (self); + + grub_video_rect_t vpsave; + grub_gui_set_viewport (&self->bounds, &vpsave); + draw_menu (self); + grub_gui_restore_viewport (&vpsave); +} + +static void +list_set_parent (void *vself, grub_gui_container_t parent) +{ + list_impl_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +list_get_parent (void *vself) +{ + list_impl_t self = vself; + return self->parent; +} + +static void +list_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + list_impl_t self = vself; + self->bounds = *bounds; +} + +static void +list_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + list_impl_t self = vself; + *bounds = self->bounds; +} + +static void +list_get_preferred_size (void *vself, int *width, int *height) +{ + list_impl_t self = vself; + + if (check_boxes (self)) + { + int boxpad = self->item_padding; + int item_vspace = self->item_spacing; + int item_height = self->item_height; + int num_items = get_num_shown_items (self); + + grub_gfxmenu_box_t box = self->menu_box; + int box_left_pad = box->get_left_pad (box); + int box_top_pad = box->get_top_pad (box); + int box_right_pad = box->get_right_pad (box); + int box_bottom_pad = box->get_bottom_pad (box); + + *width = 400 + 2 * boxpad + box_left_pad + box_right_pad; + + /* Set the menu box height to fit the items. */ + *height = (item_height * num_items + + item_vspace * (num_items - 1) + + 2 * boxpad + + box_top_pad + box_bottom_pad); + } + else + { + *width = 0; + *height = 0; + } + + /* Allow preferred dimensions to override the computed dimensions. */ + if (self->preferred_width >= 0) + *width = self->preferred_width; + if (self->preferred_height >= 0) + *height = self->preferred_height; +} + +static grub_err_t +list_set_property (void *vself, const char *name, const char *value) +{ + list_impl_t self = vself; + if (grub_strcmp (name, "item_font") == 0) + { + self->item_font = grub_font_get (value); + } + else if (grub_strcmp (name, "selected_item_font") == 0) + { + if (! value || grub_strcmp (value, "inherit") == 0) + self->selected_item_font = 0; + else + self->selected_item_font = grub_font_get (value); + } + else if (grub_strcmp (name, "item_color") == 0) + { + grub_gui_parse_color (value, &self->item_color); + } + else if (grub_strcmp (name, "selected_item_color") == 0) + { + if (! value || grub_strcmp (value, "inherit") == 0) + { + self->selected_item_color_set = 0; + } + else + { + if (grub_gui_parse_color (value, &self->selected_item_color) + == GRUB_ERR_NONE) + self->selected_item_color_set = 1; + } + } + else if (grub_strcmp (name, "icon_width") == 0) + { + self->icon_width = grub_strtol (value, 0, 10); + grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager, + self->icon_width, + self->icon_height); + } + else if (grub_strcmp (name, "icon_height") == 0) + { + self->icon_height = grub_strtol (value, 0, 10); + grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager, + self->icon_width, + self->icon_height); + } + else if (grub_strcmp (name, "item_height") == 0) + { + self->item_height = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "item_padding") == 0) + { + self->item_padding = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "item_icon_space") == 0) + { + self->item_icon_space = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "item_spacing") == 0) + { + self->item_spacing = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "visible") == 0) + { + self->visible = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "menu_pixmap_style") == 0) + { + self->need_to_recreate_boxes = 1; + grub_free (self->menu_box_pattern); + self->menu_box_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "selected_item_pixmap_style") == 0) + { + self->need_to_recreate_boxes = 1; + grub_free (self->selected_item_box_pattern); + self->selected_item_box_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "scrollbar_frame") == 0) + { + self->need_to_recreate_scrollbar = 1; + grub_free (self->scrollbar_frame_pattern); + self->scrollbar_frame_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "scrollbar_thumb") == 0) + { + self->need_to_recreate_scrollbar = 1; + grub_free (self->scrollbar_thumb_pattern); + self->scrollbar_thumb_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "scrollbar_width") == 0) + { + self->scrollbar_width = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "scrollbar") == 0) + { + self->draw_scrollbar = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "min_items_shown") == 0) + { + self->min_items_shown = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "max_items_shown") == 0) + { + self->max_items_shown = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "theme_dir") == 0) + { + self->need_to_recreate_boxes = 1; + grub_free (self->theme_dir); + self->theme_dir = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "preferred_size") == 0) + { + int w; + int h; + if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) + return grub_errno; + self->preferred_width = w; + self->preferred_height = h; + } + else if (grub_strcmp (name, "id") == 0) + { + grub_free (self->id); + if (value) + self->id = grub_strdup (value); + else + self->id = 0; + } + return grub_errno; +} + +/* Set necessary information that the gfxmenu view provides. */ +static void +list_set_view_info (void *vself, + const char *theme_path, + grub_gfxmenu_model_t menu) +{ + list_impl_t self = vself; + grub_gfxmenu_icon_manager_set_theme_path (self->icon_manager, theme_path); + self->menu = menu; +} + +static struct grub_gui_list_ops list_ops = +{ + .component_ops = + { + .destroy = list_destroy, + .get_id = list_get_id, + .is_instance = list_is_instance, + .paint = list_paint, + .set_parent = list_set_parent, + .get_parent = list_get_parent, + .set_bounds = list_set_bounds, + .get_bounds = list_get_bounds, + .get_preferred_size = list_get_preferred_size, + .set_property = list_set_property + }, + .set_view_info = list_set_view_info +}; + +grub_gui_component_t +grub_gui_list_new (void) +{ + list_impl_t self; + grub_font_t default_font; + grub_gui_color_t default_fg_color; + grub_gui_color_t default_bg_color; + + self = grub_malloc (sizeof (*self)); + if (! self) + return 0; + + self->list_ops = &list_ops; + self->parent = 0; + self->bounds.x = 0; + self->bounds.y = 0; + self->bounds.width = 0; + self->bounds.height = 0; + self->id = 0; + self->preferred_width = -1; + self->preferred_height = -1; + self->visible = 1; + + default_font = grub_font_get ("Helvetica 12"); + default_fg_color = grub_gui_color_rgb (0, 0, 0); + default_bg_color = grub_gui_color_rgb (255, 255, 255); + + self->icon_width = 32; + self->icon_height = 32; + self->item_height = 42; + self->item_padding = 14; + self->item_icon_space = 4; + self->item_spacing = 16; + self->item_font = default_font; + self->selected_item_font = 0; /* Default to using the item_font. */ + self->item_color = default_fg_color; + self->selected_item_color_set = 0; /* Default to using the item_color. */ + self->selected_item_color = default_fg_color; + + self->draw_scrollbar = 1; + self->need_to_recreate_scrollbar = 1; + self->scrollbar_frame = 0; + self->scrollbar_thumb = 0; + self->scrollbar_frame_pattern = 0; + self->scrollbar_thumb_pattern = 0; + self->scrollbar_width = 16; + + self->min_items_shown = -1; + self->max_items_shown = -1; + self->first_shown_index = 0; + + self->need_to_recreate_boxes = 0; + self->theme_dir = 0; + self->menu_box_pattern = 0; + self->selected_item_box_pattern = 0; + self->menu_box = grub_gfxmenu_create_box (0, 0); + self->selected_item_box = grub_gfxmenu_create_box (0, 0); + + self->icon_manager = grub_gfxmenu_icon_manager_new (); + if (! self->icon_manager) + { + self->list_ops->component_ops.destroy (self); + return 0; + } + grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager, + self->icon_width, + self->icon_height); + return (grub_gui_component_t) self; +} diff --git a/gfxmenu/gui_progress_bar.c b/gfxmenu/gui_progress_bar.c new file mode 100644 index 000000000..440d4b2fc --- /dev/null +++ b/gfxmenu/gui_progress_bar.c @@ -0,0 +1,378 @@ +/* gui_progress_bar.c - GUI progress bar component. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +struct grub_gui_progress_bar +{ + struct grub_gui_component_ops *progress_bar; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int preferred_width; + int preferred_height; + int visible; + int start; + int end; + int value; + int show_text; + char *text; + grub_font_t font; + grub_gui_color_t text_color; + grub_gui_color_t border_color; + grub_gui_color_t bg_color; + grub_gui_color_t fg_color; + + char *theme_dir; + int need_to_recreate_pixmaps; + char *bar_pattern; + char *highlight_pattern; + grub_gfxmenu_box_t bar_box; + grub_gfxmenu_box_t highlight_box; +}; + +typedef struct grub_gui_progress_bar *grub_gui_progress_bar_t; + +static void +progress_bar_destroy (void *vself) +{ + grub_gui_progress_bar_t self = vself; + grub_free (self); +} + +static const char * +progress_bar_get_id (void *vself) +{ + grub_gui_progress_bar_t self = vself; + return self->id; +} + +static int +progress_bar_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return grub_strcmp (type, "component") == 0; +} + +static int +check_pixmaps (grub_gui_progress_bar_t self) +{ + if (self->need_to_recreate_pixmaps) + { + grub_gui_recreate_box (&self->bar_box, + self->bar_pattern, + self->theme_dir); + + grub_gui_recreate_box (&self->highlight_box, + self->highlight_pattern, + self->theme_dir); + + self->need_to_recreate_pixmaps = 0; + } + + return (self->bar_box != 0 && self->highlight_box != 0); +} + +static void +draw_filled_rect_bar (grub_gui_progress_bar_t self) +{ + /* Set the progress bar's frame. */ + grub_video_rect_t f; + f.x = 1; + f.y = 1; + f.width = self->bounds.width - 2; + f.height = self->bounds.height - 2; + + /* Border. */ + grub_video_fill_rect (grub_gui_map_color (self->border_color), + f.x - 1, f.y - 1, + f.width + 2, f.height + 2); + + /* Bar background. */ + int barwidth = (f.width + * (self->value - self->start) + / (self->end - self->start)); + grub_video_fill_rect (grub_gui_map_color (self->bg_color), + f.x + barwidth, f.y, + f.width - barwidth, f.height); + + /* Bar foreground. */ + grub_video_fill_rect (grub_gui_map_color (self->fg_color), + f.x, f.y, + barwidth, f.height); +} + +static void +draw_pixmap_bar (grub_gui_progress_bar_t self) +{ + grub_gfxmenu_box_t bar = self->bar_box; + grub_gfxmenu_box_t hl = self->highlight_box; + int w = self->bounds.width; + int h = self->bounds.height; + int bar_l_pad = bar->get_left_pad (bar); + int bar_r_pad = bar->get_right_pad (bar); + int bar_t_pad = bar->get_top_pad (bar); + int bar_b_pad = bar->get_bottom_pad (bar); + int bar_h_pad = bar_l_pad + bar_r_pad; + int bar_v_pad = bar_t_pad + bar_b_pad; + int tracklen = w - bar_h_pad; + int trackheight = h - bar_v_pad; + bar->set_content_size (bar, tracklen, trackheight); + + int barwidth = (tracklen + * (self->value - self->start) + / (self->end - self->start)); + hl->set_content_size (hl, barwidth, h - bar_v_pad); + + bar->draw (bar, 0, 0); + hl->draw (hl, bar_l_pad, bar_t_pad); +} + +static void +draw_text (grub_gui_progress_bar_t self) +{ + const char *text = self->text; + if (text && self->show_text) + { + grub_font_t font = self->font; + grub_video_color_t text_color = grub_gui_map_color (self->text_color); + int width = self->bounds.width; + int height = self->bounds.height; + + /* Center the text. */ + int text_width = grub_font_get_string_width (font, text); + int x = (width - text_width) / 2; + int y = ((height - grub_font_get_descent (font)) / 2 + + grub_font_get_ascent (font) / 2); + grub_font_draw_string (text, font, text_color, x, y); + } +} + +static void +progress_bar_paint (void *vself) +{ + grub_gui_progress_bar_t self = vself; + if (! self->visible) + return; + + grub_video_rect_t vpsave; + grub_gui_set_viewport (&self->bounds, &vpsave); + + if (check_pixmaps (self)) + draw_pixmap_bar (self); + else + draw_filled_rect_bar (self); + + draw_text (self); + + grub_gui_restore_viewport (&vpsave); +} + +static void +progress_bar_set_parent (void *vself, grub_gui_container_t parent) +{ + grub_gui_progress_bar_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +progress_bar_get_parent (void *vself) +{ + grub_gui_progress_bar_t self = vself; + return self->parent; +} + +static void +progress_bar_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + grub_gui_progress_bar_t self = vself; + self->bounds = *bounds; +} + +static void +progress_bar_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + grub_gui_progress_bar_t self = vself; + *bounds = self->bounds; +} + +static void +progress_bar_get_preferred_size (void *vself, int *width, int *height) +{ + grub_gui_progress_bar_t self = vself; + + *width = 200; + *height = 28; + + /* Allow preferred dimensions to override the progress_bar dimensions. */ + if (self->preferred_width >= 0) + *width = self->preferred_width; + if (self->preferred_height >= 0) + *height = self->preferred_height; +} + +static grub_err_t +progress_bar_set_property (void *vself, const char *name, const char *value) +{ + grub_gui_progress_bar_t self = vself; + if (grub_strcmp (name, "value") == 0) + { + self->value = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "start") == 0) + { + self->start = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "end") == 0) + { + self->end = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "text") == 0) + { + grub_free (self->text); + if (! value) + value = ""; + self->text = grub_strdup (value); + } + else if (grub_strcmp (name, "font") == 0) + { + self->font = grub_font_get (value); + } + else if (grub_strcmp (name, "text_color") == 0) + { + grub_gui_parse_color (value, &self->text_color); + } + else if (grub_strcmp (name, "border_color") == 0) + { + grub_gui_parse_color (value, &self->border_color); + } + else if (grub_strcmp (name, "bg_color") == 0) + { + grub_gui_parse_color (value, &self->bg_color); + } + else if (grub_strcmp (name, "fg_color") == 0) + { + grub_gui_parse_color (value, &self->fg_color); + } + else if (grub_strcmp (name, "bar_style") == 0) + { + self->need_to_recreate_pixmaps = 1; + grub_free (self->bar_pattern); + self->bar_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "highlight_style") == 0) + { + self->need_to_recreate_pixmaps = 1; + grub_free (self->highlight_pattern); + self->highlight_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "theme_dir") == 0) + { + self->need_to_recreate_pixmaps = 1; + grub_free (self->theme_dir); + self->theme_dir = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "preferred_size") == 0) + { + int w; + int h; + if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) + return grub_errno; + self->preferred_width = w; + self->preferred_height = h; + } + else if (grub_strcmp (name, "visible") == 0) + { + self->visible = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "show_text") == 0) + { + self->show_text = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "id") == 0) + { + grub_free (self->id); + if (value) + self->id = grub_strdup (value); + else + self->id = 0; + } + return grub_errno; +} + +static struct grub_gui_component_ops progress_bar_ops = +{ + .destroy = progress_bar_destroy, + .get_id = progress_bar_get_id, + .is_instance = progress_bar_is_instance, + .paint = progress_bar_paint, + .set_parent = progress_bar_set_parent, + .get_parent = progress_bar_get_parent, + .set_bounds = progress_bar_set_bounds, + .get_bounds = progress_bar_get_bounds, + .get_preferred_size = progress_bar_get_preferred_size, + .set_property = progress_bar_set_property +}; + +grub_gui_component_t +grub_gui_progress_bar_new (void) +{ + grub_gui_progress_bar_t self; + self = grub_malloc (sizeof (*self)); + if (! self) + return 0; + self->progress_bar = &progress_bar_ops; + self->parent = 0; + self->bounds.x = 0; + self->bounds.y = 0; + self->bounds.width = 0; + self->bounds.height = 0; + self->id = 0; + self->preferred_width = -1; + self->preferred_height = -1; + self->visible = 1; + self->start = 0; + self->end = 0; + self->value = 0; + self->show_text = 1; + self->text = grub_strdup (""); + self->font = grub_font_get ("Helvetica 10"); + grub_gui_color_t black = { .red = 0, .green = 0, .blue = 0, .alpha = 255 }; + grub_gui_color_t gray = { .red = 128, .green = 128, .blue = 128, .alpha = 255 }; + grub_gui_color_t lightgray = { .red = 200, .green = 200, .blue = 200, .alpha = 255 }; + self->text_color = black; + self->border_color = black; + self->bg_color = gray; + self->fg_color = lightgray; + + self->theme_dir = 0; + self->need_to_recreate_pixmaps = 0; + self->bar_pattern = 0; + self->highlight_pattern = 0; + self->bar_box = 0; + self->highlight_box = 0; + + return (grub_gui_component_t) self; +} diff --git a/gfxmenu/gui_string_util.c b/gfxmenu/gui_string_util.c new file mode 100644 index 000000000..41170d724 --- /dev/null +++ b/gfxmenu/gui_string_util.c @@ -0,0 +1,358 @@ +/* gui_string_util.c - String utilities used by the GUI system. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include + +/* Create a new NUL-terminated string on the heap as a substring of BUF. + The range of buf included is the half-open interval [START,END). + The index START is inclusive, END is exclusive. */ +char * +grub_new_substring (const char *buf, + grub_size_t start, grub_size_t end) +{ + if (end < start) + return 0; + grub_size_t len = end - start; + char *s = grub_malloc (len + 1); + if (! s) + return 0; + grub_memcpy (s, buf + start, len); + s[len] = '\0'; + return s; +} + +/* Eliminate "." and ".." path elements from PATH. A new heap-allocated + string is returned. */ +static char * +canonicalize_path (const char *path) +{ + int i; + const char *p; + char *newpath = 0; + + /* Count the path components in path. */ + int components = 1; + for (p = path; *p; p++) + if (*p == '/') + components++; + + char **path_array = grub_malloc (components * sizeof (*path_array)); + if (! path_array) + return 0; + + /* Initialize array elements to NULL pointers; in case once of the + allocations fails, the cleanup code can just call grub_free() for all + pointers in the array. */ + for (i = 0; i < components; i++) + path_array[i] = 0; + + /* Parse the path into path_array. */ + p = path; + for (i = 0; i < components && p; i++) + { + /* Find the end of the path element. */ + const char *end = grub_strchr (p, '/'); + if (!end) + end = p + grub_strlen (p); + + /* Copy the element. */ + path_array[i] = grub_new_substring (p, 0, end - p); + if (! path_array[i]) + goto cleanup; + + /* Advance p to point to the start of the next element, or NULL. */ + if (*end) + p = end + 1; + else + p = 0; + } + + /* Eliminate '.' and '..' elements from the path array. */ + int newpath_length = 0; + for (i = components - 1; i >= 0; --i) + { + if (! grub_strcmp (path_array[i], ".")) + { + grub_free (path_array[i]); + path_array[i] = 0; + } + else if (! grub_strcmp (path_array[i], "..") + && i > 0) + { + /* Delete the '..' and the prior path element. */ + grub_free (path_array[i]); + path_array[i] = 0; + --i; + grub_free (path_array[i]); + path_array[i] = 0; + } + else + { + newpath_length += grub_strlen (path_array[i]) + 1; + } + } + + /* Construct a new path string. */ + newpath = grub_malloc (newpath_length + 1); + if (! newpath) + goto cleanup; + + newpath[0] = '\0'; + char *newpath_end = newpath; + int first = 1; + for (i = 0; i < components; i++) + { + char *element = path_array[i]; + if (element) + { + /* For all components but the first, prefix with a slash. */ + if (! first) + newpath_end = grub_stpcpy (newpath_end, "/"); + newpath_end = grub_stpcpy (newpath_end, element); + first = 0; + } + } + +cleanup: + for (i = 0; i < components; i++) + grub_free (path_array[i]); + grub_free (path_array); + + return newpath; +} + +/* Return a new heap-allocated string representing to absolute path + to the file referred to by PATH. If PATH is an absolute path, then + the returned path is a copy of PATH. If PATH is a relative path, then + BASE is with PATH used to construct the absolute path. */ +char * +grub_resolve_relative_path (const char *base, const char *path) +{ + char *abspath; + char *canonpath; + char *p; + + /* If PATH is an absolute path, then just use it as is. */ + if (path[0] == '/' || path[0] == '(') + return canonicalize_path (path); + + abspath = grub_malloc (grub_strlen (base) + grub_strlen (path) + 1); + if (! abspath) + return 0; + + /* Concatenate BASE and PATH. + Note that BASE is expected to have a trailing slash. */ + p = grub_stpcpy (abspath, base); + grub_stpcpy (p, path); + + canonpath = canonicalize_path (abspath); + if (! canonpath) + return abspath; + + grub_free (abspath); + return canonpath; +} + +/* Get the path of the directory where the file at FILE_PATH is located. + FILE_PATH should refer to a file, not a directory. The returned path + includes a trailing slash. + This does not handle GRUB "(hd0,0)" paths properly yet since it only + looks at slashes. */ +char * +grub_get_dirname (const char *file_path) +{ + int i; + int last_slash; + + last_slash = -1; + for (i = grub_strlen (file_path) - 1; i >= 0; --i) + { + if (file_path[i] == '/') + { + last_slash = i; + break; + } + } + if (last_slash == -1) + return grub_strdup ("/"); + + return grub_new_substring (file_path, 0, last_slash + 1); +} + +static __inline int +isxdigit (char c) +{ + return ((c >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F')); +} + +static int +parse_hex_color_component (const char *s, unsigned start, unsigned end) +{ + unsigned len; + char buf[3]; + + len = end - start; + /* Check the limits so we don't overrun the buffer. */ + if (len < 1 || len > 2) + return 0; + + if (len == 1) + { + buf[0] = s[start]; /* Get the first and only hex digit. */ + buf[1] = buf[0]; /* Duplicate the hex digit. */ + } + else if (len == 2) + { + buf[0] = s[start]; + buf[1] = s[start + 1]; + } + + buf[2] = '\0'; + + return grub_strtoul (buf, 0, 16); +} + +/* Parse a color string of the form "r, g, b", "#RGB", "#RGBA", + "#RRGGBB", or "#RRGGBBAA". */ +grub_err_t +grub_gui_parse_color (const char *s, grub_gui_color_t *color) +{ + grub_gui_color_t c; + + /* Skip whitespace. */ + while (*s && grub_isspace (*s)) + s++; + + if (*s == '#') + { + /* HTML-style. Number if hex digits: + [6] #RRGGBB [3] #RGB + [8] #RRGGBBAA [4] #RGBA */ + + s++; /* Skip the '#'. */ + /* Count the hexits to determine the format. */ + int hexits = 0; + const char *end = s; + while (isxdigit (*end)) + { + end++; + hexits++; + } + + /* Parse the color components based on the format. */ + if (hexits == 3 || hexits == 4) + { + c.red = parse_hex_color_component (s, 0, 1); + c.green = parse_hex_color_component (s, 1, 2); + c.blue = parse_hex_color_component (s, 2, 3); + if (hexits == 4) + c.alpha = parse_hex_color_component (s, 3, 4); + else + c.alpha = 255; + } + else if (hexits == 6 || hexits == 8) + { + c.red = parse_hex_color_component (s, 0, 2); + c.green = parse_hex_color_component (s, 2, 4); + c.blue = parse_hex_color_component (s, 4, 6); + if (hexits == 8) + c.alpha = parse_hex_color_component (s, 6, 8); + else + c.alpha = 255; + } + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "invalid HTML-type color string `%s'", s); + } + else if (grub_isdigit (*s)) + { + /* Comma separated decimal values. */ + c.red = grub_strtoul (s, 0, 0); + if ((s = grub_strchr (s, ',')) == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "missing 1st comma separator in color `%s'", s); + s++; + c.green = grub_strtoul (s, 0, 0); + if ((s = grub_strchr (s, ',')) == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "missing 2nd comma separator in color `%s'", s); + s++; + c.blue = grub_strtoul (s, 0, 0); + if ((s = grub_strchr (s, ',')) == 0) + c.alpha = 255; + else + { + s++; + c.alpha = grub_strtoul (s, 0, 0); + } + } + else + { + if (! grub_gui_get_named_color (s, &c)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "invalid named color `%s'", s); + } + + if (grub_errno == GRUB_ERR_NONE) + *color = c; + return grub_errno; +} + +/* Parse a value in the form "(x, y)", storing the first element (x) into + *PX and the second element (y) into *PY. + Returns GRUB_ERR_NONE if successfully parsed. */ +grub_err_t +grub_gui_parse_2_tuple (const char *s, int *px, int *py) +{ + int x; + int y; + + while (*s && grub_isspace (*s)) + s++; + if (*s != '(') + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "missing `(' in 2-tuple `%s'", s); + + /* Skip the opening parentheses. */ + s++; + if (*s == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "unexpected end of 2-tuple after `(' in `%s'", s); + + /* Parse the first element. */ + x = grub_strtol (s, 0, 10); + if ((s = grub_strchr (s, ',')) == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "missing comma in 2-tuple `%s'", s); + + /* Skip the element separator (the comma). */ + s++; + /* Parse the second element. */ + y = grub_strtol (s, 0, 10); + + *px = x; + *py = y; + + return grub_errno; +} diff --git a/gfxmenu/gui_util.c b/gfxmenu/gui_util.c new file mode 100644 index 000000000..eba7bb39e --- /dev/null +++ b/gfxmenu/gui_util.c @@ -0,0 +1,101 @@ +/* gui_util.c - GUI utility functions. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include + + +struct find_by_id_state +{ + const char *match_id; + grub_gui_component_callback match_callback; + void *match_userdata; +}; + +static void +find_by_id_recursively (grub_gui_component_t component, void *userdata) +{ + struct find_by_id_state *state; + const char *id; + + state = (struct find_by_id_state *) userdata; + id = component->ops->get_id (component); + if (id && grub_strcmp (id, state->match_id) == 0) + state->match_callback (component, state->match_userdata); + + if (component->ops->is_instance (component, "container")) + { + grub_gui_container_t container; + container = (grub_gui_container_t) component; + container->ops->iterate_children (container, + find_by_id_recursively, + state); + } +} + +void +grub_gui_find_by_id (grub_gui_component_t root, + const char *id, + grub_gui_component_callback cb, + void *userdata) +{ + struct find_by_id_state state; + state.match_id = id; + state.match_callback = cb; + state.match_userdata = userdata; + find_by_id_recursively (root, &state); +} + + +struct iterate_recursively_state +{ + grub_gui_component_callback callback; + void *userdata; +}; + +static +void iterate_recursively_cb (grub_gui_component_t component, void *userdata) +{ + struct iterate_recursively_state *state; + + state = (struct iterate_recursively_state *) userdata; + state->callback (component, state->userdata); + + if (component->ops->is_instance (component, "container")) + { + grub_gui_container_t container; + container = (grub_gui_container_t) component; + container->ops->iterate_children (container, + iterate_recursively_cb, + state); + } +} + +void +grub_gui_iterate_recursively (grub_gui_component_t root, + grub_gui_component_callback cb, + void *userdata) +{ + struct iterate_recursively_state state; + state.callback = cb; + state.userdata = userdata; + iterate_recursively_cb (root, &state); +} diff --git a/gfxmenu/icon_manager.c b/gfxmenu/icon_manager.c new file mode 100644 index 000000000..a362882e1 --- /dev/null +++ b/gfxmenu/icon_manager.c @@ -0,0 +1,258 @@ +/* icon_manager.c - gfxmenu icon manager. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Currently hard coded to '.png' extension. */ +static const char icon_extension[] = ".png"; + +typedef struct icon_entry +{ + char *class_name; + struct grub_video_bitmap *bitmap; + struct icon_entry *next; +} *icon_entry_t; + +struct grub_gfxmenu_icon_manager +{ + char *theme_path; + int icon_width; + int icon_height; + + /* Icon cache: linked list w/ dummy head node. */ + struct icon_entry cache; +}; + + +/* Create a new icon manager and return a point to it. */ +grub_gfxmenu_icon_manager_t +grub_gfxmenu_icon_manager_new (void) +{ + grub_gfxmenu_icon_manager_t mgr; + mgr = grub_malloc (sizeof (*mgr)); + if (! mgr) + return 0; + + mgr->theme_path = 0; + mgr->icon_width = 0; + mgr->icon_height = 0; + + /* Initialize the dummy head node. */ + mgr->cache.class_name = 0; + mgr->cache.bitmap = 0; + mgr->cache.next = 0; + + return mgr; +} + +/* Destroy the icon manager MGR, freeing all resources used by it. + +Note: Any bitmaps returned by grub_gfxmenu_icon_manager_get_icon() +are destroyed and must not be used by the caller after this function +is called. */ +void +grub_gfxmenu_icon_manager_destroy (grub_gfxmenu_icon_manager_t mgr) +{ + grub_gfxmenu_icon_manager_clear_cache (mgr); + grub_free (mgr->theme_path); + grub_free (mgr); +} + +/* Clear the icon cache. */ +void +grub_gfxmenu_icon_manager_clear_cache (grub_gfxmenu_icon_manager_t mgr) +{ + icon_entry_t cur; + icon_entry_t next; + for (cur = mgr->cache.next; cur; cur = next) + { + next = cur->next; + grub_free (cur->class_name); + grub_video_bitmap_destroy (cur->bitmap); + grub_free (cur); + } + mgr->cache.next = 0; +} + +/* Set the theme path. If the theme path is changed, the icon cache + is cleared. */ +void +grub_gfxmenu_icon_manager_set_theme_path (grub_gfxmenu_icon_manager_t mgr, + const char *path) +{ + /* Clear the cache if the theme path has changed. */ + if (((mgr->theme_path == 0) != (path == 0)) + || (grub_strcmp (mgr->theme_path, path) != 0)) + grub_gfxmenu_icon_manager_clear_cache (mgr); + + grub_free (mgr->theme_path); + mgr->theme_path = path ? grub_strdup (path) : 0; +} + +/* Set the icon size. When icons are requested from the icon manager, + they are scaled to this size before being returned. If the size is + changed, the icon cache is cleared. */ +void +grub_gfxmenu_icon_manager_set_icon_size (grub_gfxmenu_icon_manager_t mgr, + int width, int height) +{ + /* If the width or height is changed, we must clear the cache, since the + scaled bitmaps are stored in the cache. */ + if (width != mgr->icon_width || height != mgr->icon_height) + grub_gfxmenu_icon_manager_clear_cache (mgr); + + mgr->icon_width = width; + mgr->icon_height = height; +} + +/* Try to load an icon for the specified CLASS_NAME in the directory DIR. + Returns 0 if the icon could not be loaded, or returns a pointer to a new + bitmap if it was successful. */ +static struct grub_video_bitmap * +try_loading_icon (grub_gfxmenu_icon_manager_t mgr, + const char *dir, const char *class_name) +{ + char *path = grub_malloc (grub_strlen (dir) + + grub_strlen (class_name) + + grub_strlen (icon_extension) + + 1); + if (! path) + return 0; + + grub_strcpy (path, dir); + grub_strcat (path, class_name); + grub_strcat (path, icon_extension); + + struct grub_video_bitmap *raw_bitmap; + grub_video_bitmap_load (&raw_bitmap, path); + grub_free (path); + grub_errno = GRUB_ERR_NONE; /* Critical to clear the error!! */ + if (! raw_bitmap) + return 0; + + struct grub_video_bitmap *scaled_bitmap; + grub_video_bitmap_create_scaled (&scaled_bitmap, + mgr->icon_width, mgr->icon_height, + raw_bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + grub_video_bitmap_destroy (raw_bitmap); + if (! scaled_bitmap) + { + grub_error_push (); + grub_error (grub_errno, "failed to scale icon"); + return 0; + } + + return scaled_bitmap; +} + +/* Get the icon for the specified class CLASS_NAME. If an icon for + CLASS_NAME already exists in the cache, then a reference to the cached + bitmap is returned. If it is not cached, then it is loaded and cached. + If no icon could be could for CLASS_NAME, then 0 is returned. */ +static struct grub_video_bitmap * +get_icon_by_class (grub_gfxmenu_icon_manager_t mgr, const char *class_name) +{ + /* First check the icon cache. */ + icon_entry_t entry; + for (entry = mgr->cache.next; entry; entry = entry->next) + { + if (grub_strcmp (entry->class_name, class_name) == 0) + return entry->bitmap; + } + + if (! mgr->theme_path) + return 0; + + /* Otherwise, we search for an icon to load. */ + char *theme_dir = grub_get_dirname (mgr->theme_path); + char *icons_dir; + struct grub_video_bitmap *icon; + icon = 0; + /* First try the theme's own icons, from "grub/themes/NAME/icons/" */ + icons_dir = grub_resolve_relative_path (theme_dir, "icons/"); + if (icons_dir) + { + icon = try_loading_icon (mgr, icons_dir, class_name); + grub_free (icons_dir); + } + if (! icon) + { + /* If the theme doesn't have an appropriate icon, check in + "grub/themes/icons". */ + /* TODO use GRUB prefix "/icons" */ + icons_dir = grub_resolve_relative_path (theme_dir, "../icons/"); + if (icons_dir) + { + icon = try_loading_icon (mgr, icons_dir, class_name); + grub_free (icons_dir); + } + } + grub_free (theme_dir); + + /* No icon was found. */ + /* This should probably be noted in the cache, so that a search is not + performed each time an icon for CLASS_NAME is requested. */ + if (! icon) + return 0; + + /* Insert a new cache entry for this icon. */ + entry = grub_malloc (sizeof (*entry)); + if (! entry) + { + grub_video_bitmap_destroy (icon); + return 0; + } + entry->class_name = grub_strdup (class_name); + entry->bitmap = icon; + entry->next = mgr->cache.next; + mgr->cache.next = entry; /* Link it into the cache. */ + return entry->bitmap; +} + +/* Get the best available icon for ENTRY. Beginning with the first class + listed in the menu entry and proceeding forward, an icon for each class + is searched for. The first icon found is returned. The returned icon + is scaled to the size specified by + grub_gfxmenu_icon_manager_set_icon_size(). + + Note: Bitmaps returned by this function are destroyed when the + icon manager is destroyed. + */ +struct grub_video_bitmap * +grub_gfxmenu_icon_manager_get_icon (grub_gfxmenu_icon_manager_t mgr, + grub_menu_entry_t entry) +{ + struct grub_menu_entry_class *c; + struct grub_video_bitmap *icon; + + /* Try each class in succession. */ + icon = 0; + for (c = entry->classes->next; c && ! icon; c = c->next) + icon = get_icon_by_class (mgr, c->name); + return icon; +} diff --git a/gfxmenu/model.c b/gfxmenu/model.c new file mode 100644 index 000000000..26490ea1f --- /dev/null +++ b/gfxmenu/model.c @@ -0,0 +1,191 @@ +/* model.c - Graphical menu interface MVC model. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Model type definition. */ +struct grub_gfxmenu_model +{ + grub_menu_t menu; + int num_entries; + grub_menu_entry_t *entries; + int selected_entry_index; + int timeout_set; + grub_uint64_t timeout_start; + grub_uint64_t timeout_at; +}; + + +grub_gfxmenu_model_t +grub_gfxmenu_model_new (grub_menu_t menu) +{ + grub_gfxmenu_model_t model; + + model = grub_malloc (sizeof (*model)); + if (! model) + return 0; + + model->menu = menu; + model->num_entries = menu->size; + model->entries = 0; + model->selected_entry_index = 0; + model->timeout_set = 0; + model->timeout_at = 0; + if (model->num_entries > 0) + { + model->entries = grub_malloc (model->num_entries + * sizeof (*model->entries)); + if (! model->entries) + goto fail_and_free; + + int i; + grub_menu_entry_t cur; + for (i = 0, cur = menu->entry_list; + i < model->num_entries; + i++, cur = cur->next) + { + model->entries[i] = cur; + } + } + + return model; + +fail_and_free: + grub_free (model->entries); + grub_free (model); + return 0; +} + +void +grub_gfxmenu_model_destroy (grub_gfxmenu_model_t model) +{ + if (! model) + return; + + grub_free (model->entries); + model->entries = 0; + + grub_free (model); +} + +grub_menu_t +grub_gfxmenu_model_get_menu (grub_gfxmenu_model_t model) +{ + return model->menu; +} + +void +grub_gfxmenu_model_set_timeout (grub_gfxmenu_model_t model) +{ + int timeout_sec = grub_menu_get_timeout (); + if (timeout_sec >= 0) + { + model->timeout_start = grub_get_time_ms (); + model->timeout_at = model->timeout_start + timeout_sec * 1000; + model->timeout_set = 1; + } + else + { + model->timeout_set = 0; + } +} + +void +grub_gfxmenu_model_clear_timeout (grub_gfxmenu_model_t model) +{ + model->timeout_set = 0; + grub_menu_set_timeout (-1); +} + +int +grub_gfxmenu_model_get_timeout_ms (grub_gfxmenu_model_t model) +{ + if (!model->timeout_set) + return -1; + + return model->timeout_at - model->timeout_start; +} + +int +grub_gfxmenu_model_get_timeout_remaining_ms (grub_gfxmenu_model_t model) +{ + if (!model->timeout_set) + return -1; + + return model->timeout_at - grub_get_time_ms (); +} + +int +grub_gfxmenu_model_timeout_expired (grub_gfxmenu_model_t model) +{ + if (model->timeout_set + && grub_get_time_ms () >= model->timeout_at) + return 1; + + return 0; +} + +int +grub_gfxmenu_model_get_num_entries (grub_gfxmenu_model_t model) +{ + return model->num_entries; +} + +int +grub_gfxmenu_model_get_selected_index (grub_gfxmenu_model_t model) +{ + return model->selected_entry_index; +} + +void +grub_gfxmenu_model_set_selected_index (grub_gfxmenu_model_t model, int index) +{ + model->selected_entry_index = index; +} + +const char * +grub_gfxmenu_model_get_entry_title (grub_gfxmenu_model_t model, int index) +{ + if (index < 0 || index >= model->num_entries) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid menu index"); + return 0; + } + + return model->entries[index]->title; +} + +grub_menu_entry_t +grub_gfxmenu_model_get_entry (grub_gfxmenu_model_t model, int index) +{ + if (index < 0 || index >= model->num_entries) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid menu index"); + return 0; + } + + return model->entries[index]; +} diff --git a/gfxmenu/named_colors.c b/gfxmenu/named_colors.c new file mode 100644 index 000000000..eedbc47fb --- /dev/null +++ b/gfxmenu/named_colors.c @@ -0,0 +1,209 @@ +/* named_colors.c - Named color values. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include + +struct named_color +{ + const char *name; + grub_gui_color_t color; +}; + +/* + Named color list generated from the list of SVG color keywords from + , + processed through the following Perl command: + perl -ne 'chomp;split;print "{ \"$_[0]\", RGB_COLOR($_[2]) },\n"' + */ + +#define RGB_COLOR(r,g,b) {.red = r, .green = g, .blue = b, .alpha = 255} + +static struct named_color named_colors[] = +{ + { "aliceblue", RGB_COLOR(240,248,255) }, + { "antiquewhite", RGB_COLOR(250,235,215) }, + { "aqua", RGB_COLOR(0,255,255) }, + { "aquamarine", RGB_COLOR(127,255,212) }, + { "azure", RGB_COLOR(240,255,255) }, + { "beige", RGB_COLOR(245,245,220) }, + { "bisque", RGB_COLOR(255,228,196) }, + { "black", RGB_COLOR(0,0,0) }, + { "blanchedalmond", RGB_COLOR(255,235,205) }, + { "blue", RGB_COLOR(0,0,255) }, + { "blueviolet", RGB_COLOR(138,43,226) }, + { "brown", RGB_COLOR(165,42,42) }, + { "burlywood", RGB_COLOR(222,184,135) }, + { "cadetblue", RGB_COLOR(95,158,160) }, + { "chartreuse", RGB_COLOR(127,255,0) }, + { "chocolate", RGB_COLOR(210,105,30) }, + { "coral", RGB_COLOR(255,127,80) }, + { "cornflowerblue", RGB_COLOR(100,149,237) }, + { "cornsilk", RGB_COLOR(255,248,220) }, + { "crimson", RGB_COLOR(220,20,60) }, + { "cyan", RGB_COLOR(0,255,255) }, + { "darkblue", RGB_COLOR(0,0,139) }, + { "darkcyan", RGB_COLOR(0,139,139) }, + { "darkgoldenrod", RGB_COLOR(184,134,11) }, + { "darkgray", RGB_COLOR(169,169,169) }, + { "darkgreen", RGB_COLOR(0,100,0) }, + { "darkgrey", RGB_COLOR(169,169,169) }, + { "darkkhaki", RGB_COLOR(189,183,107) }, + { "darkmagenta", RGB_COLOR(139,0,139) }, + { "darkolivegreen", RGB_COLOR(85,107,47) }, + { "darkorange", RGB_COLOR(255,140,0) }, + { "darkorchid", RGB_COLOR(153,50,204) }, + { "darkred", RGB_COLOR(139,0,0) }, + { "darksalmon", RGB_COLOR(233,150,122) }, + { "darkseagreen", RGB_COLOR(143,188,143) }, + { "darkslateblue", RGB_COLOR(72,61,139) }, + { "darkslategray", RGB_COLOR(47,79,79) }, + { "darkslategrey", RGB_COLOR(47,79,79) }, + { "darkturquoise", RGB_COLOR(0,206,209) }, + { "darkviolet", RGB_COLOR(148,0,211) }, + { "deeppink", RGB_COLOR(255,20,147) }, + { "deepskyblue", RGB_COLOR(0,191,255) }, + { "dimgray", RGB_COLOR(105,105,105) }, + { "dimgrey", RGB_COLOR(105,105,105) }, + { "dodgerblue", RGB_COLOR(30,144,255) }, + { "firebrick", RGB_COLOR(178,34,34) }, + { "floralwhite", RGB_COLOR(255,250,240) }, + { "forestgreen", RGB_COLOR(34,139,34) }, + { "fuchsia", RGB_COLOR(255,0,255) }, + { "gainsboro", RGB_COLOR(220,220,220) }, + { "ghostwhite", RGB_COLOR(248,248,255) }, + { "gold", RGB_COLOR(255,215,0) }, + { "goldenrod", RGB_COLOR(218,165,32) }, + { "gray", RGB_COLOR(128,128,128) }, + { "green", RGB_COLOR(0,128,0) }, + { "greenyellow", RGB_COLOR(173,255,47) }, + { "grey", RGB_COLOR(128,128,128) }, + { "honeydew", RGB_COLOR(240,255,240) }, + { "hotpink", RGB_COLOR(255,105,180) }, + { "indianred", RGB_COLOR(205,92,92) }, + { "indigo", RGB_COLOR(75,0,130) }, + { "ivory", RGB_COLOR(255,255,240) }, + { "khaki", RGB_COLOR(240,230,140) }, + { "lavender", RGB_COLOR(230,230,250) }, + { "lavenderblush", RGB_COLOR(255,240,245) }, + { "lawngreen", RGB_COLOR(124,252,0) }, + { "lemonchiffon", RGB_COLOR(255,250,205) }, + { "lightblue", RGB_COLOR(173,216,230) }, + { "lightcoral", RGB_COLOR(240,128,128) }, + { "lightcyan", RGB_COLOR(224,255,255) }, + { "lightgoldenrodyellow", RGB_COLOR(250,250,210) }, + { "lightgray", RGB_COLOR(211,211,211) }, + { "lightgreen", RGB_COLOR(144,238,144) }, + { "lightgrey", RGB_COLOR(211,211,211) }, + { "lightpink", RGB_COLOR(255,182,193) }, + { "lightsalmon", RGB_COLOR(255,160,122) }, + { "lightseagreen", RGB_COLOR(32,178,170) }, + { "lightskyblue", RGB_COLOR(135,206,250) }, + { "lightslategray", RGB_COLOR(119,136,153) }, + { "lightslategrey", RGB_COLOR(119,136,153) }, + { "lightsteelblue", RGB_COLOR(176,196,222) }, + { "lightyellow", RGB_COLOR(255,255,224) }, + { "lime", RGB_COLOR(0,255,0) }, + { "limegreen", RGB_COLOR(50,205,50) }, + { "linen", RGB_COLOR(250,240,230) }, + { "magenta", RGB_COLOR(255,0,255) }, + { "maroon", RGB_COLOR(128,0,0) }, + { "mediumaquamarine", RGB_COLOR(102,205,170) }, + { "mediumblue", RGB_COLOR(0,0,205) }, + { "mediumorchid", RGB_COLOR(186,85,211) }, + { "mediumpurple", RGB_COLOR(147,112,219) }, + { "mediumseagreen", RGB_COLOR(60,179,113) }, + { "mediumslateblue", RGB_COLOR(123,104,238) }, + { "mediumspringgreen", RGB_COLOR(0,250,154) }, + { "mediumturquoise", RGB_COLOR(72,209,204) }, + { "mediumvioletred", RGB_COLOR(199,21,133) }, + { "midnightblue", RGB_COLOR(25,25,112) }, + { "mintcream", RGB_COLOR(245,255,250) }, + { "mistyrose", RGB_COLOR(255,228,225) }, + { "moccasin", RGB_COLOR(255,228,181) }, + { "navajowhite", RGB_COLOR(255,222,173) }, + { "navy", RGB_COLOR(0,0,128) }, + { "oldlace", RGB_COLOR(253,245,230) }, + { "olive", RGB_COLOR(128,128,0) }, + { "olivedrab", RGB_COLOR(107,142,35) }, + { "orange", RGB_COLOR(255,165,0) }, + { "orangered", RGB_COLOR(255,69,0) }, + { "orchid", RGB_COLOR(218,112,214) }, + { "palegoldenrod", RGB_COLOR(238,232,170) }, + { "palegreen", RGB_COLOR(152,251,152) }, + { "paleturquoise", RGB_COLOR(175,238,238) }, + { "palevioletred", RGB_COLOR(219,112,147) }, + { "papayawhip", RGB_COLOR(255,239,213) }, + { "peachpuff", RGB_COLOR(255,218,185) }, + { "peru", RGB_COLOR(205,133,63) }, + { "pink", RGB_COLOR(255,192,203) }, + { "plum", RGB_COLOR(221,160,221) }, + { "powderblue", RGB_COLOR(176,224,230) }, + { "purple", RGB_COLOR(128,0,128) }, + { "red", RGB_COLOR(255,0,0) }, + { "rosybrown", RGB_COLOR(188,143,143) }, + { "royalblue", RGB_COLOR(65,105,225) }, + { "saddlebrown", RGB_COLOR(139,69,19) }, + { "salmon", RGB_COLOR(250,128,114) }, + { "sandybrown", RGB_COLOR(244,164,96) }, + { "seagreen", RGB_COLOR(46,139,87) }, + { "seashell", RGB_COLOR(255,245,238) }, + { "sienna", RGB_COLOR(160,82,45) }, + { "silver", RGB_COLOR(192,192,192) }, + { "skyblue", RGB_COLOR(135,206,235) }, + { "slateblue", RGB_COLOR(106,90,205) }, + { "slategray", RGB_COLOR(112,128,144) }, + { "slategrey", RGB_COLOR(112,128,144) }, + { "snow", RGB_COLOR(255,250,250) }, + { "springgreen", RGB_COLOR(0,255,127) }, + { "steelblue", RGB_COLOR(70,130,180) }, + { "tan", RGB_COLOR(210,180,140) }, + { "teal", RGB_COLOR(0,128,128) }, + { "thistle", RGB_COLOR(216,191,216) }, + { "tomato", RGB_COLOR(255,99,71) }, + { "turquoise", RGB_COLOR(64,224,208) }, + { "violet", RGB_COLOR(238,130,238) }, + { "wheat", RGB_COLOR(245,222,179) }, + { "white", RGB_COLOR(255,255,255) }, + { "whitesmoke", RGB_COLOR(245,245,245) }, + { "yellow", RGB_COLOR(255,255,0) }, + { "yellowgreen", RGB_COLOR(154,205,50) }, + { 0, { 0, 0, 0, 0 } } /* Terminator. */ +}; + +/* Get the color named NAME. If the color was found, returns 1 and + stores the color into *COLOR. If the color was not found, returns 0 and + does not modify *COLOR. */ +int +grub_gui_get_named_color (const char *name, + grub_gui_color_t *color) +{ + int i; + for (i = 0; named_colors[i].name; i++) + { + if (grub_strcmp (named_colors[i].name, name) == 0) + { + *color = named_colors[i].color; + return 1; + } + } + return 0; +} diff --git a/gfxmenu/theme_loader.c b/gfxmenu/theme_loader.c new file mode 100644 index 000000000..3512c7bf1 --- /dev/null +++ b/gfxmenu/theme_loader.c @@ -0,0 +1,720 @@ +/* theme_loader.c - Theme file loader for gfxmenu. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Construct a new box widget using ABSPATTERN to find the pixmap files for + it, storing the new box instance at *BOXPTR. + PATTERN should be of the form: "(hd0,0)/somewhere/style*.png". + The '*' then gets substituted with the various pixmap names that the + box uses. */ +static grub_err_t +recreate_box_absolute (grub_gfxmenu_box_t *boxptr, const char *abspattern) +{ + char *prefix; + char *suffix; + char *star; + grub_gfxmenu_box_t box; + + star = grub_strchr (abspattern, '*'); + if (! star) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "missing `*' in box pixmap pattern `%s'", abspattern); + + /* Prefix: Get the part before the '*'. */ + prefix = grub_malloc (star - abspattern + 1); + if (! prefix) + return grub_errno; + + grub_memcpy (prefix, abspattern, star - abspattern); + prefix[star - abspattern] = '\0'; + + /* Suffix: Everything after the '*' is the suffix. */ + suffix = star + 1; + + box = grub_gfxmenu_create_box (prefix, suffix); + grub_free (prefix); + if (! box) + return grub_errno; + + if (*boxptr) + (*boxptr)->destroy (*boxptr); + *boxptr = box; + return grub_errno; +} + + +/* Construct a new box widget using PATTERN to find the pixmap files for it, + storing the new widget at *BOXPTR. PATTERN should be of the form: + "somewhere/style*.png". The '*' then gets substituted with the various + pixmap names that the widget uses. + + Important! The value of *BOXPTR must be initialized! It must either + (1) Be 0 (a NULL pointer), or + (2) Be a pointer to a valid 'grub_gfxmenu_box_t' instance. + In this case, the previous instance is destroyed. */ +grub_err_t +grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr, + const char *pattern, const char *theme_dir) +{ + char *abspattern; + + /* Check arguments. */ + if (! pattern) + { + /* If no pixmap pattern is given, then just create an empty box. */ + if (*boxptr) + (*boxptr)->destroy (*boxptr); + *boxptr = grub_gfxmenu_create_box (0, 0); + return grub_errno; + } + + if (! theme_dir) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "styled box missing theme directory"); + + /* Resolve to an absolute path. */ + abspattern = grub_resolve_relative_path (theme_dir, pattern); + if (! abspattern) + return grub_errno; + + /* Create the box. */ + recreate_box_absolute (boxptr, abspattern); + grub_free (abspattern); + return grub_errno; +} + +/* Set the specified property NAME on the view to the given string VALUE. + The caller is responsible for the lifetimes of NAME and VALUE. */ +static grub_err_t +theme_set_string (grub_gfxmenu_view_t view, + const char *name, + const char *value, + const char *theme_dir, + const char *filename, + int line_num, + int col_num) +{ + if (! grub_strcmp ("title-font", name)) + view->title_font = grub_font_get (value); + else if (! grub_strcmp ("message-font", name)) + view->message_font = grub_font_get (value); + else if (! grub_strcmp ("terminal-font", name)) + { + grub_free (view->terminal_font_name); + view->terminal_font_name = grub_strdup (value); + if (! view->terminal_font_name) + return grub_errno; + } + else if (! grub_strcmp ("title-color", name)) + grub_gui_parse_color (value, &view->title_color); + else if (! grub_strcmp ("message-color", name)) + grub_gui_parse_color (value, &view->message_color); + else if (! grub_strcmp ("message-bg-color", name)) + grub_gui_parse_color (value, &view->message_bg_color); + else if (! grub_strcmp ("desktop-image", name)) + { + struct grub_video_bitmap *raw_bitmap; + struct grub_video_bitmap *scaled_bitmap; + char *path; + path = grub_resolve_relative_path (theme_dir, value); + if (! path) + return grub_errno; + if (grub_video_bitmap_load (&raw_bitmap, path) != GRUB_ERR_NONE) + { + grub_free (path); + return grub_errno; + } + grub_free(path); + grub_video_bitmap_create_scaled (&scaled_bitmap, + view->screen.width, + view->screen.height, + raw_bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + grub_video_bitmap_destroy (raw_bitmap); + if (! scaled_bitmap) + { + grub_error_push (); + return grub_error (grub_errno, "error scaling desktop image"); + } + + grub_video_bitmap_destroy (view->desktop_image); + view->desktop_image = scaled_bitmap; + } + else if (! grub_strcmp ("desktop-color", name)) + grub_gui_parse_color (value, &view->desktop_color); + else if (! grub_strcmp ("terminal-box", name)) + { + grub_err_t err; + err = grub_gui_recreate_box (&view->terminal_box, value, theme_dir); + if (err != GRUB_ERR_NONE) + return err; + } + else if (! grub_strcmp ("title-text", name)) + { + grub_free (view->title_text); + view->title_text = grub_strdup (value); + if (! view->title_text) + return grub_errno; + } + else + { + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "%s:%d:%d unknown property `%s'", + filename, line_num, col_num, name); + } + return grub_errno; +} + +struct parsebuf +{ + char *buf; + int pos; + int len; + int line_num; + int col_num; + const char *filename; + char *theme_dir; + grub_gfxmenu_view_t view; +}; + +static int +has_more (struct parsebuf *p) +{ + return p->pos < p->len; +} + +static int +read_char (struct parsebuf *p) +{ + if (has_more (p)) + { + char c; + c = p->buf[p->pos++]; + if (c == '\n') + { + p->line_num++; + p->col_num = 1; + } + else + { + p->col_num++; + } + return c; + } + else + return -1; +} + +static int +peek_char (struct parsebuf *p) +{ + if (has_more (p)) + return p->buf[p->pos]; + else + return -1; +} + +static int +is_whitespace (char c) +{ + return (c == ' ' + || c == '\t' + || c == '\r' + || c == '\n' + || c == '\f'); +} + +static void +skip_whitespace (struct parsebuf *p) +{ + while (has_more (p) && is_whitespace(peek_char (p))) + read_char (p); +} + +static void +advance_to_next_line (struct parsebuf *p) +{ + int c; + + /* Eat characters up to the newline. */ + do + { + c = read_char (p); + } + while (c != -1 && c != '\n'); +} + +static int +is_identifier_char (int c) +{ + return (c != -1 + && (grub_isalpha(c) + || grub_isdigit(c) + || c == '_' + || c == '-')); +} + +static char * +read_identifier (struct parsebuf *p) +{ + /* Index of the first character of the identifier in p->buf. */ + int start; + /* Next index after the last character of the identifer in p->buf. */ + int end; + + skip_whitespace (p); + + /* Capture the start of the identifier. */ + start = p->pos; + + /* Scan for the end. */ + while (is_identifier_char (peek_char (p))) + read_char (p); + end = p->pos; + + if (end - start < 1) + return 0; + + return grub_new_substring (p->buf, start, end); +} + +static char * +read_expression (struct parsebuf *p) +{ + int start; + int end; + + skip_whitespace (p); + if (peek_char (p) == '"') + { + /* Read as a quoted string. + The quotation marks are not included in the expression value. */ + /* Skip opening quotation mark. */ + read_char (p); + start = p->pos; + while (has_more (p) && peek_char (p) != '"') + read_char (p); + end = p->pos; + /* Skip the terminating quotation mark. */ + read_char (p); + } + else if (peek_char (p) == '(') + { + /* Read as a parenthesized string -- for tuples/coordinates. */ + /* The parentheses are included in the expression value. */ + int c; + + start = p->pos; + do + { + c = read_char (p); + } + while (c != -1 && c != ')'); + end = p->pos; + } + else if (has_more (p)) + { + /* Read as a single word -- for numeric values or words without + whitespace. */ + start = p->pos; + while (has_more (p) && ! is_whitespace (peek_char (p))) + read_char (p); + end = p->pos; + } + else + { + /* The end of the theme file has been reached. */ + grub_error (GRUB_ERR_IO, "%s:%d:%d expression expected in theme file", + p->filename, p->line_num, p->col_num); + return 0; + } + + return grub_new_substring (p->buf, start, end); +} + +/* Read a GUI object specification from the theme file. + Any components created will be added to the GUI container PARENT. */ +static grub_err_t +read_object (struct parsebuf *p, grub_gui_container_t parent) +{ + grub_video_rect_t bounds; + + char *name; + name = read_identifier (p); + if (! name) + goto cleanup; + + grub_gui_component_t component = 0; + if (grub_strcmp (name, "label") == 0) + { + component = grub_gui_label_new (); + } + else if (grub_strcmp (name, "image") == 0) + { + component = grub_gui_image_new (); + } + else if (grub_strcmp (name, "vbox") == 0) + { + component = (grub_gui_component_t) grub_gui_vbox_new (); + } + else if (grub_strcmp (name, "hbox") == 0) + { + component = (grub_gui_component_t) grub_gui_hbox_new (); + } + else if (grub_strcmp (name, "canvas") == 0) + { + component = (grub_gui_component_t) grub_gui_canvas_new (); + } + else if (grub_strcmp (name, "progress_bar") == 0) + { + component = grub_gui_progress_bar_new (); + } + else if (grub_strcmp (name, "circular_progress") == 0) + { + component = grub_gui_circular_progress_new (); + } + else if (grub_strcmp (name, "boot_menu") == 0) + { + component = grub_gui_list_new (); + } + else + { + /* Unknown type. */ + grub_error (GRUB_ERR_IO, "%s:%d:%d unknown object type `%s'", + p->filename, p->line_num, p->col_num, name); + goto cleanup; + } + + if (! component) + goto cleanup; + + /* Inform the component about the theme so it can find its resources. */ + component->ops->set_property (component, "theme_dir", p->theme_dir); + component->ops->set_property (component, "theme_path", p->filename); + + /* Add the component as a child of PARENT. */ + bounds.x = 0; + bounds.y = 0; + bounds.width = -1; + bounds.height = -1; + component->ops->set_bounds (component, &bounds); + parent->ops->add (parent, component); + + skip_whitespace (p); + if (read_char (p) != '{') + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d expected `{' after object type name `%s'", + p->filename, p->line_num, p->col_num, name); + goto cleanup; + } + + while (has_more (p)) + { + skip_whitespace (p); + + /* Check whether the end has been encountered. */ + if (peek_char (p) == '}') + { + /* Skip the closing brace. */ + read_char (p); + break; + } + + if (peek_char (p) == '#') + { + /* Skip comments. */ + advance_to_next_line (p); + continue; + } + + if (peek_char (p) == '+') + { + /* Skip the '+'. */ + read_char (p); + + /* Check whether this component is a container. */ + if (component->ops->is_instance (component, "container")) + { + /* Read the sub-object recursively and add it as a child. */ + if (read_object (p, (grub_gui_container_t) component) != 0) + goto cleanup; + /* After reading the sub-object, resume parsing, expecting + another property assignment or sub-object definition. */ + continue; + } + else + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d attempted to add object to non-container", + p->filename, p->line_num, p->col_num); + goto cleanup; + } + } + + char *property; + property = read_identifier (p); + if (! property) + { + grub_error (GRUB_ERR_IO, "%s:%d:%d identifier expected in theme file", + p->filename, p->line_num, p->col_num); + goto cleanup; + } + + skip_whitespace (p); + if (read_char (p) != '=') + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d expected `=' after property name `%s'", + p->filename, p->line_num, p->col_num, property); + grub_free (property); + goto cleanup; + } + skip_whitespace (p); + + char *value; + value = read_expression (p); + if (! value) + { + grub_free (property); + goto cleanup; + } + + /* Handle the property value. */ + if (grub_strcmp (property, "position") == 0) + { + /* Special case for position value. */ + int x; + int y; + + if (grub_gui_parse_2_tuple (value, &x, &y) == GRUB_ERR_NONE) + { + grub_video_rect_t r; + component->ops->get_bounds (component, &r); + r.x = x; + r.y = y; + component->ops->set_bounds (component, &r); + } + } + else if (grub_strcmp (property, "size") == 0) + { + /* Special case for size value. */ + int w; + int h; + + if (grub_gui_parse_2_tuple (value, &w, &h) == GRUB_ERR_NONE) + { + grub_video_rect_t r; + component->ops->get_bounds (component, &r); + r.width = w; + r.height = h; + component->ops->set_bounds (component, &r); + } + } + else + { + /* General property handling. */ + component->ops->set_property (component, property, value); + } + + grub_free (value); + grub_free (property); + if (grub_errno != GRUB_ERR_NONE) + goto cleanup; + } + + /* Set the object's size to its preferred size unless the user has + explicitly specified the size. */ + component->ops->get_bounds (component, &bounds); + if (bounds.width == -1 || bounds.height == -1) + { + component->ops->get_preferred_size (component, + &bounds.width, &bounds.height); + component->ops->set_bounds (component, &bounds); + } + +cleanup: + grub_free (name); + return grub_errno; +} + +static grub_err_t +read_property (struct parsebuf *p) +{ + char *name; + + /* Read the property name. */ + name = read_identifier (p); + if (! name) + { + advance_to_next_line (p); + return grub_errno; + } + + /* Skip whitespace before separator. */ + skip_whitespace (p); + + /* Read separator. */ + if (read_char (p) != ':') + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d missing separator after property name `%s'", + p->filename, p->line_num, p->col_num, name); + goto done; + } + + /* Skip whitespace after separator. */ + skip_whitespace (p); + + /* Get the value based on its type. */ + if (peek_char (p) == '"') + { + /* String value (e.g., '"My string"'). */ + char *value = read_expression (p); + if (! value) + { + grub_error (GRUB_ERR_IO, "%s:%d:%d missing property value", + p->filename, p->line_num, p->col_num); + goto done; + } + /* If theme_set_string results in an error, grub_errno will be returned + below. */ + theme_set_string (p->view, name, value, p->theme_dir, + p->filename, p->line_num, p->col_num); + grub_free (value); + } + else + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d property value invalid; " + "enclose literal values in quotes (\")", + p->filename, p->line_num, p->col_num); + goto done; + } + +done: + grub_free (name); + return grub_errno; +} + +/* Set properties on the view based on settings from the specified + theme file. */ +grub_err_t +grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path) +{ + grub_file_t file; + struct parsebuf p; + + p.view = view; + p.theme_dir = grub_get_dirname (theme_path); + + file = grub_file_open (theme_path); + if (! file) + { + grub_free (p.theme_dir); + return grub_errno; + } + + p.len = grub_file_size (file); + p.buf = grub_malloc (p.len); + p.pos = 0; + p.line_num = 1; + p.col_num = 1; + p.filename = theme_path; + if (! p.buf) + { + grub_file_close (file); + grub_free (p.theme_dir); + return grub_errno; + } + if (grub_file_read (file, p.buf, p.len) != p.len) + { + grub_free (p.buf); + grub_file_close (file); + grub_free (p.theme_dir); + return grub_errno; + } + + if (view->canvas) + view->canvas->ops->component.destroy (view->canvas); + + view->canvas = grub_gui_canvas_new (); + ((grub_gui_component_t) view->canvas) + ->ops->set_bounds ((grub_gui_component_t) view->canvas, + &view->screen); + + while (has_more (&p)) + { + /* Skip comments (lines beginning with #). */ + if (peek_char (&p) == '#') + { + advance_to_next_line (&p); + continue; + } + + /* Find the first non-whitespace character. */ + skip_whitespace (&p); + + /* Handle the content. */ + if (peek_char (&p) == '+') + { + /* Skip the '+'. */ + read_char (&p); + read_object (&p, view->canvas); + } + else + { + read_property (&p); + } + + if (grub_errno != GRUB_ERR_NONE) + goto fail; + } + + /* Set the new theme path. */ + grub_free (view->theme_path); + view->theme_path = grub_strdup (theme_path); + goto cleanup; + +fail: + if (view->canvas) + { + view->canvas->ops->component.destroy (view->canvas); + view->canvas = 0; + } + +cleanup: + grub_free (p.buf); + grub_file_close (file); + grub_free (p.theme_dir); + return grub_errno; +} diff --git a/gfxmenu/view.c b/gfxmenu/view.c new file mode 100644 index 000000000..56edc86cf --- /dev/null +++ b/gfxmenu/view.c @@ -0,0 +1,497 @@ +/* view.c - Graphical menu interface MVC view. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The component ID identifying GUI components to be updated as the timeout + status changes. */ +#define TIMEOUT_COMPONENT_ID "__timeout__" + +static void init_terminal (grub_gfxmenu_view_t view); +static void destroy_terminal (void); +static grub_err_t set_graphics_mode (void); +static grub_err_t set_text_mode (void); + +/* Create a new view object, loading the theme specified by THEME_PATH and + associating MODEL with the view. */ +grub_gfxmenu_view_t +grub_gfxmenu_view_new (const char *theme_path, grub_gfxmenu_model_t model) +{ + grub_gfxmenu_view_t view; + + view = grub_malloc (sizeof (*view)); + if (! view) + return 0; + + set_graphics_mode (); + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + grub_video_get_viewport ((unsigned *) &view->screen.x, + (unsigned *) &view->screen.y, + (unsigned *) &view->screen.width, + (unsigned *) &view->screen.height); + + /* Clear the screen; there may be garbage left over in video memory, and + loading the menu style (particularly the background) can take a while. */ + grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), + view->screen.x, view->screen.y, + view->screen.width, view->screen.height); + grub_video_swap_buffers (); + + grub_font_t default_font; + grub_gui_color_t default_fg_color; + grub_gui_color_t default_bg_color; + + default_font = grub_font_get ("Helvetica 12"); + default_fg_color = grub_gui_color_rgb (0, 0, 0); + default_bg_color = grub_gui_color_rgb (255, 255, 255); + + view->model = model; + view->canvas = 0; + + view->title_font = default_font; + view->message_font = default_font; + view->terminal_font_name = grub_strdup ("Fixed 10"); + view->title_color = default_fg_color; + view->message_color = default_bg_color; + view->message_bg_color = default_fg_color; + view->desktop_image = 0; + view->desktop_color = default_bg_color; + view->terminal_box = grub_gfxmenu_create_box (0, 0); + view->title_text = grub_strdup ("GRUB Boot Menu"); + view->progress_message_text = 0; + view->theme_path = 0; + + if (grub_gfxmenu_view_load_theme (view, theme_path) != 0) + { + grub_gfxmenu_view_destroy (view); + return 0; + } + + init_terminal (view); + + return view; +} + +/* Destroy the view object. All used memory is freed. */ +void +grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view) +{ + grub_video_bitmap_destroy (view->desktop_image); + if (view->terminal_box) + view->terminal_box->destroy (view->terminal_box); + grub_free (view->terminal_font_name); + grub_free (view->title_text); + grub_free (view->progress_message_text); + grub_free (view->theme_path); + if (view->canvas) + view->canvas->ops->component.destroy (view->canvas); + grub_free (view); + + set_text_mode (); + destroy_terminal (); +} + +/* Sets MESSAGE as the progress message for the view. + MESSAGE can be 0, in which case no message is displayed. */ +static void +set_progress_message (grub_gfxmenu_view_t view, const char *message) +{ + grub_free (view->progress_message_text); + if (message) + view->progress_message_text = grub_strdup (message); + else + view->progress_message_text = 0; +} + +static void +draw_background (grub_gfxmenu_view_t view) +{ + if (view->desktop_image) + { + struct grub_video_bitmap *img = view->desktop_image; + grub_video_blit_bitmap (img, GRUB_VIDEO_BLIT_REPLACE, + view->screen.x, view->screen.y, 0, 0, + grub_video_bitmap_get_width (img), + grub_video_bitmap_get_height (img)); + } + else + { + grub_video_fill_rect (grub_gui_map_color (view->desktop_color), + view->screen.x, view->screen.y, + view->screen.width, view->screen.height); + } +} + +static void +draw_title (grub_gfxmenu_view_t view) +{ + if (! view->title_text) + return; + + /* Center the title. */ + int title_width = grub_font_get_string_width (view->title_font, + view->title_text); + int x = (view->screen.width - title_width) / 2; + int y = 40 + grub_font_get_ascent (view->title_font); + grub_font_draw_string (view->title_text, + view->title_font, + grub_gui_map_color (view->title_color), + x, y); +} + +struct progress_value_data +{ + const char *visible; + const char *start; + const char *end; + const char *value; + const char *text; +}; + +static void +update_timeout_visit (grub_gui_component_t component, + void *userdata) +{ + struct progress_value_data *pv; + pv = (struct progress_value_data *) userdata; + component->ops->set_property (component, "visible", pv->visible); + component->ops->set_property (component, "start", pv->start); + component->ops->set_property (component, "end", pv->end); + component->ops->set_property (component, "value", pv->value); + component->ops->set_property (component, "text", pv->text); +} + +static void +update_timeout (grub_gfxmenu_view_t view) +{ + char startbuf[20]; + char valuebuf[20]; + char msgbuf[120]; + + int timeout = grub_gfxmenu_model_get_timeout_ms (view->model); + int remaining = grub_gfxmenu_model_get_timeout_remaining_ms (view->model); + struct progress_value_data pv; + + pv.visible = timeout > 0 ? "true" : "false"; + grub_sprintf (startbuf, "%d", -timeout); + pv.start = startbuf; + pv.end = "0"; + grub_sprintf (valuebuf, "%d", remaining > 0 ? -remaining : 0); + pv.value = valuebuf; + + int seconds_remaining_rounded_up = (remaining + 999) / 1000; + grub_sprintf (msgbuf, + "The highlighted entry will be booted automatically in %d s.", + seconds_remaining_rounded_up); + pv.text = msgbuf; + + grub_gui_find_by_id ((grub_gui_component_t) view->canvas, + TIMEOUT_COMPONENT_ID, update_timeout_visit, &pv); +} + +static void +update_menu_visit (grub_gui_component_t component, + void *userdata) +{ + grub_gfxmenu_view_t view; + view = userdata; + if (component->ops->is_instance (component, "list")) + { + grub_gui_list_t list = (grub_gui_list_t) component; + list->ops->set_view_info (list, view->theme_path, view->model); + } +} + +/* Update any boot menu components with the current menu model and + theme path. */ +static void +update_menu_components (grub_gfxmenu_view_t view) +{ + grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, + update_menu_visit, view); +} + +static void +draw_message (grub_gfxmenu_view_t view) +{ + char *text = view->progress_message_text; + if (! text) + return; + + grub_font_t font = view->message_font; + grub_video_color_t color = grub_gui_map_color (view->message_color); + + /* Set the timeout bar's frame. */ + grub_video_rect_t f; + f.width = view->screen.width * 4 / 5; + f.height = 50; + f.x = view->screen.x + (view->screen.width - f.width) / 2; + f.y = view->screen.y + view->screen.height - 90 - 20 - f.height; + + /* Border. */ + grub_video_fill_rect (color, + f.x-1, f.y-1, f.width+2, f.height+2); + /* Fill. */ + grub_video_fill_rect (grub_gui_map_color (view->message_bg_color), + f.x, f.y, f.width, f.height); + + /* Center the text. */ + int text_width = grub_font_get_string_width (font, text); + int x = f.x + (f.width - text_width) / 2; + int y = (f.y + (f.height - grub_font_get_descent (font)) / 2 + + grub_font_get_ascent (font) / 2); + grub_font_draw_string (text, font, color, x, y); +} + + +void +grub_gfxmenu_view_draw (grub_gfxmenu_view_t view) +{ + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + update_timeout (view); + update_menu_components (view); + + draw_background (view); + if (view->canvas) + view->canvas->ops->component.paint (view->canvas); + draw_title (view); + draw_message (view); +} + +static grub_err_t +set_graphics_mode (void) +{ + const char *modestr = grub_env_get ("gfxmode"); + if (!modestr || !modestr[0]) + modestr = "auto"; + return grub_video_set_mode (modestr, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); +} + +static grub_err_t +set_text_mode (void) +{ + return grub_video_restore (); +} + +static int term_target_width; +static int term_target_height; +static struct grub_video_render_target *term_target; +static int term_initialized; +static grub_term_output_t term_original; +static grub_gfxmenu_view_t term_view; + +static void +repaint_terminal (int x __attribute ((unused)), + int y __attribute ((unused)), + int width __attribute ((unused)), + int height __attribute ((unused))) +{ + if (! term_view) + return; + + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + grub_gfxmenu_view_draw (term_view); + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + + int termx = term_view->screen.x + + term_view->screen.width * (10 - 7) / 10 / 2; + int termy = term_view->screen.y + + term_view->screen.height * (10 - 7) / 10 / 2; + + grub_gfxmenu_box_t term_box = term_view->terminal_box; + if (term_box) + { + term_box->set_content_size (term_box, + term_target_width, term_target_height); + + term_box->draw (term_box, + termx - term_box->get_left_pad (term_box), + termy - term_box->get_top_pad (term_box)); + } + + grub_video_blit_render_target (term_target, GRUB_VIDEO_BLIT_REPLACE, + termx, termy, + 0, 0, term_target_width, term_target_height); + grub_video_swap_buffers (); +} + +static void +init_terminal (grub_gfxmenu_view_t view) +{ + term_original = grub_term_get_current_output (); + + term_target_width = view->screen.width * 7 / 10; + term_target_height = view->screen.height * 7 / 10; + + grub_video_create_render_target (&term_target, + term_target_width, + term_target_height, + GRUB_VIDEO_MODE_TYPE_RGB + | GRUB_VIDEO_MODE_TYPE_ALPHA); + if (grub_errno != GRUB_ERR_NONE) + return; + + /* Note: currently there is no API for changing the gfxterm font + on the fly, so whatever font the initially loaded theme specifies + will be permanent. */ + grub_gfxterm_init_window (term_target, 0, 0, + term_target_width, term_target_height, 0, + view->terminal_font_name, 3); + if (grub_errno != GRUB_ERR_NONE) + return; + term_initialized = 1; + + /* XXX: store static pointer to the 'view' object so the repaint callback can access it. */ + term_view = view; + grub_gfxterm_set_repaint_callback (repaint_terminal); + grub_term_set_current_output (grub_gfxterm_get_term ()); +} + +static void destroy_terminal (void) +{ + term_view = 0; + if (term_initialized) + grub_gfxterm_destroy_window (); + grub_gfxterm_set_repaint_callback (0); + if (term_target) + grub_video_delete_render_target (term_target); + if (term_original) + grub_term_set_current_output (term_original); +} + + +static void +notify_booting (grub_menu_entry_t entry, void *userdata) +{ + grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata; + + char *s = grub_malloc (100 + grub_strlen (entry->title)); + if (!s) + return; + + grub_sprintf (s, "Booting '%s'", entry->title); + set_progress_message (view, s); + grub_free (s); + grub_gfxmenu_view_draw (view); + grub_video_swap_buffers (); +} + +static void +notify_fallback (grub_menu_entry_t entry, void *userdata) +{ + grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata; + + char *s = grub_malloc (100 + grub_strlen (entry->title)); + if (!s) + return; + + grub_sprintf (s, "Falling back to '%s'", entry->title); + set_progress_message (view, s); + grub_free (s); + grub_gfxmenu_view_draw (view); + grub_video_swap_buffers (); +} + +static void +notify_execution_failure (void *userdata __attribute__ ((unused))) +{ +} + + +static struct grub_menu_execute_callback execute_callback = +{ + .notify_booting = notify_booting, + .notify_fallback = notify_fallback, + .notify_failure = notify_execution_failure +}; + +int +grub_gfxmenu_view_execute_with_fallback (grub_gfxmenu_view_t view, + grub_menu_entry_t entry) +{ + grub_menu_execute_with_fallback (grub_gfxmenu_model_get_menu (view->model), + entry, &execute_callback, (void *) view); + + if (set_graphics_mode () != GRUB_ERR_NONE) + return 0; /* Failure. */ + + /* If we returned, there was a failure. */ + set_progress_message (view, + "Unable to automatically boot. " + "Press SPACE to continue."); + grub_gfxmenu_view_draw (view); + grub_video_swap_buffers (); + while (GRUB_TERM_ASCII_CHAR(grub_getkey ()) != ' ') + { + /* Wait for SPACE to be pressed. */ + } + + set_progress_message (view, 0); /* Clear the message. */ + + return 1; /* Ok. */ +} + +int +grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view, + grub_menu_entry_t entry) +{ + /* Currently we switch back to text mode by restoring + the original terminal before executing the menu entry. + It is hard to make it work when executing a menu entry + that switches video modes -- it using gfxterm in a + window, the repaint callback seems to crash GRUB. */ + /* TODO: Determine if this works when 'gfxterm' was set as + the current terminal before invoking the gfxmenu. */ + destroy_terminal (); + + grub_menu_execute_entry (entry); + if (grub_errno != GRUB_ERR_NONE) + grub_wait_after_message (); + + if (set_graphics_mode () != GRUB_ERR_NONE) + return 0; /* Failure. */ + + init_terminal (view); + return 1; /* Ok. */ +} + +void +grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view __attribute__((unused))) +{ + grub_cmdline_run (1); +} diff --git a/gfxmenu/widget-box.c b/gfxmenu/widget-box.c new file mode 100644 index 000000000..079fd66d4 --- /dev/null +++ b/gfxmenu/widget-box.c @@ -0,0 +1,313 @@ +/* widget_box.c - Pixmap-stylized box widget. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +enum box_pixmaps +{ + BOX_PIXMAP_NW, BOX_PIXMAP_NE, BOX_PIXMAP_SE, BOX_PIXMAP_SW, + BOX_PIXMAP_N, BOX_PIXMAP_E, BOX_PIXMAP_S, BOX_PIXMAP_W, + BOX_PIXMAP_CENTER +}; + +static const char *box_pixmap_names[] = { + /* Corners: */ + "nw", "ne", "se", "sw", + /* Sides: */ + "n", "e", "s", "w", + /* Center: */ + "c" +}; + +#define BOX_NUM_PIXMAPS (sizeof(box_pixmap_names)/sizeof(*box_pixmap_names)) + +static int +get_height (struct grub_video_bitmap *bitmap) +{ + if (bitmap) + return grub_video_bitmap_get_height (bitmap); + else + return 0; +} + +static int +get_width (struct grub_video_bitmap *bitmap) +{ + if (bitmap) + return grub_video_bitmap_get_width (bitmap); + else + return 0; +} + +static void +blit (grub_gfxmenu_box_t self, int pixmap_index, int x, int y) +{ + struct grub_video_bitmap *bitmap; + bitmap = self->scaled_pixmaps[pixmap_index]; + if (! bitmap) + return; + grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_BLEND, + x, y, 0, 0, + grub_video_bitmap_get_width (bitmap), + grub_video_bitmap_get_height (bitmap)); +} + +static void +draw (grub_gfxmenu_box_t self, int x, int y) +{ + int height_n; + int height_s; + int height_e; + int height_w; + int width_n; + int width_s; + int width_e; + int width_w; + + height_n = get_height (self->scaled_pixmaps[BOX_PIXMAP_N]); + height_s = get_height (self->scaled_pixmaps[BOX_PIXMAP_S]); + height_e = get_height (self->scaled_pixmaps[BOX_PIXMAP_E]); + height_w = get_height (self->scaled_pixmaps[BOX_PIXMAP_W]); + width_n = get_width (self->scaled_pixmaps[BOX_PIXMAP_N]); + width_s = get_width (self->scaled_pixmaps[BOX_PIXMAP_S]); + width_e = get_width (self->scaled_pixmaps[BOX_PIXMAP_E]); + width_w = get_width (self->scaled_pixmaps[BOX_PIXMAP_W]); + + /* Draw sides. */ + blit (self, BOX_PIXMAP_N, x + width_w, y); + blit (self, BOX_PIXMAP_S, x + width_w, y + height_n + self->content_height); + blit (self, BOX_PIXMAP_E, x + width_w + self->content_width, y + height_n); + blit (self, BOX_PIXMAP_W, x, y + height_n); + + /* Draw corners. */ + blit (self, BOX_PIXMAP_NW, x, y); + blit (self, BOX_PIXMAP_NE, x + width_w + self->content_width, y); + blit (self, BOX_PIXMAP_SE, + x + width_w + self->content_width, + y + height_n + self->content_height); + blit (self, BOX_PIXMAP_SW, x, y + height_n + self->content_height); + + /* Draw center. */ + blit (self, BOX_PIXMAP_CENTER, x + width_w, y + height_n); +} + +static grub_err_t +scale_pixmap (grub_gfxmenu_box_t self, int i, int w, int h) +{ + struct grub_video_bitmap **scaled = &self->scaled_pixmaps[i]; + struct grub_video_bitmap *raw = self->raw_pixmaps[i]; + + if (raw == 0) + return grub_errno; + + if (w == -1) + w = grub_video_bitmap_get_width (raw); + if (h == -1) + h = grub_video_bitmap_get_height (raw); + + if (*scaled == 0 + || ((int) grub_video_bitmap_get_width (*scaled) != w) + || ((int) grub_video_bitmap_get_height (*scaled) != h)) + { + if (*scaled) + { + grub_video_bitmap_destroy (*scaled); + *scaled = 0; + } + + /* Don't try to create a bitmap with a zero dimension. */ + if (w != 0 && h != 0) + grub_video_bitmap_create_scaled (scaled, w, h, raw, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + if (grub_errno != GRUB_ERR_NONE) + { + grub_error_push (); + grub_error (grub_errno, + "failed to scale bitmap for styled box pixmap #%d", i); + } + } + + return grub_errno; +} + +static void +set_content_size (grub_gfxmenu_box_t self, + int width, int height) +{ + self->content_width = width; + self->content_height = height; + + /* Resize sides to match the width and height. */ + /* It is assumed that the corners width/height match the adjacent sides. */ + + /* Resize N and S sides to match width. */ + if (scale_pixmap(self, BOX_PIXMAP_N, width, -1) != GRUB_ERR_NONE) + return; + if (scale_pixmap(self, BOX_PIXMAP_S, width, -1) != GRUB_ERR_NONE) + return; + + /* Resize E and W sides to match height. */ + if (scale_pixmap(self, BOX_PIXMAP_E, -1, height) != GRUB_ERR_NONE) + return; + if (scale_pixmap(self, BOX_PIXMAP_W, -1, height) != GRUB_ERR_NONE) + return; + + /* Don't scale the corners--they are assumed to match the sides. */ + if (scale_pixmap(self, BOX_PIXMAP_NW, -1, -1) != GRUB_ERR_NONE) + return; + if (scale_pixmap(self, BOX_PIXMAP_SW, -1, -1) != GRUB_ERR_NONE) + return; + if (scale_pixmap(self, BOX_PIXMAP_NE, -1, -1) != GRUB_ERR_NONE) + return; + if (scale_pixmap(self, BOX_PIXMAP_SE, -1, -1) != GRUB_ERR_NONE) + return; + + /* Scale the center area. */ + if (scale_pixmap(self, BOX_PIXMAP_CENTER, width, height) != GRUB_ERR_NONE) + return; +} + +static int +get_left_pad (grub_gfxmenu_box_t self) +{ + return get_width (self->raw_pixmaps[BOX_PIXMAP_W]); +} + +static int +get_top_pad (grub_gfxmenu_box_t self) +{ + return get_height (self->raw_pixmaps[BOX_PIXMAP_N]); +} + +static int +get_right_pad (grub_gfxmenu_box_t self) +{ + return get_width (self->raw_pixmaps[BOX_PIXMAP_E]); +} + +static int +get_bottom_pad (grub_gfxmenu_box_t self) +{ + return get_height (self->raw_pixmaps[BOX_PIXMAP_S]); +} + +static void +destroy (grub_gfxmenu_box_t self) +{ + unsigned i; + for (i = 0; i < BOX_NUM_PIXMAPS; i++) + { + if (self->raw_pixmaps[i]) + grub_video_bitmap_destroy(self->raw_pixmaps[i]); + self->raw_pixmaps[i] = 0; + + if (self->scaled_pixmaps[i]) + grub_video_bitmap_destroy(self->scaled_pixmaps[i]); + self->scaled_pixmaps[i] = 0; + } + grub_free (self->raw_pixmaps); + self->raw_pixmaps = 0; + grub_free (self->scaled_pixmaps); + self->scaled_pixmaps = 0; + + /* Free self: must be the last step! */ + grub_free (self); +} + + +/* Create a new box. If PIXMAPS_PREFIX and PIXMAPS_SUFFIX are both non-null, + then an attempt is made to load the north, south, east, west, northwest, + northeast, southeast, southwest, and center pixmaps. + If either PIXMAPS_PREFIX or PIXMAPS_SUFFIX is 0, then no pixmaps are + loaded, and the box has zero-width borders and is drawn transparent. */ +grub_gfxmenu_box_t +grub_gfxmenu_create_box (const char *pixmaps_prefix, + const char *pixmaps_suffix) +{ + unsigned i; + grub_gfxmenu_box_t box; + + box = (grub_gfxmenu_box_t) grub_malloc (sizeof (*box)); + if (! box) + return 0; + + box->content_width = 0; + box->content_height = 0; + box->raw_pixmaps = + (struct grub_video_bitmap **) + grub_malloc (BOX_NUM_PIXMAPS * sizeof (struct grub_video_bitmap *)); + box->scaled_pixmaps = + (struct grub_video_bitmap **) + grub_malloc (BOX_NUM_PIXMAPS * sizeof (struct grub_video_bitmap *)); + + /* Initialize all pixmap pointers to NULL so that proper destruction can + be performed if an error is encountered partway through construction. */ + for (i = 0; i < BOX_NUM_PIXMAPS; i++) + box->raw_pixmaps[i] = 0; + for (i = 0; i < BOX_NUM_PIXMAPS; i++) + box->scaled_pixmaps[i] = 0; + + /* Load the pixmaps. */ + for (i = 0; i < BOX_NUM_PIXMAPS; i++) + { + if (pixmaps_prefix && pixmaps_suffix) + { + char *path; + char *path_end; + + path = grub_malloc (grub_strlen (pixmaps_prefix) + + grub_strlen (box_pixmap_names[i]) + + grub_strlen (pixmaps_suffix) + + 1); + if (! path) + goto fail_and_destroy; + + /* Construct the specific path for this pixmap. */ + path_end = grub_stpcpy (path, pixmaps_prefix); + path_end = grub_stpcpy (path_end, box_pixmap_names[i]); + path_end = grub_stpcpy (path_end, pixmaps_suffix); + + grub_video_bitmap_load (&box->raw_pixmaps[i], path); + grub_free (path); + + /* Ignore missing pixmaps. */ + grub_errno = GRUB_ERR_NONE; + } + } + + box->draw = draw; + box->set_content_size = set_content_size; + box->get_left_pad = get_left_pad; + box->get_top_pad = get_top_pad; + box->get_right_pad = get_right_pad; + box->get_bottom_pad = get_bottom_pad; + box->destroy = destroy; + return box; + +fail_and_destroy: + destroy (box); + return 0; +} diff --git a/include/grub/gfxmenu_model.h b/include/grub/gfxmenu_model.h new file mode 100644 index 000000000..e5c7da3ac --- /dev/null +++ b/include/grub/gfxmenu_model.h @@ -0,0 +1,59 @@ +/* gfxmenu_model.h - gfxmenu model interface. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_GFXMENU_MODEL_HEADER +#define GRUB_GFXMENU_MODEL_HEADER 1 + +#include + +struct grub_gfxmenu_model; /* Forward declaration of opaque type. */ +typedef struct grub_gfxmenu_model *grub_gfxmenu_model_t; + + +grub_gfxmenu_model_t grub_gfxmenu_model_new (grub_menu_t menu); + +void grub_gfxmenu_model_destroy (grub_gfxmenu_model_t model); + +grub_menu_t grub_gfxmenu_model_get_menu (grub_gfxmenu_model_t model); + +void grub_gfxmenu_model_set_timeout (grub_gfxmenu_model_t model); + +void grub_gfxmenu_model_clear_timeout (grub_gfxmenu_model_t model); + +int grub_gfxmenu_model_get_timeout_ms (grub_gfxmenu_model_t model); + +int grub_gfxmenu_model_get_timeout_remaining_ms (grub_gfxmenu_model_t model); + +int grub_gfxmenu_model_timeout_expired (grub_gfxmenu_model_t model); + +int grub_gfxmenu_model_get_num_entries (grub_gfxmenu_model_t model); + +int grub_gfxmenu_model_get_selected_index (grub_gfxmenu_model_t model); + +void grub_gfxmenu_model_set_selected_index (grub_gfxmenu_model_t model, + int index); + +const char *grub_gfxmenu_model_get_entry_title (grub_gfxmenu_model_t model, + int index); + +grub_menu_entry_t grub_gfxmenu_model_get_entry (grub_gfxmenu_model_t model, + int index); + +#endif /* GRUB_GFXMENU_MODEL_HEADER */ + diff --git a/include/grub/gfxmenu_view.h b/include/grub/gfxmenu_view.h new file mode 100644 index 000000000..1144382f2 --- /dev/null +++ b/include/grub/gfxmenu_view.h @@ -0,0 +1,91 @@ +/* gfxmenu_view.h - gfxmenu view interface. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_GFXMENU_VIEW_HEADER +#define GRUB_GFXMENU_VIEW_HEADER 1 + +#include +#include +#include +#include +#include +#include + +struct grub_gfxmenu_view; /* Forward declaration of opaque type. */ +typedef struct grub_gfxmenu_view *grub_gfxmenu_view_t; + + +grub_gfxmenu_view_t grub_gfxmenu_view_new (const char *theme_path, + grub_gfxmenu_model_t model); + +void grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view); + +/* Set properties on the view based on settings from the specified + theme file. */ +grub_err_t grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, + const char *theme_path); + +grub_err_t grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr, + const char *pattern, const char *theme_dir); + +void grub_gfxmenu_view_draw (grub_gfxmenu_view_t view); + +int grub_gfxmenu_view_execute_with_fallback (grub_gfxmenu_view_t view, + grub_menu_entry_t entry); + +int grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view, + grub_menu_entry_t entry); + +void grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view); + + + +/* Implementation details -- this should not be used outside of the + view itself. */ + +#include +#include +#include +#include +#include + +/* Definition of the private representation of the view. */ +struct grub_gfxmenu_view +{ + grub_video_rect_t screen; + + grub_font_t title_font; + grub_font_t message_font; + char *terminal_font_name; + grub_gui_color_t title_color; + grub_gui_color_t message_color; + grub_gui_color_t message_bg_color; + struct grub_video_bitmap *desktop_image; + grub_gui_color_t desktop_color; + grub_gfxmenu_box_t terminal_box; + char *title_text; + char *progress_message_text; + char *theme_path; + + grub_gui_container_t canvas; + + grub_gfxmenu_model_t model; +}; + +#endif /* ! GRUB_GFXMENU_VIEW_HEADER */ diff --git a/include/grub/gfxwidgets.h b/include/grub/gfxwidgets.h new file mode 100644 index 000000000..f9678bf9e --- /dev/null +++ b/include/grub/gfxwidgets.h @@ -0,0 +1,49 @@ +/* gfxwidgets.h - Widgets for the graphical menu (gfxmenu). */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_GFXWIDGETS_HEADER +#define GRUB_GFXWIDGETS_HEADER 1 + +#include + +typedef struct grub_gfxmenu_box *grub_gfxmenu_box_t; + +struct grub_gfxmenu_box +{ + /* The size of the content. */ + int content_width; + int content_height; + + struct grub_video_bitmap **raw_pixmaps; + struct grub_video_bitmap **scaled_pixmaps; + + void (*draw) (grub_gfxmenu_box_t self, int x, int y); + void (*set_content_size) (grub_gfxmenu_box_t self, + int width, int height); + int (*get_left_pad) (grub_gfxmenu_box_t self); + int (*get_top_pad) (grub_gfxmenu_box_t self); + int (*get_right_pad) (grub_gfxmenu_box_t self); + int (*get_bottom_pad) (grub_gfxmenu_box_t self); + void (*destroy) (grub_gfxmenu_box_t self); +}; + +grub_gfxmenu_box_t grub_gfxmenu_create_box (const char *pixmaps_prefix, + const char *pixmaps_suffix); + +#endif /* ! GRUB_GFXWIDGETS_HEADER */ diff --git a/include/grub/gui.h b/include/grub/gui.h new file mode 100644 index 000000000..5b785dbb5 --- /dev/null +++ b/include/grub/gui.h @@ -0,0 +1,165 @@ +/* gui.h - GUI components header file. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +#ifndef GRUB_GUI_H +#define GRUB_GUI_H 1 + +/* A representation of a color. Unlike grub_video_color_t, this + representation is independent of any video mode specifics. */ +typedef struct grub_gui_color +{ + grub_uint8_t red; + grub_uint8_t green; + grub_uint8_t blue; + grub_uint8_t alpha; +} grub_gui_color_t; + +typedef struct grub_gui_component *grub_gui_component_t; +typedef struct grub_gui_container *grub_gui_container_t; +typedef struct grub_gui_list *grub_gui_list_t; + +typedef void (*grub_gui_component_callback) (grub_gui_component_t component, + void *userdata); + +/* Component interface. */ + +struct grub_gui_component_ops +{ + void (*destroy) (void *self); + const char * (*get_id) (void *self); + int (*is_instance) (void *self, const char *type); + void (*paint) (void *self); + void (*set_parent) (void *self, grub_gui_container_t parent); + grub_gui_container_t (*get_parent) (void *self); + void (*set_bounds) (void *self, const grub_video_rect_t *bounds); + void (*get_bounds) (void *self, grub_video_rect_t *bounds); + void (*get_preferred_size) (void *self, int *width, int *height); + grub_err_t (*set_property) (void *self, const char *name, const char *value); +}; + +struct grub_gui_container_ops +{ + struct grub_gui_component_ops component; + void (*add) (void *self, grub_gui_component_t comp); + void (*remove) (void *self, grub_gui_component_t comp); + void (*iterate_children) (void *self, + grub_gui_component_callback cb, void *userdata); +}; + +struct grub_gui_list_ops +{ + struct grub_gui_component_ops component_ops; + void (*set_view_info) (void *self, + const char *theme_path, + grub_gfxmenu_model_t menu); +}; + +struct grub_gui_component +{ + struct grub_gui_component_ops *ops; +}; + +struct grub_gui_container +{ + struct grub_gui_container_ops *ops; +}; + +struct grub_gui_list +{ + struct grub_gui_list_ops *ops; +}; + + +/* Interfaces to concrete component classes. */ + +grub_gui_container_t grub_gui_canvas_new (void); +grub_gui_container_t grub_gui_vbox_new (void); +grub_gui_container_t grub_gui_hbox_new (void); +grub_gui_component_t grub_gui_label_new (void); +grub_gui_component_t grub_gui_image_new (void); +grub_gui_component_t grub_gui_progress_bar_new (void); +grub_gui_component_t grub_gui_list_new (void); +grub_gui_component_t grub_gui_circular_progress_new (void); + +/* Manipulation functions. */ + +/* Visit all components with the specified ID. */ +void grub_gui_find_by_id (grub_gui_component_t root, + const char *id, + grub_gui_component_callback cb, + void *userdata); + +/* Visit all components. */ +void grub_gui_iterate_recursively (grub_gui_component_t root, + grub_gui_component_callback cb, + void *userdata); + +/* Helper functions. */ + +static __inline void +grub_gui_save_viewport (grub_video_rect_t *r) +{ + grub_video_get_viewport ((unsigned *) &r->x, + (unsigned *) &r->y, + (unsigned *) &r->width, + (unsigned *) &r->height); +} + +static __inline void +grub_gui_restore_viewport (const grub_video_rect_t *r) +{ + grub_video_set_viewport (r->x, r->y, r->width, r->height); +} + +/* Set a new viewport relative the the current one, saving the current + viewport in OLD so it can be later restored. */ +static __inline void +grub_gui_set_viewport (const grub_video_rect_t *r, grub_video_rect_t *old) +{ + grub_gui_save_viewport (old); + grub_video_set_viewport (old->x + r->x, + old->y + r->y, + r->width, + r->height); +} + +static __inline grub_gui_color_t +grub_gui_color_rgb (int r, int g, int b) +{ + grub_gui_color_t c; + c.red = r; + c.green = g; + c.blue = b; + c.alpha = 255; + return c; +} + +static __inline grub_video_color_t +grub_gui_map_color (grub_gui_color_t c) +{ + return grub_video_map_rgba (c.red, c.green, c.blue, c.alpha); +} + +#endif /* ! GRUB_GUI_H */ diff --git a/include/grub/gui_string_util.h b/include/grub/gui_string_util.h new file mode 100644 index 000000000..7b5fbb3ea --- /dev/null +++ b/include/grub/gui_string_util.h @@ -0,0 +1,39 @@ +/* gui_string_util.h - String utilities for the graphical menu interface. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_GUI_STRING_UTIL_HEADER +#define GRUB_GUI_STRING_UTIL_HEADER 1 + +#include +#include + +char *grub_new_substring (const char *buf, + grub_size_t start, grub_size_t end); + +char *grub_resolve_relative_path (const char *base, const char *path); + +char *grub_get_dirname (const char *file_path); + +int grub_gui_get_named_color (const char *name, grub_gui_color_t *color); + +grub_err_t grub_gui_parse_color (const char *s, grub_gui_color_t *color); + +grub_err_t grub_gui_parse_2_tuple (const char *s, int *px, int *py); + +#endif /* GRUB_GUI_STRING_UTIL_HEADER */ diff --git a/include/grub/icon_manager.h b/include/grub/icon_manager.h new file mode 100644 index 000000000..81c488416 --- /dev/null +++ b/include/grub/icon_manager.h @@ -0,0 +1,41 @@ +/* icon_manager.h - gfxmenu icon manager. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_ICON_MANAGER_HEADER +#define GRUB_ICON_MANAGER_HEADER 1 + +#include +#include + +/* Forward declaration of opaque structure handle type. */ +typedef struct grub_gfxmenu_icon_manager *grub_gfxmenu_icon_manager_t; + +grub_gfxmenu_icon_manager_t grub_gfxmenu_icon_manager_new (void); +void grub_gfxmenu_icon_manager_destroy (grub_gfxmenu_icon_manager_t mgr); +void grub_gfxmenu_icon_manager_clear_cache (grub_gfxmenu_icon_manager_t mgr); +void grub_gfxmenu_icon_manager_set_theme_path (grub_gfxmenu_icon_manager_t mgr, + const char *path); +void grub_gfxmenu_icon_manager_set_icon_size (grub_gfxmenu_icon_manager_t mgr, + int width, int height); +struct grub_video_bitmap * +grub_gfxmenu_icon_manager_get_icon (grub_gfxmenu_icon_manager_t mgr, + grub_menu_entry_t entry); + +#endif /* GRUB_ICON_MANAGER_HEADER */ + diff --git a/include/grub/term.h b/include/grub/term.h index 316d75390..20b85d1cd 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -261,7 +261,7 @@ grub_term_set_current_input (grub_term_input_t term) } static inline grub_err_t -grub_term_set_current_output (grub_term_output_t term) +grub_term_set_current_output (const struct grub_term_output *term) { return grub_handler_set_current (&grub_term_output_class, GRUB_AS_HANDLER (term)); From 704e21180ed65e96111383a8b780eff614e0e035 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Nov 2009 16:07:16 +0100 Subject: [PATCH 17/67] At least it compiles now --- gfxmenu/gui_label.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gfxmenu/gui_label.c b/gfxmenu/gui_label.c index 2e49c787e..eb2a495ff 100644 --- a/gfxmenu/gui_label.c +++ b/gfxmenu/gui_label.c @@ -151,7 +151,7 @@ label_get_preferred_size (void *vself, int *width, int *height) *height = self->preferred_height; } -static void +static grub_err_t label_set_property (void *vself, const char *name, const char *value) { grub_gui_label_t self = vself; @@ -204,6 +204,7 @@ label_set_property (void *vself, const char *name, const char *value) else self->id = 0; } + return GRUB_ERR_NONE; } static struct grub_gui_component_ops label_ops = From 8dec533a1cdeafd13c239121d36ffd507575bc47 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Nov 2009 22:26:08 +0100 Subject: [PATCH 18/67] ChangeLog --- ChangeLog.gfxmenu | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 ChangeLog.gfxmenu diff --git a/ChangeLog.gfxmenu b/ChangeLog.gfxmenu new file mode 100644 index 000000000..bc9db7170 --- /dev/null +++ b/ChangeLog.gfxmenu @@ -0,0 +1,31 @@ +2009-11-20 Colin D Bennett + + * conf/common.rmk (pkglib_MODULES): Add gfxmenu.mod. + (gfxmenu_mod_SOURCES): New variable. + (gfxmenu_mod_CFLAGS): Likewise. + (gfxmenu_mod_LDFLAGS): Likewise. + * include/grub/term.h (grub_term_set_current_output): Declare + argument as const. + * docs/gfxmenu-theme-example.txt: New file. + * gfxmenu/gfxmenu.c: Likewise. + * gfxmenu/gui_box.c: Likewise. + * gfxmenu/gui_canvas.c: Likewise. + * gfxmenu/gui_circular_progress.c: Likewise. + * gfxmenu/gui_image.c: Likewise. + * gfxmenu/gui_label.c: Likewise. + * gfxmenu/gui_list.c: Likewise. + * gfxmenu/gui_progress_bar.c: Likewise. + * gfxmenu/gui_string_util.c: Likewise. + * gfxmenu/gui_util.c: Likewise. + * gfxmenu/icon_manager.c: Likewise. + * gfxmenu/model.c: Likewise. + * gfxmenu/named_colors.c: Likewise. + * gfxmenu/theme_loader.c: Likewise. + * gfxmenu/view.c: Likewise. + * gfxmenu/widget-box.c: Likewise. + * include/grub/gfxmenu_model.h: Likewise. + * include/grub/gfxmenu_view.h: Likewise. + * include/grub/gfxwidgets.h: Likewise. + * include/grub/gui.h: Likewise. + * include/grub/gui_string_util.h: Likewise. + * include/grub/icon_manager.h: Likewise. From aff798d6f4ae597c6b887abc8977d63bc434aa10 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Nov 2009 15:29:12 +0100 Subject: [PATCH 19/67] icondir support --- gfxmenu/gui_string_util.c | 13 ++++++++++--- gfxmenu/icon_manager.c | 18 ++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/gfxmenu/gui_string_util.c b/gfxmenu/gui_string_util.c index 41170d724..31b2f0aca 100644 --- a/gfxmenu/gui_string_util.c +++ b/gfxmenu/gui_string_util.c @@ -150,18 +150,25 @@ grub_resolve_relative_path (const char *base, const char *path) char *abspath; char *canonpath; char *p; + grub_size_t l; /* If PATH is an absolute path, then just use it as is. */ if (path[0] == '/' || path[0] == '(') return canonicalize_path (path); - abspath = grub_malloc (grub_strlen (base) + grub_strlen (path) + 1); + abspath = grub_malloc (grub_strlen (base) + grub_strlen (path) + 3); if (! abspath) return 0; - /* Concatenate BASE and PATH. - Note that BASE is expected to have a trailing slash. */ + /* Concatenate BASE and PATH. */ p = grub_stpcpy (abspath, base); + l = grub_strlen (abspath); + if (l == 0 || abspath[l-1] != '/') + { + *p = '/'; + p++; + *p = 0; + } grub_stpcpy (p, path); canonpath = canonicalize_path (abspath); diff --git a/gfxmenu/icon_manager.c b/gfxmenu/icon_manager.c index a362882e1..b7b891991 100644 --- a/gfxmenu/icon_manager.c +++ b/gfxmenu/icon_manager.c @@ -26,6 +26,7 @@ #include #include #include +#include /* Currently hard coded to '.png' extension. */ static const char icon_extension[] = ".png"; @@ -200,19 +201,16 @@ get_icon_by_class (grub_gfxmenu_icon_manager_t mgr, const char *class_name) icon = try_loading_icon (mgr, icons_dir, class_name); grub_free (icons_dir); } + + grub_free (theme_dir); if (! icon) { - /* If the theme doesn't have an appropriate icon, check in - "grub/themes/icons". */ - /* TODO use GRUB prefix "/icons" */ - icons_dir = grub_resolve_relative_path (theme_dir, "../icons/"); - if (icons_dir) - { - icon = try_loading_icon (mgr, icons_dir, class_name); - grub_free (icons_dir); - } + const char *icondir; + + icondir = grub_env_get ("icondir"); + if (icondir) + icon = try_loading_icon (mgr, icondir, class_name); } - grub_free (theme_dir); /* No icon was found. */ /* This should probably be noted in the cache, so that a search is not From 87efa251d5ff7474bc5827d6aa1957a12880e3a4 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Nov 2009 17:48:05 +0100 Subject: [PATCH 20/67] Fix a bug in icondir handling --- gfxmenu/icon_manager.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/gfxmenu/icon_manager.c b/gfxmenu/icon_manager.c index b7b891991..0c304ede0 100644 --- a/gfxmenu/icon_manager.c +++ b/gfxmenu/icon_manager.c @@ -137,14 +137,21 @@ static struct grub_video_bitmap * try_loading_icon (grub_gfxmenu_icon_manager_t mgr, const char *dir, const char *class_name) { - char *path = grub_malloc (grub_strlen (dir) - + grub_strlen (class_name) - + grub_strlen (icon_extension) - + 1); + char *path; + int l; + + path = grub_malloc (grub_strlen (dir) + grub_strlen (class_name) + + grub_strlen (icon_extension) + 3); if (! path) return 0; grub_strcpy (path, dir); + l = grub_strlen (path); + if (path[l-1] != '/') + { + path[l] = '/'; + path[l+1] = 0; + } grub_strcat (path, class_name); grub_strcat (path, icon_extension); From f5b23252e2f071650bce4cb9e39ef18f211e95a2 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sat, 21 Nov 2009 20:59:48 +0000 Subject: [PATCH 21/67] 2009-11-21 Robert Millan * maintainance/gentrigtables.py: Avoid duplicate hardcoding of integer constants. --- ChangeLog.trig | 5 +++++ maintainance/gentrigtables.py | 16 +++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ChangeLog.trig b/ChangeLog.trig index c3cd73594..725e67859 100644 --- a/ChangeLog.trig +++ b/ChangeLog.trig @@ -1,3 +1,8 @@ +2009-11-21 Robert Millan + + * maintainance/gentrigtables.py: Avoid duplicate hardcoding of + integer constants. + 2009-11-14 Colin D Bennet Trigonometry support. diff --git a/maintainance/gentrigtables.py b/maintainance/gentrigtables.py index 7c069f833..81b7bd058 100644 --- a/maintainance/gentrigtables.py +++ b/maintainance/gentrigtables.py @@ -2,7 +2,7 @@ # Script to generate trigonometric function tables. # # GRUB -- GRand Unified Bootloader -# Copyright (C) 2008 Free Software Foundation, Inc. +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. # # GRUB is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -41,14 +41,16 @@ def writeTable(arr, name): def main(): sintab = [] costab = [] - for i in range(256): + angle_max = 256 + fraction_scale = 16384 + for i in range(angle_max): # Convert to an angle in 1/256 of a circle. - x = i * 2 * pi / 256 - sintab.append(int(round(sin(x) * 16384))) - costab.append(int(round(cos(x) * 16384))) + x = i * 2 * pi / angle_max + sintab.append(int(round(sin(x) * fraction_scale))) + costab.append(int(round(cos(x) * fraction_scale))) - write("#define TRIG_ANGLE_MAX 256\n") - write("#define TRIG_FRACTION_SCALE 16384\n") + write("#define TRIG_ANGLE_MAX " + str (angle_max) + "\n") + write("#define TRIG_FRACTION_SCALE " + str (fraction_scale) + "\n") writeTable(sintab, "sintab") writeTable(costab, "costab") From d2be7481856e8c8296a230ed91c410dac81fb207 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sat, 21 Nov 2009 21:44:08 +0000 Subject: [PATCH 22/67] 2009-11-21 Robert Millan * maintainance/gentrigtables.py: Remove. * lib/trig.c: Likewise. * gentrigtables.c: New file. C rewrite of gentrigtables.py. * conf/common.rmk (trig_mod_SOURCES): Replace `lib/trig.c' with `trigtables.c'. (trigtables.c): New rule. (gentrigtables): Likewise. (DISTCLEANFILES): Add `trigtables.c' and `gentrigtables'. --- ChangeLog.trig | 13 ++++++ conf/common.rmk | 10 ++++- gentrigtables.c | 48 ++++++++++++++++++++ lib/trig.c | 83 ----------------------------------- maintainance/gentrigtables.py | 60 ------------------------- 5 files changed, 69 insertions(+), 145 deletions(-) create mode 100644 gentrigtables.c delete mode 100644 lib/trig.c delete mode 100644 maintainance/gentrigtables.py diff --git a/ChangeLog.trig b/ChangeLog.trig index 725e67859..6aef8f894 100644 --- a/ChangeLog.trig +++ b/ChangeLog.trig @@ -1,3 +1,16 @@ +2009-11-21 Robert Millan + + * maintainance/gentrigtables.py: Remove. + * lib/trig.c: Likewise. + + * gentrigtables.c: New file. C rewrite of gentrigtables.py. + + * conf/common.rmk (trig_mod_SOURCES): Replace `lib/trig.c' with + `trigtables.c'. + (trigtables.c): New rule. + (gentrigtables): Likewise. + (DISTCLEANFILES): Add `trigtables.c' and `gentrigtables'. + 2009-11-21 Robert Millan * maintainance/gentrigtables.py: Avoid duplicate hardcoding of diff --git a/conf/common.rmk b/conf/common.rmk index 439f468dd..e841d5608 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -660,12 +660,18 @@ xnu_uuid_mod_SOURCES = commands/xnu_uuid.c xnu_uuid_mod_CFLAGS = $(COMMON_CFLAGS) xnu_uuid_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For trig.mod. pkglib_MODULES += trig.mod -trig_mod_SOURCES = lib/trig.c +trig_mod_SOURCES = trigtables.c trig_mod_CFLAGS = $(COMMON_CFLAGS) trig_mod_LDFLAGS = $(COMMON_LDFLAGS) +trigtables.c: gentrigtables + ./gentrigtables > $@ +DISTCLEANFILES += trigtables.c +gentrigtables: gentrigtables.c + $(CC) -o $@ $^ $(CPPFLAGS) -lm +DISTCLEANFILES += gentrigtables + pkglib_MODULES += setjmp.mod setjmp_mod_SOURCES = lib/$(target_cpu)/setjmp.S setjmp_mod_ASFLAGS = $(COMMON_ASFLAGS) diff --git a/gentrigtables.c b/gentrigtables.c new file mode 100644 index 000000000..3ef6d08f7 --- /dev/null +++ b/gentrigtables.c @@ -0,0 +1,48 @@ +/* Generate trigonometric function tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008, 2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#define _GNU_SOURCE 1 + +#include +#include +#include + +int +main () +{ + int i; + + printf ("#include \n"); + +#define TAB(op) \ + printf ("grub_int16_t grub_trig_" #op "tab[] =\n{"); \ + for (i = 0; i < GRUB_TRIG_ANGLE_MAX; i++) \ + { \ + double x = i * 2 * M_PI / GRUB_TRIG_ANGLE_MAX; \ + if (i % 10 == 0) \ + printf ("\n "); \ + printf ("%d,", (int) (round (op (x) * GRUB_TRIG_FRACTION_SCALE))); \ + } \ + printf ("\n};\n") + + TAB(sin); + TAB(cos); + + exit (0); +} diff --git a/lib/trig.c b/lib/trig.c deleted file mode 100644 index e36aa38ef..000000000 --- a/lib/trig.c +++ /dev/null @@ -1,83 +0,0 @@ -/* trig.c - Trigonometric table definitions. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. - * - * GRUB 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. - * - * GRUB 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 GRUB. If not, see . - */ - -#include - -/* These tables were generated with `gentrigtables.py'. */ - -short grub_trig_sintab[] = -{ - 0,402,804,1205,1606,2006,2404,2801,3196,3590, - 3981,4370,4756,5139,5520,5897,6270,6639,7005,7366, - 7723,8076,8423,8765,9102,9434,9760,10080,10394,10702, - 11003,11297,11585,11866,12140,12406,12665,12916,13160,13395, - 13623,13842,14053,14256,14449,14635,14811,14978,15137,15286, - 15426,15557,15679,15791,15893,15986,16069,16143,16207,16261, - 16305,16340,16364,16379,16384,16379,16364,16340,16305,16261, - 16207,16143,16069,15986,15893,15791,15679,15557,15426,15286, - 15137,14978,14811,14635,14449,14256,14053,13842,13623,13395, - 13160,12916,12665,12406,12140,11866,11585,11297,11003,10702, - 10394,10080,9760,9434,9102,8765,8423,8076,7723,7366, - 7005,6639,6270,5897,5520,5139,4756,4370,3981,3590, - 3196,2801,2404,2006,1606,1205,804,402,0,-402, - -804,-1205,-1606,-2006,-2404,-2801,-3196,-3590,-3981,-4370, - -4756,-5139,-5520,-5897,-6270,-6639,-7005,-7366,-7723,-8076, - -8423,-8765,-9102,-9434,-9760,-10080,-10394,-10702,-11003,-11297, - -11585,-11866,-12140,-12406,-12665,-12916,-13160,-13395,-13623,-13842, - -14053,-14256,-14449,-14635,-14811,-14978,-15137,-15286,-15426,-15557, - -15679,-15791,-15893,-15986,-16069,-16143,-16207,-16261,-16305,-16340, - -16364,-16379,-16384,-16379,-16364,-16340,-16305,-16261,-16207,-16143, - -16069,-15986,-15893,-15791,-15679,-15557,-15426,-15286,-15137,-14978, - -14811,-14635,-14449,-14256,-14053,-13842,-13623,-13395,-13160,-12916, - -12665,-12406,-12140,-11866,-11585,-11297,-11003,-10702,-10394,-10080, - -9760,-9434,-9102,-8765,-8423,-8076,-7723,-7366,-7005,-6639, - -6270,-5897,-5520,-5139,-4756,-4370,-3981,-3590,-3196,-2801, - -2404,-2006,-1606,-1205,-804,-402 -}; - -short grub_trig_costab[] = -{ - 16384,16379,16364,16340,16305,16261,16207,16143,16069,15986, - 15893,15791,15679,15557,15426,15286,15137,14978,14811,14635, - 14449,14256,14053,13842,13623,13395,13160,12916,12665,12406, - 12140,11866,11585,11297,11003,10702,10394,10080,9760,9434, - 9102,8765,8423,8076,7723,7366,7005,6639,6270,5897, - 5520,5139,4756,4370,3981,3590,3196,2801,2404,2006, - 1606,1205,804,402,0,-402,-804,-1205,-1606,-2006, - -2404,-2801,-3196,-3590,-3981,-4370,-4756,-5139,-5520,-5897, - -6270,-6639,-7005,-7366,-7723,-8076,-8423,-8765,-9102,-9434, - -9760,-10080,-10394,-10702,-11003,-11297,-11585,-11866,-12140,-12406, - -12665,-12916,-13160,-13395,-13623,-13842,-14053,-14256,-14449,-14635, - -14811,-14978,-15137,-15286,-15426,-15557,-15679,-15791,-15893,-15986, - -16069,-16143,-16207,-16261,-16305,-16340,-16364,-16379,-16384,-16379, - -16364,-16340,-16305,-16261,-16207,-16143,-16069,-15986,-15893,-15791, - -15679,-15557,-15426,-15286,-15137,-14978,-14811,-14635,-14449,-14256, - -14053,-13842,-13623,-13395,-13160,-12916,-12665,-12406,-12140,-11866, - -11585,-11297,-11003,-10702,-10394,-10080,-9760,-9434,-9102,-8765, - -8423,-8076,-7723,-7366,-7005,-6639,-6270,-5897,-5520,-5139, - -4756,-4370,-3981,-3590,-3196,-2801,-2404,-2006,-1606,-1205, - -804,-402,0,402,804,1205,1606,2006,2404,2801, - 3196,3590,3981,4370,4756,5139,5520,5897,6270,6639, - 7005,7366,7723,8076,8423,8765,9102,9434,9760,10080, - 10394,10702,11003,11297,11585,11866,12140,12406,12665,12916, - 13160,13395,13623,13842,14053,14256,14449,14635,14811,14978, - 15137,15286,15426,15557,15679,15791,15893,15986,16069,16143, - 16207,16261,16305,16340,16364,16379 -}; - diff --git a/maintainance/gentrigtables.py b/maintainance/gentrigtables.py deleted file mode 100644 index 81b7bd058..000000000 --- a/maintainance/gentrigtables.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/python -# Script to generate trigonometric function tables. -# -# GRUB -- GRand Unified Bootloader -# Copyright (C) 2008, 2009 Free Software Foundation, Inc. -# -# GRUB 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. -# -# GRUB 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 GRUB. If not, see . - -from math import * -from sys import stdout - -def write(x): - stdout.write(x) - -def writeTable(arr, name): - indent = ' ' * 4 - write("short ") - write(name) - write("[] =\n{\n") - write(indent) - for i in range(len(arr)): - if i != 0: - write(",") - if i % 10 == 0: - write("\n") - write(indent) - write("%d" % arr[i]) - write("\n};\n") - -def main(): - sintab = [] - costab = [] - angle_max = 256 - fraction_scale = 16384 - for i in range(angle_max): - # Convert to an angle in 1/256 of a circle. - x = i * 2 * pi / angle_max - sintab.append(int(round(sin(x) * fraction_scale))) - costab.append(int(round(cos(x) * fraction_scale))) - - write("#define TRIG_ANGLE_MAX " + str (angle_max) + "\n") - write("#define TRIG_FRACTION_SCALE " + str (fraction_scale) + "\n") - writeTable(sintab, "sintab") - writeTable(costab, "costab") - -if __name__ == "__main__": - main() - -# vim:ai et sw=4 ts=4 From a5c894bcd986b2ad3bba9d17d732d5542b39e168 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 24 Nov 2009 04:19:33 +0100 Subject: [PATCH 23/67] Enable gfxmenu on grub-emu --- conf/any-emu.rmk | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/conf/any-emu.rmk b/conf/any-emu.rmk index 82e297986..d79ec542b 100644 --- a/conf/any-emu.rmk +++ b/conf/any-emu.rmk @@ -45,6 +45,14 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ video/readers/jpeg.c video/readers/png.c font/font_cmd.c \ font/font.c term/gfxterm.c io/bufio.c \ \ + gfxmenu/gfxmenu.c gfxmenu/model.c gfxmenu/view.c \ + gfxmenu/icon_manager.c gfxmenu/theme_loader.c \ + gfxmenu/widget-box.c gfxmenu/gui_canvas.c \ + gfxmenu/gui_circular_progress.c gfxmenu/gui_box.c \ + gfxmenu/gui_label.c gfxmenu/gui_list.c gfxmenu/gui_image.c \ + gfxmenu/gui_progress_bar.c gfxmenu/gui_util.c \ + gfxmenu/gui_string_util.c gfxmenu/named_colors.c trigtables.c \ + \ util/console.c util/hostfs.c util/grub-emu.c util/misc.c \ util/hostdisk.c util/getroot.c \ \ @@ -87,6 +95,13 @@ DISTCLEANFILES += grub_emu_init.c # FIXME: this could be shared with common.rmk +trigtables.c: gentrigtables + ./gentrigtables > $@ +DISTCLEANFILES += trigtables.c +gentrigtables: gentrigtables.c + $(CC) -o $@ $^ $(CPPFLAGS) -lm +DISTCLEANFILES += gentrigtables + # For grub-mkfont. ifeq ($(enable_grub_mkfont), yes) bin_UTILITIES += grub-mkfont From a9c12f853332e801a4a300ace7fadfc8d9d5738f Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 24 Nov 2009 04:20:18 +0100 Subject: [PATCH 24/67] Remove hardcoded hotkeys --- gfxmenu/gfxmenu.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/gfxmenu/gfxmenu.c b/gfxmenu/gfxmenu.c index 85ce5879d..c854c68da 100644 --- a/gfxmenu/gfxmenu.c +++ b/gfxmenu/gfxmenu.c @@ -92,26 +92,6 @@ process_key_press (int c, switch_to_text_menu (); *should_exit = 1; } - else if (c == '1') - { - grub_gfxmenu_view_load_theme (view, - "/boot/grub/themes/proto/theme.txt"); - } - else if (c == '2') - { - grub_gfxmenu_view_load_theme (view, - "/boot/grub/themes/winter/theme.txt"); - } - else if (c == '3') - { - grub_gfxmenu_view_load_theme (view, - "/boot/grub/themes/ubuntu1/theme.txt"); - } - else if (c == '4') - { - grub_gfxmenu_view_load_theme (view, - "/boot/grub/themes/ubuntu2/theme.txt"); - } else if (nested && c == GRUB_TERM_ESC) { *should_exit = 1; From 8f41eb558284ffca53d8e80a98a6924b286f09ab Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 24 Nov 2009 04:21:07 +0100 Subject: [PATCH 25/67] Use return instead of exit () in gentrigtables.c --- gentrigtables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gentrigtables.c b/gentrigtables.c index 3ef6d08f7..772cd6224 100644 --- a/gentrigtables.c +++ b/gentrigtables.c @@ -44,5 +44,5 @@ main () TAB(sin); TAB(cos); - exit (0); + return 0; } From 93fd2dd8095288fd823b746a30a3f8430d9c11fd Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 24 Nov 2009 04:22:22 +0100 Subject: [PATCH 26/67] Optimise gfxterm in gfxmenu by avoiding indirect repainting --- gfxmenu/view.c | 93 +++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/gfxmenu/view.c b/gfxmenu/view.c index 56edc86cf..e807d3838 100644 --- a/gfxmenu/view.c +++ b/gfxmenu/view.c @@ -42,6 +42,8 @@ status changes. */ #define TIMEOUT_COMPONENT_ID "__timeout__" +static grub_gfxmenu_view_t term_view; + static void init_terminal (grub_gfxmenu_view_t view); static void destroy_terminal (void); static grub_err_t set_graphics_mode (void); @@ -310,86 +312,82 @@ set_text_mode (void) static int term_target_width; static int term_target_height; -static struct grub_video_render_target *term_target; static int term_initialized; static grub_term_output_t term_original; -static grub_gfxmenu_view_t term_view; static void -repaint_terminal (int x __attribute ((unused)), - int y __attribute ((unused)), - int width __attribute ((unused)), - int height __attribute ((unused))) +draw_terminal_box (void) { - if (! term_view) + grub_gfxmenu_box_t term_box; + int termx; + int termy; + + term_box = term_view->terminal_box; + if (!term_box) return; - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); - grub_gfxmenu_view_draw (term_view); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); - - int termx = term_view->screen.x - + term_view->screen.width * (10 - 7) / 10 / 2; - int termy = term_view->screen.y - + term_view->screen.height * (10 - 7) / 10 / 2; - - grub_gfxmenu_box_t term_box = term_view->terminal_box; - if (term_box) - { - term_box->set_content_size (term_box, - term_target_width, term_target_height); - - term_box->draw (term_box, - termx - term_box->get_left_pad (term_box), - termy - term_box->get_top_pad (term_box)); - } - - grub_video_blit_render_target (term_target, GRUB_VIDEO_BLIT_REPLACE, - termx, termy, - 0, 0, term_target_width, term_target_height); - grub_video_swap_buffers (); + termx = term_view->screen.x + term_view->screen.width * (10 - 7) / 10 / 2; + termy = term_view->screen.y + term_view->screen.height * (10 - 7) / 10 / 2; + + term_box->set_content_size (term_box, term_target_width, + term_target_height); + + term_box->draw (term_box, + termx - term_box->get_left_pad (term_box), + termy - term_box->get_top_pad (term_box)); } static void init_terminal (grub_gfxmenu_view_t view) { + int termx; + int termy; + struct grub_video_mode_info mode_info; + grub_err_t err; + int double_repaint; + term_original = grub_term_get_current_output (); term_target_width = view->screen.width * 7 / 10; term_target_height = view->screen.height * 7 / 10; - grub_video_create_render_target (&term_target, - term_target_width, - term_target_height, - GRUB_VIDEO_MODE_TYPE_RGB - | GRUB_VIDEO_MODE_TYPE_ALPHA); - if (grub_errno != GRUB_ERR_NONE) - return; + termx = view->screen.x + view->screen.width * (10 - 7) / 10 / 2; + termy = view->screen.y + view->screen.height * (10 - 7) / 10 / 2; + + err = grub_video_get_info (&mode_info); + if (err) + { + grub_errno = GRUB_ERR_NONE; + double_repaint = 1; + } + else + double_repaint = (mode_info.mode_type + & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED) + && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); /* Note: currently there is no API for changing the gfxterm font on the fly, so whatever font the initially loaded theme specifies will be permanent. */ - grub_gfxterm_init_window (term_target, 0, 0, - term_target_width, term_target_height, 0, - view->terminal_font_name, 3); + grub_gfxterm_init_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, termx, termy, + term_target_width, term_target_height, + double_repaint, view->terminal_font_name, 3); if (grub_errno != GRUB_ERR_NONE) return; term_initialized = 1; - /* XXX: store static pointer to the 'view' object so the repaint callback can access it. */ + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + grub_gfxmenu_view_draw (view); + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + term_view = view; - grub_gfxterm_set_repaint_callback (repaint_terminal); + grub_term_set_current_output (grub_gfxterm_get_term ()); } static void destroy_terminal (void) { - term_view = 0; if (term_initialized) grub_gfxterm_destroy_window (); - grub_gfxterm_set_repaint_callback (0); - if (term_target) - grub_video_delete_render_target (term_target); if (term_original) grub_term_set_current_output (term_original); } @@ -493,5 +491,6 @@ grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view, void grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view __attribute__((unused))) { + draw_terminal_box (); grub_cmdline_run (1); } From 4545f150f38e536b38d54f2a578671f578918fcf Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 24 Nov 2009 05:02:30 +0100 Subject: [PATCH 27/67] Various cleanups --- gfxmenu/gfxmenu.c | 113 +++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 51 deletions(-) diff --git a/gfxmenu/gfxmenu.c b/gfxmenu/gfxmenu.c index c854c68da..6f7382c18 100644 --- a/gfxmenu/gfxmenu.c +++ b/gfxmenu/gfxmenu.c @@ -51,50 +51,63 @@ process_key_press (int c, /* When a key is pressed, stop the timeout. */ grub_gfxmenu_model_clear_timeout (model); - if (c == 'j' || c == GRUB_TERM_DOWN) - { - int i = grub_gfxmenu_model_get_selected_index (model); - int num_items = grub_gfxmenu_model_get_num_entries (model); - if (i < num_items - 1) - { - i++; - grub_gfxmenu_model_set_selected_index (model, i); - } - } - else if (c == 'k' || c == GRUB_TERM_UP) - { - int i = grub_gfxmenu_model_get_selected_index (model); - if (i > 0) - { - i--; - grub_gfxmenu_model_set_selected_index (model, i); - } - } - else if (c == '\r' || c == '\n' || c == GRUB_TERM_RIGHT) - { - int selected = grub_gfxmenu_model_get_selected_index (model); - int num_entries = grub_gfxmenu_model_get_num_entries (model); - if (selected >= 0 && selected < num_entries) - { - grub_menu_entry_t entry = - grub_gfxmenu_model_get_entry (model, selected); - grub_gfxmenu_view_execute_entry (view, entry); - } - } - else if (c == 'c') + switch (c) { + case 'j': + case GRUB_TERM_DOWN: + { + int i = grub_gfxmenu_model_get_selected_index (model); + int num_items = grub_gfxmenu_model_get_num_entries (model); + if (i < num_items - 1) + { + i++; + grub_gfxmenu_model_set_selected_index (model, i); + } + } + break; + + case 'k': + case GRUB_TERM_UP: + { + int i = grub_gfxmenu_model_get_selected_index (model); + if (i > 0) + { + i--; + grub_gfxmenu_model_set_selected_index (model, i); + } + } + break; + + case '\r': + case '\n': + case GRUB_TERM_RIGHT: + { + int selected = grub_gfxmenu_model_get_selected_index (model); + int num_entries = grub_gfxmenu_model_get_num_entries (model); + if (selected >= 0 && selected < num_entries) + { + grub_menu_entry_t entry = + grub_gfxmenu_model_get_entry (model, selected); + grub_gfxmenu_view_execute_entry (view, entry); + } + } + break; + + case 'c': grub_gfxmenu_view_run_terminal (view); - } - else if (c == 't') - { + break; + + case 't': /* The write hook for 'menuviewer' will cause * grub_menu_viewer_should_return to return nonzero. */ switch_to_text_menu (); *should_exit = 1; - } - else if (nested && c == GRUB_TERM_ESC) - { - *should_exit = 1; + break; + + case GRUB_TERM_ESC: + if (nested) + *should_exit = 1; + break; } if (grub_errno != GRUB_ERR_NONE) @@ -119,32 +132,29 @@ static grub_err_t show_menu (grub_menu_t menu, int nested) { grub_gfxmenu_model_t model; + grub_gfxmenu_view_t view; + const char *theme_path; + + theme_path = grub_env_get ("theme"); + if (! theme_path) + { + switch_to_text_menu (); + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no theme specified"); + } model = grub_gfxmenu_model_new (menu); if (! model) { - grub_print_error (); - grub_printf ("Initializing menu data for graphical menu failed;\n" - "falling back to text based menu.\n"); - grub_wait_after_message (); switch_to_text_menu (); return grub_errno; } - grub_gfxmenu_view_t view; - /* Create the view. */ - const char *theme_path = grub_env_get ("theme"); - if (! theme_path) - theme_path = "/boot/grub/themes/proto/theme.txt"; - view = grub_gfxmenu_view_new (theme_path, model); + if (! view) { grub_print_error (); - grub_printf ("Starting graphical menu failed;\n" - "falling back to text based menu.\n"); - grub_wait_after_message (); grub_gfxmenu_model_destroy (model); switch_to_text_menu (); return grub_errno; @@ -159,6 +169,7 @@ show_menu (grub_menu_t menu, int nested) /* Main event loop. */ int exit_requested = 0; + while ((! exit_requested) && (! grub_menu_viewer_should_return ())) { if (grub_gfxmenu_model_timeout_expired (model)) From 947fa16c8b8bf6a0f91ca7b01da8c47f8cc9361c Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 24 Nov 2009 07:17:18 +0100 Subject: [PATCH 28/67] Important speedup by not redrawing too much --- gfxmenu/gfxmenu.c | 12 +- gfxmenu/gui_box.c | 4 +- gfxmenu/gui_canvas.c | 5 +- gfxmenu/gui_circular_progress.c | 6 +- gfxmenu/gui_image.c | 8 +- gfxmenu/gui_label.c | 5 +- gfxmenu/gui_list.c | 6 +- gfxmenu/gui_progress_bar.c | 4 +- gfxmenu/view.c | 214 +++++++++++++++++++++++--------- include/grub/gfxmenu_view.h | 14 +++ include/grub/gui.h | 16 ++- 11 files changed, 221 insertions(+), 73 deletions(-) diff --git a/gfxmenu/gfxmenu.c b/gfxmenu/gfxmenu.c index 6f7382c18..ab1c8befb 100644 --- a/gfxmenu/gfxmenu.c +++ b/gfxmenu/gfxmenu.c @@ -35,6 +35,7 @@ #include #include #include +#include static void switch_to_text_menu (void) { @@ -62,6 +63,7 @@ process_key_press (int c, { i++; grub_gfxmenu_model_set_selected_index (model, i); + grub_gfxmenu_redraw_menu (view); } } break; @@ -74,6 +76,7 @@ process_key_press (int c, { i--; grub_gfxmenu_model_set_selected_index (model, i); + grub_gfxmenu_redraw_menu (view); } } break; @@ -170,8 +173,14 @@ show_menu (grub_menu_t menu, int nested) /* Main event loop. */ int exit_requested = 0; + grub_gfxmenu_view_draw (view); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_gfxmenu_view_draw (view); + while ((! exit_requested) && (! grub_menu_viewer_should_return ())) { + grub_gfxmenu_redraw_timeout (view); if (grub_gfxmenu_model_timeout_expired (model)) { grub_gfxmenu_model_clear_timeout (model); @@ -181,9 +190,8 @@ show_menu (grub_menu_t menu, int nested) continue; } - grub_gfxmenu_view_draw (view); - grub_video_swap_buffers (); handle_key_events (model, view, nested, &exit_requested); + grub_cpu_idle (); } grub_gfxmenu_view_destroy (view); diff --git a/gfxmenu/gui_box.c b/gfxmenu/gui_box.c index 876d0733f..4fe131f98 100644 --- a/gfxmenu/gui_box.c +++ b/gfxmenu/gui_box.c @@ -166,7 +166,7 @@ layout_vertically (grub_gui_box_t self, int modify_layout, } static void -box_paint (void *vself) +box_paint (void *vself, const grub_video_rect_t *region) { grub_gui_box_t self = vself; struct component_node *cur; @@ -176,7 +176,7 @@ box_paint (void *vself) for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) { grub_gui_component_t comp = cur->component; - comp->ops->paint (comp); + comp->ops->paint (comp, region); } grub_gui_restore_viewport (&vpsave); } diff --git a/gfxmenu/gui_canvas.c b/gfxmenu/gui_canvas.c index a2cd77df6..d155364d7 100644 --- a/gfxmenu/gui_canvas.c +++ b/gfxmenu/gui_canvas.c @@ -79,7 +79,7 @@ canvas_is_instance (void *vself __attribute__((unused)), const char *type) } static void -canvas_paint (void *vself) +canvas_paint (void *vself, const grub_video_rect_t *region) { grub_gui_canvas_t self = vself; struct component_node *cur; @@ -106,7 +106,8 @@ canvas_paint (void *vself) } /* Paint the child. */ - comp->ops->paint (comp); + if (grub_video_have_common_points (region, &r)) + comp->ops->paint (comp, region); } grub_gui_restore_viewport (&vpsave); } diff --git a/gfxmenu/gui_circular_progress.c b/gfxmenu/gui_circular_progress.c index cd95c51f9..f3c8bc3af 100644 --- a/gfxmenu/gui_circular_progress.c +++ b/gfxmenu/gui_circular_progress.c @@ -112,12 +112,16 @@ check_pixmaps (circular_progress_t self) } static void -circprog_paint (void *vself) +circprog_paint (void *vself, const grub_video_rect_t *region) { circular_progress_t self = vself; if (! self->visible) return; + + if (!grub_video_have_common_points (region, &self->bounds)) + return; + if (! check_pixmaps (self)) return; diff --git a/gfxmenu/gui_image.c b/gfxmenu/gui_image.c index 1c58a535b..eb2ff1ee0 100644 --- a/gfxmenu/gui_image.c +++ b/gfxmenu/gui_image.c @@ -67,12 +67,16 @@ image_is_instance (void *vself __attribute__((unused)), const char *type) } static void -image_paint (void *vself) +image_paint (void *vself, const grub_video_rect_t *region) { grub_gui_image_t self = vself; + grub_video_rect_t vpsave; + if (! self->bitmap) return; - grub_video_rect_t vpsave; + if (!grub_video_have_common_points (region, &self->bounds)) + return; + grub_gui_set_viewport (&self->bounds, &vpsave); grub_video_blit_bitmap (self->bitmap, GRUB_VIDEO_BLIT_BLEND, 0, 0, 0, 0, diff --git a/gfxmenu/gui_label.c b/gfxmenu/gui_label.c index eb2a495ff..30474f52f 100644 --- a/gfxmenu/gui_label.c +++ b/gfxmenu/gui_label.c @@ -77,13 +77,16 @@ label_is_instance (void *vself __attribute__((unused)), const char *type) } static void -label_paint (void *vself) +label_paint (void *vself, const grub_video_rect_t *region) { grub_gui_label_t self = vself; if (! self->visible) return; + if (!grub_video_have_common_points (region, &self->bounds)) + return; + /* Calculate the starting x coordinate. */ int left_x; if (self->align == align_left) diff --git a/gfxmenu/gui_list.c b/gfxmenu/gui_list.c index aa9655b45..bf6d94657 100644 --- a/gfxmenu/gui_list.c +++ b/gfxmenu/gui_list.c @@ -311,16 +311,18 @@ draw_menu (list_impl_t self) } static void -list_paint (void *vself) +list_paint (void *vself, const grub_video_rect_t *region) { list_impl_t self = vself; + grub_video_rect_t vpsave; if (! self->visible) return; + if (!grub_video_have_common_points (region, &self->bounds)) + return; check_boxes (self); - grub_video_rect_t vpsave; grub_gui_set_viewport (&self->bounds, &vpsave); draw_menu (self); grub_gui_restore_viewport (&vpsave); diff --git a/gfxmenu/gui_progress_bar.c b/gfxmenu/gui_progress_bar.c index 440d4b2fc..498711169 100644 --- a/gfxmenu/gui_progress_bar.c +++ b/gfxmenu/gui_progress_bar.c @@ -171,11 +171,13 @@ draw_text (grub_gui_progress_bar_t self) } static void -progress_bar_paint (void *vself) +progress_bar_paint (void *vself, const grub_video_rect_t *region) { grub_gui_progress_bar_t self = vself; if (! self->visible) return; + if (!grub_video_have_common_points (region, &self->bounds)) + return; grub_video_rect_t vpsave; grub_gui_set_viewport (&self->bounds, &vpsave); diff --git a/gfxmenu/view.c b/gfxmenu/view.c index e807d3838..1c512fee1 100644 --- a/gfxmenu/view.c +++ b/gfxmenu/view.c @@ -55,6 +55,8 @@ grub_gfxmenu_view_t grub_gfxmenu_view_new (const char *theme_path, grub_gfxmenu_model_t model) { grub_gfxmenu_view_t view; + grub_err_t err; + struct grub_video_mode_info mode_info; view = grub_malloc (sizeof (*view)); if (! view) @@ -67,6 +69,18 @@ grub_gfxmenu_view_new (const char *theme_path, grub_gfxmenu_model_t model) (unsigned *) &view->screen.width, (unsigned *) &view->screen.height); + err = grub_video_get_info (&mode_info); + if (err) + { + grub_free (view); + return 0; + } + else + view->double_repaint = (mode_info.mode_type + & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED) + && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); + + /* Clear the screen; there may be garbage left over in video memory, and loading the menu style (particularly the background) can take a while. */ grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), @@ -97,6 +111,15 @@ grub_gfxmenu_view_new (const char *theme_path, grub_gfxmenu_model_t model) view->title_text = grub_strdup ("GRUB Boot Menu"); view->progress_message_text = 0; view->theme_path = 0; + view->last_seconds_remaining = -2; + + /* Set the timeout bar's frame. */ + view->progress_message_frame.width = view->screen.width * 4 / 5; + view->progress_message_frame.height = 50; + view->progress_message_frame.x = view->screen.x + + (view->screen.width - view->progress_message_frame.width) / 2; + view->progress_message_frame.y = view->screen.y + + view->screen.height - 90 - 20 - view->progress_message_frame.height; if (grub_gfxmenu_view_load_theme (view, theme_path) != 0) { @@ -141,21 +164,23 @@ set_progress_message (grub_gfxmenu_view_t view, const char *message) } static void -draw_background (grub_gfxmenu_view_t view) +redraw_background (grub_gfxmenu_view_t view, + const grub_video_rect_t *bounds) { if (view->desktop_image) { struct grub_video_bitmap *img = view->desktop_image; grub_video_blit_bitmap (img, GRUB_VIDEO_BLIT_REPLACE, - view->screen.x, view->screen.y, 0, 0, - grub_video_bitmap_get_width (img), - grub_video_bitmap_get_height (img)); + bounds->x, bounds->y, + bounds->x - view->screen.x, + bounds->y - view->screen.y, + bounds->width, bounds->height); } else { grub_video_fill_rect (grub_gui_map_color (view->desktop_color), - view->screen.x, view->screen.y, - view->screen.width, view->screen.height); + bounds->x, bounds->y, + bounds->width, bounds->height); } } @@ -191,6 +216,7 @@ update_timeout_visit (grub_gui_component_t component, { struct progress_value_data *pv; pv = (struct progress_value_data *) userdata; + component->ops->set_property (component, "visible", pv->visible); component->ops->set_property (component, "start", pv->start); component->ops->set_property (component, "end", pv->end); @@ -198,16 +224,43 @@ update_timeout_visit (grub_gui_component_t component, component->ops->set_property (component, "text", pv->text); } -static void -update_timeout (grub_gfxmenu_view_t view) + +static inline void +update_timeout (grub_gfxmenu_view_t view, int is_init) { char startbuf[20]; char valuebuf[20]; char msgbuf[120]; - int timeout = grub_gfxmenu_model_get_timeout_ms (view->model); - int remaining = grub_gfxmenu_model_get_timeout_remaining_ms (view->model); + int timeout; + int remaining; struct progress_value_data pv; + int seconds_remaining_rounded_up; + + auto void redraw_timeout_visit (grub_gui_component_t component, + void *userdata __attribute__ ((unused))); + + auto void redraw_timeout_visit (grub_gui_component_t component, + void *userdata __attribute__ ((unused))) + { + grub_video_rect_t bounds; + component->ops->get_bounds (component, &bounds); + grub_gfxmenu_view_redraw (view, &bounds); + } + + timeout = grub_gfxmenu_model_get_timeout_ms (view->model); + if (timeout > 0) + { + remaining = grub_gfxmenu_model_get_timeout_remaining_ms (view->model); + seconds_remaining_rounded_up = (remaining + 999) / 1000; + } + else + seconds_remaining_rounded_up = -1; + + if (view->last_seconds_remaining == seconds_remaining_rounded_up && !is_init) + return; + + view->last_seconds_remaining = seconds_remaining_rounded_up; pv.visible = timeout > 0 ? "true" : "false"; grub_sprintf (startbuf, "%d", -timeout); @@ -216,7 +269,6 @@ update_timeout (grub_gfxmenu_view_t view) grub_sprintf (valuebuf, "%d", remaining > 0 ? -remaining : 0); pv.value = valuebuf; - int seconds_remaining_rounded_up = (remaining + 999) / 1000; grub_sprintf (msgbuf, "The highlighted entry will be booted automatically in %d s.", seconds_remaining_rounded_up); @@ -224,6 +276,21 @@ update_timeout (grub_gfxmenu_view_t view) grub_gui_find_by_id ((grub_gui_component_t) view->canvas, TIMEOUT_COMPONENT_ID, update_timeout_visit, &pv); + if (!is_init) + { + grub_gui_find_by_id ((grub_gui_component_t) view->canvas, + TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_gui_find_by_id ((grub_gui_component_t) view->canvas, + TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv); + } +} + +void +grub_gfxmenu_redraw_timeout (grub_gfxmenu_view_t view) +{ + update_timeout (view, 0); } static void @@ -252,19 +319,13 @@ static void draw_message (grub_gfxmenu_view_t view) { char *text = view->progress_message_text; + grub_video_rect_t f = view->progress_message_frame; if (! text) return; grub_font_t font = view->message_font; grub_video_color_t color = grub_gui_map_color (view->message_color); - /* Set the timeout bar's frame. */ - grub_video_rect_t f; - f.width = view->screen.width * 4 / 5; - f.height = 50; - f.x = view->screen.x + (view->screen.width - f.width) / 2; - f.y = view->screen.y + view->screen.height - 90 - 20 - f.height; - /* Border. */ grub_video_fill_rect (color, f.x-1, f.y-1, f.width+2, f.height+2); @@ -280,19 +341,62 @@ draw_message (grub_gfxmenu_view_t view) grub_font_draw_string (text, font, color, x, y); } +void +grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, + const grub_video_rect_t *region) +{ + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + + redraw_background (view, region); + if (view->canvas) + view->canvas->ops->component.paint (view->canvas, region); + draw_title (view); + if (grub_video_have_common_points (&view->progress_message_frame, region)) + draw_message (view); +} void grub_gfxmenu_view_draw (grub_gfxmenu_view_t view) { - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); - update_timeout (view); + update_timeout (view, 1); update_menu_components (view); - draw_background (view); - if (view->canvas) - view->canvas->ops->component.paint (view->canvas); - draw_title (view); - draw_message (view); + grub_gfxmenu_view_redraw (view, &view->screen); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_gfxmenu_view_redraw (view, &view->screen); +} + +static void +redraw_menu_visit (grub_gui_component_t component, + void *userdata) +{ + grub_gfxmenu_view_t view; + view = userdata; + if (component->ops->is_instance (component, "list")) + { + grub_gui_list_t list; + grub_video_rect_t bounds; + + list = (grub_gui_list_t) component; + component->ops->get_bounds (component, &bounds); + grub_gfxmenu_view_redraw (view, &bounds); + } +} + +void +grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view) +{ + update_menu_components (view); + + grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, + redraw_menu_visit, view); + grub_video_swap_buffers (); + if (view->double_repaint) + { + grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, + redraw_menu_visit, view); + } } static grub_err_t @@ -316,7 +420,7 @@ static int term_initialized; static grub_term_output_t term_original; static void -draw_terminal_box (void) +draw_terminal_box (grub_gfxmenu_view_t view) { grub_gfxmenu_box_t term_box; int termx; @@ -335,6 +439,11 @@ draw_terminal_box (void) term_box->draw (term_box, termx - term_box->get_left_pad (term_box), termy - term_box->get_top_pad (term_box)); + grub_video_swap_buffers (); + if (view->double_repaint) + term_box->draw (term_box, + termx - term_box->get_left_pad (term_box), + termy - term_box->get_top_pad (term_box)); } static void @@ -342,9 +451,6 @@ init_terminal (grub_gfxmenu_view_t view) { int termx; int termy; - struct grub_video_mode_info mode_info; - grub_err_t err; - int double_repaint; term_original = grub_term_get_current_output (); @@ -354,34 +460,20 @@ init_terminal (grub_gfxmenu_view_t view) termx = view->screen.x + view->screen.width * (10 - 7) / 10 / 2; termy = view->screen.y + view->screen.height * (10 - 7) / 10 / 2; - err = grub_video_get_info (&mode_info); - if (err) - { - grub_errno = GRUB_ERR_NONE; - double_repaint = 1; - } - else - double_repaint = (mode_info.mode_type - & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED) - && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); - /* Note: currently there is no API for changing the gfxterm font on the fly, so whatever font the initially loaded theme specifies will be permanent. */ grub_gfxterm_init_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, termx, termy, term_target_width, term_target_height, - double_repaint, view->terminal_font_name, 3); + view->double_repaint, view->terminal_font_name, 3); if (grub_errno != GRUB_ERR_NONE) return; term_initialized = 1; - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); - grub_gfxmenu_view_draw (view); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); - term_view = view; grub_term_set_current_output (grub_gfxterm_get_term ()); + grub_refresh (); } static void destroy_terminal (void) @@ -405,8 +497,10 @@ notify_booting (grub_menu_entry_t entry, void *userdata) grub_sprintf (s, "Booting '%s'", entry->title); set_progress_message (view, s); grub_free (s); - grub_gfxmenu_view_draw (view); + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); grub_video_swap_buffers (); + if (view->double_repaint) + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); } static void @@ -421,8 +515,10 @@ notify_fallback (grub_menu_entry_t entry, void *userdata) grub_sprintf (s, "Falling back to '%s'", entry->title); set_progress_message (view, s); grub_free (s); - grub_gfxmenu_view_draw (view); + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); grub_video_swap_buffers (); + if (view->double_repaint) + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); } static void @@ -442,6 +538,8 @@ int grub_gfxmenu_view_execute_with_fallback (grub_gfxmenu_view_t view, grub_menu_entry_t entry) { + draw_terminal_box (view); + grub_menu_execute_with_fallback (grub_gfxmenu_model_get_menu (view->model), entry, &execute_callback, (void *) view); @@ -453,7 +551,6 @@ grub_gfxmenu_view_execute_with_fallback (grub_gfxmenu_view_t view, "Unable to automatically boot. " "Press SPACE to continue."); grub_gfxmenu_view_draw (view); - grub_video_swap_buffers (); while (GRUB_TERM_ASCII_CHAR(grub_getkey ()) != ' ') { /* Wait for SPACE to be pressed. */ @@ -461,6 +558,11 @@ grub_gfxmenu_view_execute_with_fallback (grub_gfxmenu_view_t view, set_progress_message (view, 0); /* Clear the message. */ + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); + return 1; /* Ok. */ } @@ -468,14 +570,7 @@ int grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view, grub_menu_entry_t entry) { - /* Currently we switch back to text mode by restoring - the original terminal before executing the menu entry. - It is hard to make it work when executing a menu entry - that switches video modes -- it using gfxterm in a - window, the repaint callback seems to crash GRUB. */ - /* TODO: Determine if this works when 'gfxterm' was set as - the current terminal before invoking the gfxmenu. */ - destroy_terminal (); + draw_terminal_box (view); grub_menu_execute_entry (entry); if (grub_errno != GRUB_ERR_NONE) @@ -484,13 +579,14 @@ grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view, if (set_graphics_mode () != GRUB_ERR_NONE) return 0; /* Failure. */ - init_terminal (view); + grub_gfxmenu_view_draw (view); return 1; /* Ok. */ } void -grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view __attribute__((unused))) +grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view) { - draw_terminal_box (); + draw_terminal_box (view); grub_cmdline_run (1); + grub_gfxmenu_view_draw (view); } diff --git a/include/grub/gfxmenu_view.h b/include/grub/gfxmenu_view.h index 1144382f2..c86334400 100644 --- a/include/grub/gfxmenu_view.h +++ b/include/grub/gfxmenu_view.h @@ -54,7 +54,15 @@ int grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view, void grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view); +void +grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view); +void +grub_gfxmenu_redraw_timeout (grub_gfxmenu_view_t view); + +void +grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, + const grub_video_rect_t *region); /* Implementation details -- this should not be used outside of the view itself. */ @@ -86,6 +94,12 @@ struct grub_gfxmenu_view grub_gui_container_t canvas; grub_gfxmenu_model_t model; + + int last_seconds_remaining; + + int double_repaint; + + grub_video_rect_t progress_message_frame; }; #endif /* ! GRUB_GFXMENU_VIEW_HEADER */ diff --git a/include/grub/gui.h b/include/grub/gui.h index 5b785dbb5..385c0962b 100644 --- a/include/grub/gui.h +++ b/include/grub/gui.h @@ -50,13 +50,14 @@ struct grub_gui_component_ops void (*destroy) (void *self); const char * (*get_id) (void *self); int (*is_instance) (void *self, const char *type); - void (*paint) (void *self); + void (*paint) (void *self, const grub_video_rect_t *bounds); void (*set_parent) (void *self, grub_gui_container_t parent); grub_gui_container_t (*get_parent) (void *self); void (*set_bounds) (void *self, const grub_video_rect_t *bounds); void (*get_bounds) (void *self, grub_video_rect_t *bounds); void (*get_preferred_size) (void *self, int *width, int *height); grub_err_t (*set_property) (void *self, const char *name, const char *value); + void (*repaint) (void *self, int second_pass); }; struct grub_gui_container_ops @@ -162,4 +163,17 @@ grub_gui_map_color (grub_gui_color_t c) return grub_video_map_rgba (c.red, c.green, c.blue, c.alpha); } +static inline int +grub_video_have_common_points (const grub_video_rect_t *a, + const grub_video_rect_t *b) +{ + if (!((a->x <= b->x && b->x <= a->x + a->width) + || (b->x <= a->x && a->x <= b->x + b->width))) + return 0; + if (!((a->y <= b->y && b->y <= a->y + a->height) + || (b->y <= a->y && a->y <= b->y + b->height))) + return 0; + return 1; +} + #endif /* ! GRUB_GUI_H */ From f788bf3cd4a3ae22d25d305f42652651ccc962f5 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Thu, 26 Nov 2009 23:54:26 +0000 Subject: [PATCH 29/67] Add (unused) mode_mask parameter (implicitly documented in ChangeLog.videomask) --- video/efi_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video/efi_fb.c b/video/efi_fb.c index 2faff12f9..a4a9950b1 100644 --- a/video/efi_fb.c +++ b/video/efi_fb.c @@ -197,7 +197,7 @@ grub_video_efi_fini (void) static grub_err_t grub_video_efi_setup (unsigned int width, unsigned int height, - unsigned int mode_type) + unsigned int mode_type, unsigned int mode_mask __attribute__ ((unused))) { unsigned int depth; int found = 0; From 2fac00e6687eb0b55e7102c2d6c64a389084bc77 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 27 Nov 2009 10:20:24 +0100 Subject: [PATCH 30/67] Fixed a warning --- gfxmenu/view.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gfxmenu/view.c b/gfxmenu/view.c index 1c512fee1..7d9bb1cd0 100644 --- a/gfxmenu/view.c +++ b/gfxmenu/view.c @@ -255,7 +255,10 @@ update_timeout (grub_gfxmenu_view_t view, int is_init) seconds_remaining_rounded_up = (remaining + 999) / 1000; } else - seconds_remaining_rounded_up = -1; + { + seconds_remaining_rounded_up = -1; + remaining = -1; + } if (view->last_seconds_remaining == seconds_remaining_rounded_up && !is_init) return; From af20edb21d83d413e9721948f71e8ca2035e7d1b Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 30 Nov 2009 12:51:20 +0100 Subject: [PATCH 31/67] 2009-11-30 Vladimir Serbinenko Agglomerate scrolling in gfxterm. * term/gfxterm.c (grub_virtual_screen): New member 'total_screen'. (grub_virtual_screen_setup): Initialise 'total_screen'. (write_char): Split to ... (paint_char): ... this ... (write_char): ... and this. (paint_char): Handle delayed scrolling. (draw_cursor): Likewise. (scroll_up): Split to ... (real_scroll): ... this ... (scroll_up): ... and this. (real_scroll): Handle multi-line scroll and draw below-the-bottom characters. (grub_gfxterm_refresh): Call real_scroll. --- term/gfxterm.c | 157 ++++++++++++++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 59 deletions(-) diff --git a/term/gfxterm.c b/term/gfxterm.c index 5330c4ac4..be0487830 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -102,6 +102,8 @@ struct grub_virtual_screen /* Text buffer for virtual screen. Contains (columns * rows) number of entries. */ struct grub_colored_char *text_buffer; + + int total_scroll; }; struct grub_gfxterm_window @@ -225,6 +227,7 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, virtual_screen.cursor_x = 0; virtual_screen.cursor_y = 0; virtual_screen.cursor_state = 1; + virtual_screen.total_scroll = 0; /* Calculate size of text buffer. */ virtual_screen.columns = virtual_screen.width / virtual_screen.normal_char_width; @@ -586,8 +589,8 @@ dirty_region_redraw (void) redraw_screen_rect (x, y, width, height); } -static void -write_char (void) +static inline void +paint_char (unsigned cx, unsigned cy) { struct grub_colored_char *p; struct grub_font_glyph *glyph; @@ -599,10 +602,12 @@ write_char (void) unsigned int height; unsigned int width; + if (cy + virtual_screen.total_scroll >= virtual_screen.rows) + return; + /* Find out active character. */ p = (virtual_screen.text_buffer - + virtual_screen.cursor_x - + (virtual_screen.cursor_y * virtual_screen.columns)); + + cx + (cy * virtual_screen.columns)); p -= p->index; @@ -616,8 +621,8 @@ write_char (void) color = p->fg_color; bgcolor = p->bg_color; - x = virtual_screen.cursor_x * virtual_screen.normal_char_width; - y = virtual_screen.cursor_y * virtual_screen.normal_char_height; + x = cx * virtual_screen.normal_char_width; + y = (cy + virtual_screen.total_scroll) * virtual_screen.normal_char_height; /* Render glyph to text layer. */ grub_video_set_active_render_target (text_layer); @@ -630,64 +635,58 @@ write_char (void) width, height); } -static void +static inline void +write_char (void) +{ + paint_char (virtual_screen.cursor_x, virtual_screen.cursor_y); +} + +static inline void draw_cursor (int show) { + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + grub_video_color_t color; + write_char (); - if (show) - { - unsigned int x; - unsigned int y; - unsigned int width; - unsigned int height; - grub_video_color_t color; + if (!show) + return; - /* Determine cursor properties and position on text layer. */ - x = virtual_screen.cursor_x * virtual_screen.normal_char_width; - width = virtual_screen.normal_char_width; - color = virtual_screen.fg_color; - y = (virtual_screen.cursor_y * virtual_screen.normal_char_height - + grub_font_get_ascent (virtual_screen.font)); - height = 2; + if (virtual_screen.cursor_y + virtual_screen.total_scroll + >= virtual_screen.rows) + return; - /* Render cursor to text layer. */ - grub_video_set_active_render_target (text_layer); - grub_video_fill_rect (color, x, y, width, height); - grub_video_set_active_render_target (render_target); - - /* Mark cursor to be redrawn. */ - dirty_region_add (virtual_screen.offset_x + x, - virtual_screen.offset_y + y, - width, height); - } + /* Determine cursor properties and position on text layer. */ + x = virtual_screen.cursor_x * virtual_screen.normal_char_width; + width = virtual_screen.normal_char_width; + color = virtual_screen.fg_color; + y = ((virtual_screen.cursor_y + virtual_screen.total_scroll) + * virtual_screen.normal_char_height + + grub_font_get_ascent (virtual_screen.font)); + height = 2; + + /* Render cursor to text layer. */ + grub_video_set_active_render_target (text_layer); + grub_video_fill_rect (color, x, y, width, height); + grub_video_set_active_render_target (render_target); + + /* Mark cursor to be redrawn. */ + dirty_region_add (virtual_screen.offset_x + x, + virtual_screen.offset_y + y, + width, height); } static void -scroll_up (void) +real_scroll (void) { - unsigned int i; + unsigned int i, j, was_scroll; grub_video_color_t color; - /* If we don't have background bitmap, remove cursor. */ - if (!bitmap) - { - /* Remove cursor. */ - draw_cursor (0); - } - - /* Scroll text buffer with one line to up. */ - grub_memmove (virtual_screen.text_buffer, - virtual_screen.text_buffer + virtual_screen.columns, - sizeof (*virtual_screen.text_buffer) - * virtual_screen.columns - * (virtual_screen.rows - 1)); - - /* Clear last line in text buffer. */ - for (i = virtual_screen.columns * (virtual_screen.rows - 1); - i < virtual_screen.columns * virtual_screen.rows; - i++) - clear_char (&(virtual_screen.text_buffer[i])); + if (!virtual_screen.total_scroll) + return; /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */ if (bitmap) @@ -695,7 +694,8 @@ scroll_up (void) /* Scroll physical screen. */ grub_video_set_active_render_target (text_layer); color = virtual_screen.bg_color; - grub_video_scroll (color, 0, -virtual_screen.normal_char_height); + grub_video_scroll (color, 0, -virtual_screen.normal_char_height + * virtual_screen.total_scroll); /* Mark virtual screen to be redrawn. */ dirty_region_add_virtualscreen (); @@ -704,6 +704,9 @@ scroll_up (void) { grub_video_rect_t saved_view; + /* Remove cursor. */ + draw_cursor (0); + grub_video_set_active_render_target (render_target); /* Save viewport and set it to our window. */ grub_video_get_viewport ((unsigned *) &saved_view.x, @@ -723,13 +726,15 @@ scroll_up (void) virtual_screen.offset_x, virtual_screen.offset_y, virtual_screen.width, - virtual_screen.normal_char_height); + virtual_screen.normal_char_height + * virtual_screen.total_scroll); grub_video_set_active_render_target (render_target); dirty_region_redraw (); /* Scroll physical screen. */ - grub_video_scroll (color, 0, -virtual_screen.normal_char_height); + grub_video_scroll (color, 0, -virtual_screen.normal_char_height + * virtual_screen.total_scroll); if (i) grub_video_swap_buffers (); @@ -739,22 +744,54 @@ scroll_up (void) /* Scroll physical screen. */ grub_video_set_active_render_target (text_layer); color = virtual_screen.bg_color; - grub_video_scroll (color, 0, -virtual_screen.normal_char_height); + grub_video_scroll (color, 0, -virtual_screen.normal_char_height + * virtual_screen.total_scroll); /* Restore saved viewport. */ grub_video_set_viewport (saved_view.x, saved_view.y, saved_view.width, saved_view.height); grub_video_set_active_render_target (render_target); - /* Draw cursor if visible. */ - if (virtual_screen.cursor_state) - draw_cursor (1); } + /* Draw cursor if visible. */ + if (virtual_screen.cursor_state) + draw_cursor (1); + + was_scroll = virtual_screen.total_scroll; + virtual_screen.total_scroll = 0; + + /* Draw shadow part. */ + for (i = virtual_screen.rows - was_scroll; + i < virtual_screen.rows; i++) + for (j = 0; j < virtual_screen.columns; j++) + paint_char (j, i); + if (repaint_callback) repaint_callback (window.x, window.y, window.width, window.height); } +static void +scroll_up (void) +{ + unsigned int i; + + /* Scroll text buffer with one line to up. */ + grub_memmove (virtual_screen.text_buffer, + virtual_screen.text_buffer + virtual_screen.columns, + sizeof (*virtual_screen.text_buffer) + * virtual_screen.columns + * (virtual_screen.rows - 1)); + + /* Clear last line in text buffer. */ + for (i = virtual_screen.columns * (virtual_screen.rows - 1); + i < virtual_screen.columns * virtual_screen.rows; + i++) + clear_char (&(virtual_screen.text_buffer[i])); + + virtual_screen.total_scroll++; +} + static void grub_gfxterm_putchar (grub_uint32_t c) { @@ -1023,6 +1060,8 @@ grub_gfxterm_setcursor (int on) static void grub_gfxterm_refresh (void) { + real_scroll (); + /* Redraw only changed regions. */ dirty_region_redraw (); From e59e3e59caa3d3f7dbe54812f7b97964f03aa3aa Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 30 Nov 2009 12:52:39 +0100 Subject: [PATCH 32/67] Changelog --- ChangeLog.gfxtermscroll | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 ChangeLog.gfxtermscroll diff --git a/ChangeLog.gfxtermscroll b/ChangeLog.gfxtermscroll new file mode 100644 index 000000000..b0733116f --- /dev/null +++ b/ChangeLog.gfxtermscroll @@ -0,0 +1,18 @@ +2009-11-30 Vladimir Serbinenko + + Agglomerate scrolling in gfxterm. + + * term/gfxterm.c (grub_virtual_screen): New member 'total_screen'. + (grub_virtual_screen_setup): Initialise 'total_screen'. + (write_char): Split to ... + (paint_char): ... this ... + (write_char): ... and this. + (paint_char): Handle delayed scrolling. + (draw_cursor): Likewise. + (scroll_up): Split to ... + (real_scroll): ... this ... + (scroll_up): ... and this. + (real_scroll): Handle multi-line scroll and draw below-the-bottom + characters. + (grub_gfxterm_refresh): Call real_scroll. + From f505738643d0c580026f63d28777eb5bef8ff4da Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 2 Dec 2009 14:42:28 +0100 Subject: [PATCH 33/67] Fix warning --- gfxmenu/gui_string_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gfxmenu/gui_string_util.c b/gfxmenu/gui_string_util.c index 31b2f0aca..8ea7c497b 100644 --- a/gfxmenu/gui_string_util.c +++ b/gfxmenu/gui_string_util.c @@ -206,7 +206,7 @@ grub_get_dirname (const char *file_path) } static __inline int -isxdigit (char c) +my_isxdigit (char c) { return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') @@ -261,7 +261,7 @@ grub_gui_parse_color (const char *s, grub_gui_color_t *color) /* Count the hexits to determine the format. */ int hexits = 0; const char *end = s; - while (isxdigit (*end)) + while (my_isxdigit (*end)) { end++; hexits++; From 17d1956f5c5bab387f544bdffa0c9041ae8d80c6 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 2 Dec 2009 21:03:41 +0100 Subject: [PATCH 34/67] Fix cursor drawing and whole screen scrolling --- term/gfxterm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/term/gfxterm.c b/term/gfxterm.c index be0487830..eb2c47c3d 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -754,19 +754,22 @@ real_scroll (void) } - /* Draw cursor if visible. */ - if (virtual_screen.cursor_state) - draw_cursor (1); - was_scroll = virtual_screen.total_scroll; virtual_screen.total_scroll = 0; + if (was_scroll > virtual_screen.rows) + was_scroll = virtual_screen.rows; + /* Draw shadow part. */ for (i = virtual_screen.rows - was_scroll; i < virtual_screen.rows; i++) for (j = 0; j < virtual_screen.columns; j++) paint_char (j, i); + /* Draw cursor if visible. */ + if (virtual_screen.cursor_state) + draw_cursor (1); + if (repaint_callback) repaint_callback (window.x, window.y, window.width, window.height); } From 3d79d70fe4d78302b6c0a116278e490193154dc6 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 20 Dec 2009 01:51:38 +0100 Subject: [PATCH 35/67] Don't use UNUSED --- gfxmenu/gfxmenu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gfxmenu/gfxmenu.c b/gfxmenu/gfxmenu.c index ab1c8befb..62ee34234 100644 --- a/gfxmenu/gfxmenu.c +++ b/gfxmenu/gfxmenu.c @@ -201,8 +201,9 @@ show_menu (grub_menu_t menu, int nested) } static grub_err_t -grub_cmd_gfxmenu (grub_command_t cmd UNUSED, - int argc UNUSED, char **args UNUSED) +grub_cmd_gfxmenu (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) { grub_menu_t menu = grub_env_get_data_slot ("menu"); if (! menu) From 9b1209ba15cc0cddaf965f98777eb6cbd1213129 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 26 Dec 2009 02:37:01 +0100 Subject: [PATCH 36/67] Cache loaded theme --- gfxmenu/gfxmenu.c | 63 +++++++++++++++++++++++++++----- gfxmenu/view.c | 71 ++++++++----------------------------- include/grub/gfxmenu_view.h | 3 +- 3 files changed, 70 insertions(+), 67 deletions(-) diff --git a/gfxmenu/gfxmenu.c b/gfxmenu/gfxmenu.c index 0d807914b..f39cdbbfe 100644 --- a/gfxmenu/gfxmenu.c +++ b/gfxmenu/gfxmenu.c @@ -37,21 +37,39 @@ #include #include -void -grub_gfxmenu_viewer_fini (void *data) -{ - grub_gfxmenu_view_t view = data; +grub_gfxmenu_view_t cached_view; - grub_gfxmenu_view_destroy (view); +static grub_err_t +set_graphics_mode (void) +{ + const char *modestr = grub_env_get ("gfxmode"); + if (!modestr || !modestr[0]) + modestr = "auto"; + return grub_video_set_mode (modestr, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); +} + +/* FIXME: conflicts with gfxterm. */ +static grub_err_t +set_text_mode (void) +{ + return grub_video_restore (); +} + +void +grub_gfxmenu_viewer_fini (void *data __attribute__ ((unused))) +{ + set_text_mode (); } /* FIXME: 't' and 'c'. */ grub_err_t grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) { - grub_gfxmenu_view_t view; + grub_gfxmenu_view_t view = NULL; const char *theme_path; struct grub_menu_viewer *instance; + grub_err_t err; + struct grub_video_mode_info mode_info; theme_path = grub_env_get ("theme"); if (! theme_path) @@ -61,15 +79,41 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) if (!instance) return grub_errno; - /* Create the view. */ - view = grub_gfxmenu_view_new (theme_path, menu, entry, nested); + set_graphics_mode (); + err = grub_video_get_info (&mode_info); + if (err) + { + set_text_mode (); + return 0; + } - if (! view) + if (!cached_view || grub_strcmp (cached_view->theme_path, theme_path) != 0 + || cached_view->screen.width != (int) mode_info.width + || cached_view->screen.height != (int) mode_info.height) + { + grub_free (cached_view); + /* Create the view. */ + cached_view = grub_gfxmenu_view_new (theme_path, mode_info.width, + mode_info.height); + } + + if (! cached_view) { grub_free (instance); + set_text_mode (); return grub_errno; } + view = cached_view; + + view->double_repaint = (mode_info.mode_type + & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED) + && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); + view->selected = entry; + view->menu = menu; + view->nested = nested; + view->first_timeout = -1; + grub_gfxmenu_view_draw (view); instance->data = view; @@ -90,5 +134,6 @@ GRUB_MOD_INIT (gfxmenu) GRUB_MOD_FINI (gfxmenu) { + grub_gfxmenu_view_destroy (cached_view); grub_gfxmenu_try_hook = NULL; } diff --git a/gfxmenu/view.c b/gfxmenu/view.c index 882469447..8c460ff88 100644 --- a/gfxmenu/view.c +++ b/gfxmenu/view.c @@ -45,62 +45,31 @@ static grub_gfxmenu_view_t term_view; #endif -static grub_err_t set_graphics_mode (void); -static grub_err_t set_text_mode (void); - /* Create a new view object, loading the theme specified by THEME_PATH and associating MODEL with the view. */ grub_gfxmenu_view_t -grub_gfxmenu_view_new (const char *theme_path, grub_menu_t menu, int entry, - int nested) +grub_gfxmenu_view_new (const char *theme_path, + int width, int height) { grub_gfxmenu_view_t view; - grub_err_t err; - struct grub_video_mode_info mode_info; + grub_font_t default_font; + grub_gui_color_t default_fg_color; + grub_gui_color_t default_bg_color; view = grub_malloc (sizeof (*view)); if (! view) return 0; - set_graphics_mode (); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); - grub_video_get_viewport ((unsigned *) &view->screen.x, - (unsigned *) &view->screen.y, - (unsigned *) &view->screen.width, - (unsigned *) &view->screen.height); - - err = grub_video_get_info (&mode_info); - if (err) - { - grub_free (view); - return 0; - } - else - view->double_repaint = (mode_info.mode_type - & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED) - && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); - - - /* Clear the screen; there may be garbage left over in video memory, and - loading the menu style (particularly the background) can take a while. */ - grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), - view->screen.x, view->screen.y, - view->screen.width, view->screen.height); - grub_video_swap_buffers (); - - grub_font_t default_font; - grub_gui_color_t default_fg_color; - grub_gui_color_t default_bg_color; + view->screen.x = 0; + view->screen.y = 0; + view->screen.width = width; + view->screen.height = height; default_font = grub_font_get ("Helvetica 12"); default_fg_color = grub_gui_color_rgb (0, 0, 0); default_bg_color = grub_gui_color_rgb (255, 255, 255); view->canvas = 0; - view->selected = entry; - view->menu = menu; - view->nested = nested; - view->first_timeout = -1; view->title_font = default_font; view->message_font = default_font; @@ -151,7 +120,6 @@ grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view) view->canvas->ops->component.destroy (view->canvas); grub_free (view); - set_text_mode (); #if 0 destroy_terminal (); #endif @@ -376,6 +344,12 @@ grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, void grub_gfxmenu_view_draw (grub_gfxmenu_view_t view) { + /* Clear the screen; there may be garbage left over in video memory. */ + grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), + view->screen.x, view->screen.y, + view->screen.width, view->screen.height); + grub_video_swap_buffers (); + update_menu_components (view); grub_gfxmenu_view_redraw (view, &view->screen); @@ -426,21 +400,6 @@ grub_gfxmenu_set_chosen_entry (int entry, void *data) } -static grub_err_t -set_graphics_mode (void) -{ - const char *modestr = grub_env_get ("gfxmode"); - if (!modestr || !modestr[0]) - modestr = "auto"; - return grub_video_set_mode (modestr, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); -} - -static grub_err_t -set_text_mode (void) -{ - return grub_video_restore (); -} - /* FIXME */ #if 0 static int term_target_width; diff --git a/include/grub/gfxmenu_view.h b/include/grub/gfxmenu_view.h index 92cedc6a7..1b83cc5a3 100644 --- a/include/grub/gfxmenu_view.h +++ b/include/grub/gfxmenu_view.h @@ -31,8 +31,7 @@ typedef struct grub_gfxmenu_view *grub_gfxmenu_view_t; grub_gfxmenu_view_t grub_gfxmenu_view_new (const char *theme_path, - grub_menu_t menu, int entry, - int nested); + int width, int height); void grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view); From d3ee2d201e3a241ee1f39e9a2a2e3e6580579186 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 26 Dec 2009 16:41:54 +0100 Subject: [PATCH 37/67] Various fixes to make gfxmenu work smoothly in multioutput environment --- gfxmenu/gfxmenu.c | 43 +++++----- gfxmenu/view.c | 109 ++++++++++---------------- include/grub/gfxmenu_view.h | 8 -- include/grub/gfxterm.h | 18 +++-- include/grub/menu.h | 4 - term/gfxterm.c | 152 ++++++++++++++++-------------------- 6 files changed, 137 insertions(+), 197 deletions(-) diff --git a/gfxmenu/gfxmenu.c b/gfxmenu/gfxmenu.c index f39cdbbfe..b093ec49e 100644 --- a/gfxmenu/gfxmenu.c +++ b/gfxmenu/gfxmenu.c @@ -39,26 +39,9 @@ grub_gfxmenu_view_t cached_view; -static grub_err_t -set_graphics_mode (void) -{ - const char *modestr = grub_env_get ("gfxmode"); - if (!modestr || !modestr[0]) - modestr = "auto"; - return grub_video_set_mode (modestr, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); -} - -/* FIXME: conflicts with gfxterm. */ -static grub_err_t -set_text_mode (void) -{ - return grub_video_restore (); -} - void grub_gfxmenu_viewer_fini (void *data __attribute__ ((unused))) { - set_text_mode (); } /* FIXME: 't' and 'c'. */ @@ -73,18 +56,23 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) theme_path = grub_env_get ("theme"); if (! theme_path) - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no theme specified"); + { + grub_gfxterm_fullscreen (); + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no theme specified"); + } instance = grub_zalloc (sizeof (*instance)); if (!instance) - return grub_errno; + { + grub_gfxterm_fullscreen (); + return grub_errno; + } - set_graphics_mode (); err = grub_video_get_info (&mode_info); if (err) { - set_text_mode (); - return 0; + grub_gfxterm_fullscreen (); + return err; } if (!cached_view || grub_strcmp (cached_view->theme_path, theme_path) != 0 @@ -100,7 +88,7 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) if (! cached_view) { grub_free (instance); - set_text_mode (); + grub_gfxterm_fullscreen (); return grub_errno; } @@ -129,6 +117,15 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) GRUB_MOD_INIT (gfxmenu) { + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_gfxmenu_try_hook && grub_strcmp (term->name, "gfxterm") == 0) + { + grub_gfxterm_fullscreen (); + break; + } + grub_gfxmenu_try_hook = grub_gfxmenu_try; } diff --git a/gfxmenu/view.c b/gfxmenu/view.c index 8c460ff88..a7ca14530 100644 --- a/gfxmenu/view.c +++ b/gfxmenu/view.c @@ -41,9 +41,10 @@ status changes. */ #define TIMEOUT_COMPONENT_ID "__timeout__" -#if 0 +static void +init_terminal (grub_gfxmenu_view_t view); +static grub_video_rect_t term_rect; static grub_gfxmenu_view_t term_view; -#endif /* Create a new view object, loading the theme specified by THEME_PATH and associating MODEL with the view. */ @@ -98,10 +99,6 @@ grub_gfxmenu_view_new (const char *theme_path, return 0; } -#if 0 - init_terminal (view); -#endif - return view; } @@ -119,26 +116,8 @@ grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view) if (view->canvas) view->canvas->ops->component.destroy (view->canvas); grub_free (view); - -#if 0 - destroy_terminal (); -#endif } -#if 0 -/* Sets MESSAGE as the progress message for the view. - MESSAGE can be 0, in which case no message is displayed. */ -static void -set_progress_message (grub_gfxmenu_view_t view, const char *message) -{ - grub_free (view->progress_message_text); - if (message) - view->progress_message_text = grub_strdup (message); - else - view->progress_message_text = 0; -} -#endif - static void redraw_background (grub_gfxmenu_view_t view, const grub_video_rect_t *bounds) @@ -331,6 +310,9 @@ void grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, const grub_video_rect_t *region) { + if (grub_video_have_common_points (&term_rect, region)) + grub_gfxterm_schedule_repaint (); + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); redraw_background (view, region); @@ -344,11 +326,17 @@ grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, void grub_gfxmenu_view_draw (grub_gfxmenu_view_t view) { + init_terminal (view); + /* Clear the screen; there may be garbage left over in video memory. */ grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), view->screen.x, view->screen.y, view->screen.width, view->screen.height); grub_video_swap_buffers (); + if (view->double_repaint) + grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), + view->screen.x, view->screen.y, + view->screen.width, view->screen.height); update_menu_components (view); @@ -399,77 +387,60 @@ grub_gfxmenu_set_chosen_entry (int entry, void *data) grub_gfxmenu_redraw_menu (view); } - -/* FIXME */ -#if 0 -static int term_target_width; -static int term_target_height; -static int term_initialized; -static grub_term_output_t term_original; - static void -draw_terminal_box (grub_gfxmenu_view_t view) +grub_gfxmenu_draw_terminal_box (void) { grub_gfxmenu_box_t term_box; - int termx; - int termy; term_box = term_view->terminal_box; if (!term_box) return; - - termx = term_view->screen.x + term_view->screen.width * (10 - 7) / 10 / 2; - termy = term_view->screen.y + term_view->screen.height * (10 - 7) / 10 / 2; - term_box->set_content_size (term_box, term_target_width, - term_target_height); + term_box->set_content_size (term_box, term_rect.width, + term_rect.height); term_box->draw (term_box, - termx - term_box->get_left_pad (term_box), - termy - term_box->get_top_pad (term_box)); + term_rect.x - term_box->get_left_pad (term_box), + term_rect.y - term_box->get_top_pad (term_box)); grub_video_swap_buffers (); - if (view->double_repaint) + if (term_view->double_repaint) term_box->draw (term_box, - termx - term_box->get_left_pad (term_box), - termy - term_box->get_top_pad (term_box)); + term_rect.x - term_box->get_left_pad (term_box), + term_rect.y - term_box->get_top_pad (term_box)); } static void init_terminal (grub_gfxmenu_view_t view) { - int termx; - int termy; + term_rect.width = view->screen.width * 7 / 10; + term_rect.height = view->screen.height * 7 / 10; - term_original = grub_term_get_current_output (); + term_rect.x = view->screen.x + view->screen.width * (10 - 7) / 10 / 2; + term_rect.y = view->screen.y + view->screen.height * (10 - 7) / 10 / 2; - term_target_width = view->screen.width * 7 / 10; - term_target_height = view->screen.height * 7 / 10; - - termx = view->screen.x + view->screen.width * (10 - 7) / 10 / 2; - termy = view->screen.y + view->screen.height * (10 - 7) / 10 / 2; + term_view = view; /* Note: currently there is no API for changing the gfxterm font on the fly, so whatever font the initially loaded theme specifies will be permanent. */ - grub_gfxterm_init_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, termx, termy, - term_target_width, term_target_height, - view->double_repaint, view->terminal_font_name, 3); - if (grub_errno != GRUB_ERR_NONE) - return; - term_initialized = 1; - - term_view = view; - - grub_term_set_current_output (grub_gfxterm_get_term ()); - grub_refresh (); + grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, term_rect.x, + term_rect.y, + term_rect.width, term_rect.height, + view->double_repaint, view->terminal_font_name, 3); + grub_gfxterm_decorator_hook = grub_gfxmenu_draw_terminal_box; } -static void destroy_terminal (void) +#if 0 +/* Sets MESSAGE as the progress message for the view. + MESSAGE can be 0, in which case no message is displayed. */ +static void +set_progress_message (grub_gfxmenu_view_t view, const char *message) { - if (term_initialized) - grub_gfxterm_destroy_window (); - if (term_original) - grub_term_set_current_output (term_original); + grub_free (view->progress_message_text); + if (message) + view->progress_message_text = grub_strdup (message); + else + view->progress_message_text = 0; } static void diff --git a/include/grub/gfxmenu_view.h b/include/grub/gfxmenu_view.h index 1b83cc5a3..7cbfa89d3 100644 --- a/include/grub/gfxmenu_view.h +++ b/include/grub/gfxmenu_view.h @@ -45,14 +45,6 @@ grub_err_t grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr, void grub_gfxmenu_view_draw (grub_gfxmenu_view_t view); -int grub_gfxmenu_view_execute_with_fallback (grub_gfxmenu_view_t view, - grub_menu_entry_t entry); - -int grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view, - grub_menu_entry_t entry); - -void grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view); - void grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view); diff --git a/include/grub/gfxterm.h b/include/grub/gfxterm.h index e607bd5e1..fe3da7409 100644 --- a/include/grub/gfxterm.h +++ b/include/grub/gfxterm.h @@ -25,18 +25,20 @@ #include grub_err_t -grub_gfxterm_init_window (struct grub_video_render_target *target, - int x, int y, int width, int height, - int double_repaint, - const char *font_name, int border_width); - -void grub_gfxterm_destroy_window (void); - -const struct grub_term_output *grub_gfxterm_get_term (void); +grub_gfxterm_set_window (struct grub_video_render_target *target, + int x, int y, int width, int height, + int double_repaint, + const char *font_name, int border_width); typedef void (*grub_gfxterm_repaint_callback_t)(int x, int y, int width, int height); void grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func); +void grub_gfxterm_schedule_repaint (void); + +grub_err_t grub_gfxterm_fullscreen (void); + +extern void (*grub_gfxterm_decorator_hook) (void); + #endif /* ! GRUB_GFXTERM_HEADER */ diff --git a/include/grub/menu.h b/include/grub/menu.h index 20a1fc47f..78f461b92 100644 --- a/include/grub/menu.h +++ b/include/grub/menu.h @@ -83,10 +83,6 @@ typedef struct grub_menu_execute_callback } *grub_menu_execute_callback_t; -extern grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu, - int nested); - - grub_menu_entry_t grub_menu_get_entry (grub_menu_t menu, int no); int grub_menu_get_timeout (void); void grub_menu_set_timeout (int timeout); diff --git a/term/gfxterm.c b/term/gfxterm.c index eb2c47c3d..8ef7d848b 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -115,20 +115,16 @@ struct grub_gfxterm_window int double_repaint; }; -static int refcount; static struct grub_video_render_target *render_target; +void (*grub_gfxterm_decorator_hook) (void) = NULL; static struct grub_gfxterm_window window; static struct grub_virtual_screen virtual_screen; static grub_gfxterm_repaint_callback_t repaint_callback; - -static grub_err_t init_window (struct grub_video_render_target *target, - int x, int y, int width, int height, - int double_repaint, - const char *font_name, int border_width); +static int repaint_schedulded = 0; +static int repaint_was_schedulded = 0; static void destroy_window (void); - static struct grub_video_render_target *text_layer; static unsigned int bitmap_width; @@ -271,10 +267,17 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, return grub_errno; } -static grub_err_t -init_window (struct grub_video_render_target *target, - int x, int y, int width, int height, int double_repaint, - const char *font_name, int border_width) +void +grub_gfxterm_schedule_repaint (void) +{ + repaint_schedulded = 1; +} + +grub_err_t +grub_gfxterm_set_window (struct grub_video_render_target *target, + int x, int y, int width, int height, + int double_repaint, + const char *font_name, int border_width) { /* Clean up any prior instance. */ destroy_window (); @@ -299,45 +302,55 @@ init_window (struct grub_video_render_target *target, window.height = height; window.double_repaint = double_repaint; - /* Mark whole window as dirty. */ dirty_region_reset (); - dirty_region_add (0, 0, width, height); + grub_gfxterm_schedule_repaint (); return grub_errno; } grub_err_t -grub_gfxterm_init_window (struct grub_video_render_target *target, - int x, int y, int width, int height, - int double_repaint, - const char *font_name, int border_width) -{ - if (refcount++ == 0) - init_window (target, x, y, width, height, double_repaint, - font_name, border_width); - return grub_errno; -} - -static grub_err_t -grub_gfxterm_init (void) +grub_gfxterm_fullscreen (void) { const char *font_name; - const char *modevar; struct grub_video_mode_info mode_info; - char *tmp; - grub_err_t err; grub_video_color_t color; + grub_err_t err; - /* If gfxterm has already been initialized by calling the init_window - function, then leave it alone when it is set as the current terminal. */ - if (refcount++ != 0) - return GRUB_ERR_NONE; + err = grub_video_get_info (&mode_info); + /* Figure out what mode we ended up. */ + if (err) + return err; + + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + + /* Make sure screen is black. */ + color = grub_video_map_rgb (0, 0, 0); + grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height); + bitmap = 0; /* Select the font to use. */ font_name = grub_env_get ("gfxterm_font"); if (! font_name) font_name = ""; /* Allow fallback to any font. */ + grub_gfxterm_decorator_hook = NULL; + + return grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, + 0, 0, mode_info.width, mode_info.height, + mode_info.mode_type + & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + && !(mode_info.mode_type + & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP), + font_name, DEFAULT_BORDER_WIDTH); +} + +static grub_err_t +grub_gfxterm_init (void) +{ + char *tmp; + grub_err_t err; + const char *modevar; + /* Parse gfxmode environment variable if set. */ modevar = grub_env_get ("gfxmode"); if (! modevar || *modevar == 0) @@ -358,35 +371,11 @@ grub_gfxterm_init (void) if (err) return err; - err = grub_video_get_info (&mode_info); - /* Figure out what mode we ended up. */ + err = grub_gfxterm_fullscreen (); if (err) - return err; + grub_video_restore (); - /* Make sure screen is black. */ - color = grub_video_map_rgb (0, 0, 0); - grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height); - bitmap = 0; - - /* Select the font to use. */ - font_name = grub_env_get ("gfxterm_font"); - if (! font_name) - font_name = ""; /* Allow fallback to any font. */ - - /* Leave borders for virtual screen. */ - if (init_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, - 0, 0, mode_info.width, mode_info.height, - mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED - && !(mode_info.mode_type - & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP), - font_name, - DEFAULT_BORDER_WIDTH) != GRUB_ERR_NONE) - { - grub_video_restore (); - return grub_errno; - } - - return grub_errno; + return err; } static void @@ -402,26 +391,15 @@ destroy_window (void) grub_virtual_screen_free (); } -void -grub_gfxterm_destroy_window (void) -{ - if (--refcount == 0) - destroy_window (); -} - static grub_err_t grub_gfxterm_fini (void) { - /* Don't destroy an explicitly initialized terminal instance when it is - unset as the current terminal. */ - if (--refcount == 0) - { - destroy_window (); - grub_video_restore (); - } + destroy_window (); + grub_video_restore (); /* Clear error state. */ - return (grub_errno = GRUB_ERR_NONE); + grub_errno = GRUB_ERR_NONE; + return GRUB_ERR_NONE; } static void @@ -521,6 +499,7 @@ dirty_region_reset (void) dirty_region.top_left_y = -1; dirty_region.bottom_right_x = -1; dirty_region.bottom_right_y = -1; + repaint_was_schedulded = 0; } static int @@ -540,6 +519,16 @@ dirty_region_add (int x, int y, unsigned int width, unsigned int height) if ((width == 0) || (height == 0)) return; + if (repaint_schedulded) + { + x = virtual_screen.offset_x; + y = virtual_screen.offset_y; + width = virtual_screen.width; + height = virtual_screen.height; + repaint_schedulded = 0; + repaint_was_schedulded = 1; + } + if (dirty_region_is_empty ()) { dirty_region.top_left_x = x; @@ -586,6 +575,9 @@ dirty_region_redraw (void) width = dirty_region.bottom_right_x - x + 1; height = dirty_region.bottom_right_y - y + 1; + if (repaint_was_schedulded && grub_gfxterm_decorator_hook) + grub_gfxterm_decorator_hook (); + redraw_screen_rect (x, y, width, height); } @@ -1109,7 +1101,6 @@ grub_gfxterm_background_image_cmd (grub_extcmd_t cmd __attribute__ ((unused)), bitmap = 0; /* Mark whole screen as dirty. */ - dirty_region_reset (); dirty_region_add (0, 0, window.width, window.height); } @@ -1152,7 +1143,6 @@ grub_gfxterm_background_image_cmd (grub_extcmd_t cmd __attribute__ ((unused)), bitmap_height = grub_video_bitmap_get_height (bitmap); /* Mark whole screen as dirty. */ - dirty_region_reset (); dirty_region_add (0, 0, window.width, window.height); } } @@ -1182,18 +1172,10 @@ static struct grub_term_output grub_video_term = .next = 0 }; -const struct grub_term_output * -grub_gfxterm_get_term (void) -{ - return &grub_video_term; -} - static grub_extcmd_t background_image_cmd_handle; GRUB_MOD_INIT(term_gfxterm) { - refcount = 0; - grub_term_register_output ("gfxterm", &grub_video_term); background_image_cmd_handle = grub_register_extcmd ("background_image", From 4cc972be91c947f12a9edcd10946ae1119494fe7 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 26 Dec 2009 16:58:01 +0100 Subject: [PATCH 38/67] Clarify FIXME comments. --- gfxmenu/gfxmenu.c | 2 +- gfxmenu/view.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/gfxmenu/gfxmenu.c b/gfxmenu/gfxmenu.c index b093ec49e..1fe6e7297 100644 --- a/gfxmenu/gfxmenu.c +++ b/gfxmenu/gfxmenu.c @@ -44,7 +44,7 @@ grub_gfxmenu_viewer_fini (void *data __attribute__ ((unused))) { } -/* FIXME: 't' and 'c'. */ +/* FIXME: Previously 't' changed to text menu is it necessary? */ grub_err_t grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) { diff --git a/gfxmenu/view.c b/gfxmenu/view.c index a7ca14530..c32211261 100644 --- a/gfxmenu/view.c +++ b/gfxmenu/view.c @@ -430,6 +430,9 @@ init_terminal (grub_gfxmenu_view_t view) grub_gfxterm_decorator_hook = grub_gfxmenu_draw_terminal_box; } +/* FIXME: previously notifications were displayed in special case. + Is it necessary? + */ #if 0 /* Sets MESSAGE as the progress message for the view. MESSAGE can be 0, in which case no message is displayed. */ From a2b4c09b1c48c5e3b8958291a06c2ee651b5a57d Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 27 Dec 2009 22:24:46 +0100 Subject: [PATCH 39/67] Don't destroy NULL view --- gfxmenu/view.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gfxmenu/view.c b/gfxmenu/view.c index 7d9bb1cd0..e2348b6ef 100644 --- a/gfxmenu/view.c +++ b/gfxmenu/view.c @@ -136,6 +136,8 @@ grub_gfxmenu_view_new (const char *theme_path, grub_gfxmenu_model_t model) void grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view) { + if (!view) + return; grub_video_bitmap_destroy (view->desktop_image); if (view->terminal_box) view->terminal_box->destroy (view->terminal_box); From 9a17588459f2bc876c7b3f4c9d86b0489ca1bc5b Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 29 Dec 2009 17:31:02 +0100 Subject: [PATCH 40/67] Initial support for scalable gfxmenu --- gfxmenu/gui_box.c | 232 +++++++++++++++++++------------- gfxmenu/gui_canvas.c | 120 ++++++++--------- gfxmenu/gui_circular_progress.c | 52 +------ gfxmenu/gui_image.c | 38 +----- gfxmenu/gui_label.c | 36 +---- gfxmenu/gui_list.c | 64 +++------ gfxmenu/gui_progress_bar.c | 48 +------ gfxmenu/gui_string_util.c | 38 ------ gfxmenu/theme_loader.c | 104 ++++++++------ gfxmenu/view.c | 4 +- include/grub/gui.h | 59 +++++++- include/grub/gui_string_util.h | 2 - include/grub/video.h | 8 +- 13 files changed, 368 insertions(+), 437 deletions(-) diff --git a/gfxmenu/gui_box.c b/gfxmenu/gui_box.c index 4fe131f98..45028e5b1 100644 --- a/gfxmenu/gui_box.c +++ b/gfxmenu/gui_box.c @@ -32,17 +32,16 @@ struct component_node typedef struct grub_gui_box *grub_gui_box_t; typedef void (*layout_func_t) (grub_gui_box_t self, int modify_layout, - int *width, int *height); + unsigned *minimal_width, + unsigned *minimal_height); struct grub_gui_box { - struct grub_gui_container_ops *container; + struct grub_gui_container container; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; /* Doubly linked list of components with dummy head & tail nodes. */ struct component_node chead; @@ -87,82 +86,158 @@ box_is_instance (void *vself __attribute__((unused)), const char *type) static void layout_horizontally (grub_gui_box_t self, int modify_layout, - int *width, int *height) + unsigned *min_width, unsigned *min_height) { /* Start at the left (chead) and set the x coordinates as we go right. */ /* All components have their width set to the box's width. */ struct component_node *cur; - int x = 0; - if (height) - *height = 0; + unsigned w = 0, mwfrac = 0, h = 0, x = 0; + grub_fixed_unsigned_t wfrac = 0; + int bogus_frac = 0; + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) { grub_gui_component_t c = cur->component; + unsigned mw = 0, mh = 0; + + if (c->ops->get_minimal_size) + c->ops->get_minimal_size (c, &mw, &mh); + + if (!c->ishfrac && c->h > h) + h = c->h; + if (mh > h) + h = mh; + if (!c->iswfrac) + w += mw > c->w ? mw : c->w; + if (c->iswfrac) + { + wfrac += c->wfrac; + mwfrac += mw; + } + } + if (wfrac > GRUB_FIXED_1 || (w > 0 && wfrac == GRUB_FIXED_1)) + bogus_frac = 1; + + if (min_width) + { + if (wfrac < GRUB_FIXED_1) + *min_width = grub_fixed_ufu_divide (w, GRUB_FIXED_1 - wfrac); + else + *min_width = w; + if (*min_width < w + mwfrac) + *min_width = w + mwfrac; + } + if (min_height) + *min_height = h; + + if (!modify_layout) + return; + + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { grub_video_rect_t r; + grub_gui_component_t c = cur->component; + unsigned mw = 0, mh = 0; - c->ops->get_preferred_size (c, &r.width, &r.height); + r.x = x; + r.y = 0; + r.width = 32; + r.height = h; - /* Check and possibly update the maximum width, if non-null. */ - if (height && r.height > *height) - *height = r.height; + if (c->ops->get_minimal_size) + c->ops->get_minimal_size (c, &mw, &mh); - /* Set the component's bounds, if the flag is set. */ - if (modify_layout) - { - r.x = x; - r.y = 0; - /* Width comes from the component's preferred size. */ - r.height = self->bounds.height; - c->ops->set_bounds (c, &r); - } + if (!c->iswfrac) + r.width = c->w; + if (c->iswfrac && !bogus_frac) + r.width = grub_fixed_ufu_multiply (self->bounds.width, c->wfrac); + + if (r.width < mw) + r.width = mw; + + c->ops->set_bounds (c, &r); x += r.width; } - - /* Return the sum of the children's preferred widths. */ - if (width) - *width = x; } static void layout_vertically (grub_gui_box_t self, int modify_layout, - int *width, int *height) + unsigned *min_width, unsigned *min_height) { - /* Start at the top (chead) and set the y coordinates as we go down. */ - /* All components have their width set to the vbox's width. */ + /* Start at the top (chead) and set the y coordinates as we go rdown. */ + /* All components have their height set to the box's height. */ struct component_node *cur; - int y = 0; - if (width) - *width = 0; + unsigned h = 0, mhfrac = 0, w = 0, y = 0; + grub_fixed_unsigned_t hfrac = 0; + int bogus_frac = 0; + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) { grub_gui_component_t c = cur->component; + unsigned mw = 0, mh = 0; + + if (c->ops->get_minimal_size) + c->ops->get_minimal_size (c, &mw, &mh); + + if (!c->iswfrac && c->w > w) + w = c->w; + if (mw > w) + w = mw; + if (!c->ishfrac) + h += mh > c->h ? mh : c->h; + if (c->ishfrac) + { + hfrac += c->hfrac; + mhfrac += mh; + } + } + if (hfrac > GRUB_FIXED_1 || (h > 0 && hfrac == GRUB_FIXED_1)) + bogus_frac = 1; + + if (min_height) + { + if (hfrac < GRUB_FIXED_1) + *min_height = grub_fixed_ufu_divide (h, GRUB_FIXED_1 - hfrac); + else + *min_height = h; + if (*min_height < h + mhfrac) + *min_height = h + mhfrac; + } + if (min_width) + *min_width = w; + + if (!modify_layout) + return; + + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { grub_video_rect_t r; + grub_gui_component_t c = cur->component; + unsigned mw = 0, mh = 0; - c->ops->get_preferred_size (c, &r.width, &r.height); + r.x = 0; + r.y = y; + r.width = w; + r.height = 32; - /* Check and possibly update the maximum width, if non-null. */ - if (width && r.width > *width) - *width = r.width; + if (c->ops->get_minimal_size) + c->ops->get_minimal_size (c, &mw, &mh); - /* Set the component's bounds, if the flag is set. */ - if (modify_layout) - { - r.x = 0; - r.y = y; - r.width = self->bounds.width; - /* Height comes from the component's preferred size. */ - c->ops->set_bounds (c, &r); - } + if (!c->ishfrac) + r.height = c->h; + if (c->ishfrac) + r.height = grub_fixed_ufu_multiply (self->bounds.height, c->hfrac); + + if (r.height < mh) + r.height = mh; + + c->ops->set_bounds (c, &r); y += r.height; } - - /* Return the sum of the children's preferred heights. */ - if (height) - *height = y; } static void @@ -213,16 +288,10 @@ box_get_bounds (void *vself, grub_video_rect_t *bounds) /* The box's preferred size is based on the preferred sizes of its children. */ static void -box_get_preferred_size (void *vself, int *width, int *height) +box_get_minimal_size (void *vself, unsigned *width, unsigned *height) { grub_gui_box_t self = vself; self->layout_func (self, 0, width, height); /* Just calculate the size. */ - - /* Allow preferred dimensions to override the computed dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; } static grub_err_t @@ -241,15 +310,6 @@ box_set_property (void *vself, const char *name, const char *value) else self->id = 0; } - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) - return grub_errno; - self->preferred_width = w; - self->preferred_height = h; - } return grub_errno; } @@ -303,21 +363,22 @@ box_iterate_children (void *vself, cb (cur->component, userdata); } +static struct grub_gui_component_ops box_comp_ops = + { + .destroy = box_destroy, + .get_id = box_get_id, + .is_instance = box_is_instance, + .paint = box_paint, + .set_parent = box_set_parent, + .get_parent = box_get_parent, + .set_bounds = box_set_bounds, + .get_bounds = box_get_bounds, + .get_minimal_size = box_get_minimal_size, + .set_property = box_set_property + }; + static struct grub_gui_container_ops box_ops = { - .component = - { - .destroy = box_destroy, - .get_id = box_get_id, - .is_instance = box_is_instance, - .paint = box_paint, - .set_parent = box_set_parent, - .get_parent = box_get_parent, - .set_bounds = box_set_bounds, - .get_bounds = box_get_bounds, - .get_preferred_size = box_get_preferred_size, - .set_property = box_set_property - }, .add = box_add, .remove = box_remove, .iterate_children = box_iterate_children @@ -329,24 +390,13 @@ static grub_gui_box_t box_new (layout_func_t layout_func) { grub_gui_box_t box; - box = grub_malloc (sizeof (*box)); + box = grub_zalloc (sizeof (*box)); if (! box) return 0; - box->container = &box_ops; - box->parent = 0; - box->bounds.x = 0; - box->bounds.y = 0; - box->bounds.width = 0; - box->bounds.height = 0; - box->id = 0; - box->preferred_width = -1; - box->preferred_height = -1; - box->chead.component = 0; - box->chead.prev = 0; + box->container.ops = &box_ops; + box->container.component.ops = &box_comp_ops; box->chead.next = &box->ctail; - box->ctail.component = 0; box->ctail.prev = &box->chead; - box->ctail.next = 0; box->layout_func = layout_func; return box; } diff --git a/gfxmenu/gui_canvas.c b/gfxmenu/gui_canvas.c index d155364d7..8b55b2a73 100644 --- a/gfxmenu/gui_canvas.c +++ b/gfxmenu/gui_canvas.c @@ -32,13 +32,11 @@ struct component_node struct grub_gui_canvas { - struct grub_gui_container_ops *container; + struct grub_gui_container container; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; /* Component list (dummy head node). */ struct component_node components; }; @@ -88,22 +86,52 @@ canvas_paint (void *vself, const grub_video_rect_t *region) grub_gui_set_viewport (&self->bounds, &vpsave); for (cur = self->components.next; cur; cur = cur->next) { - int pw; - int ph; grub_video_rect_t r; grub_gui_component_t comp; comp = cur->component; - /* Give the child its preferred size. */ - comp->ops->get_preferred_size (comp, &pw, &ph); - comp->ops->get_bounds (comp, &r); - if (r.width != pw || r.height != ph) - { - r.width = pw; - r.height = ph; - comp->ops->set_bounds (comp, &r); - } + r.x = 0; + r.y = 0; + r.width = 32; + r.height = 32; + + if (!comp->iswfrac && comp->w) + r.width = comp->w; + + if (!comp->ishfrac && comp->h) + r.height = comp->h; + + if (!comp->isxfrac && comp->x) + r.x = comp->x; + + if (!comp->isyfrac && comp->y) + r.y = comp->y; + + if (comp->ishfrac && comp->hfrac) + r.height = grub_fixed_ufu_multiply (self->bounds.height, comp->hfrac); + + if (comp->iswfrac && comp->wfrac) + r.width = grub_fixed_ufu_multiply (self->bounds.width, comp->wfrac); + + if (comp->isxfrac && comp->xfrac) + r.x = grub_fixed_ufu_multiply (self->bounds.width, comp->xfrac); + + if (comp->isyfrac && comp->yfrac) + r.y = grub_fixed_ufu_multiply (self->bounds.height, comp->yfrac); + + if (comp->ops->get_minimal_size) + { + unsigned mw; + unsigned mh; + comp->ops->get_minimal_size (comp, &mw, &mh); + if (r.width < mw) + r.width = mw; + if (r.height < mh) + r.height = mh; + } + + comp->ops->set_bounds (comp, &r); /* Paint the child. */ if (grub_video_have_common_points (region, &r)) @@ -140,20 +168,6 @@ canvas_get_bounds (void *vself, grub_video_rect_t *bounds) *bounds = self->bounds; } -static void -canvas_get_preferred_size (void *vself, int *width, int *height) -{ - grub_gui_canvas_t self = vself; - *width = 0; - *height = 0; - - /* Allow preferred dimensions to override the empty dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; -} - static grub_err_t canvas_set_property (void *vself, const char *name, const char *value) { @@ -170,15 +184,6 @@ canvas_set_property (void *vself, const char *name, const char *value) else self->id = 0; } - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) - return grub_errno; - self->preferred_width = w; - self->preferred_height = h; - } return grub_errno; } @@ -227,21 +232,21 @@ canvas_iterate_children (void *vself, cb (cur->component, userdata); } +static struct grub_gui_component_ops canvas_comp_ops = +{ + .destroy = canvas_destroy, + .get_id = canvas_get_id, + .is_instance = canvas_is_instance, + .paint = canvas_paint, + .set_parent = canvas_set_parent, + .get_parent = canvas_get_parent, + .set_bounds = canvas_set_bounds, + .get_bounds = canvas_get_bounds, + .set_property = canvas_set_property +}; + static struct grub_gui_container_ops canvas_ops = { - .component = - { - .destroy = canvas_destroy, - .get_id = canvas_get_id, - .is_instance = canvas_is_instance, - .paint = canvas_paint, - .set_parent = canvas_set_parent, - .get_parent = canvas_get_parent, - .set_bounds = canvas_set_bounds, - .get_bounds = canvas_get_bounds, - .get_preferred_size = canvas_get_preferred_size, - .set_property = canvas_set_property - }, .add = canvas_add, .remove = canvas_remove, .iterate_children = canvas_iterate_children @@ -251,19 +256,10 @@ grub_gui_container_t grub_gui_canvas_new (void) { grub_gui_canvas_t canvas; - canvas = grub_malloc (sizeof (*canvas)); + canvas = grub_zalloc (sizeof (*canvas)); if (! canvas) return 0; - canvas->container = &canvas_ops; - canvas->parent = 0; - canvas->bounds.x = 0; - canvas->bounds.y = 0; - canvas->bounds.width = 0; - canvas->bounds.height = 0; - canvas->id = 0; - canvas->preferred_width = -1; - canvas->preferred_height = -1; - canvas->components.component = 0; - canvas->components.next = 0; + canvas->container.ops = &canvas_ops; + canvas->container.component.ops = &canvas_comp_ops; return (grub_gui_container_t) canvas; } diff --git a/gfxmenu/gui_circular_progress.c b/gfxmenu/gui_circular_progress.c index f3c8bc3af..e57d1c236 100644 --- a/gfxmenu/gui_circular_progress.c +++ b/gfxmenu/gui_circular_progress.c @@ -28,13 +28,11 @@ struct grub_gui_circular_progress { - struct grub_gui_component_ops *circprog_ops; + struct grub_gui_component comp; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; int visible; int start; int end; @@ -209,21 +207,6 @@ circprog_get_bounds (void *vself, grub_video_rect_t *bounds) *bounds = self->bounds; } -static void -circprog_get_preferred_size (void *vself, int *width, int *height) -{ - circular_progress_t self = vself; - - *width = 0; - *height = 0; - - /* Allow preferred dimensions to override the circprog dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; -} - static grub_err_t circprog_set_property (void *vself, const char *name, const char *value) { @@ -270,15 +253,6 @@ circprog_set_property (void *vself, const char *name, const char *value) grub_free (self->theme_dir); self->theme_dir = value ? grub_strdup (value) : 0; } - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) - return grub_errno; - self->preferred_width = w; - self->preferred_height = h; - } else if (grub_strcmp (name, "visible") == 0) { self->visible = grub_strcmp (value, "false") != 0; @@ -304,7 +278,6 @@ static struct grub_gui_component_ops circprog_ops = .get_parent = circprog_get_parent, .set_bounds = circprog_set_bounds, .get_bounds = circprog_get_bounds, - .get_preferred_size = circprog_get_preferred_size, .set_property = circprog_set_property }; @@ -312,32 +285,13 @@ grub_gui_component_t grub_gui_circular_progress_new (void) { circular_progress_t self; - self = grub_malloc (sizeof (*self)); + self = grub_zalloc (sizeof (*self)); if (! self) return 0; - self->circprog_ops = &circprog_ops; - self->parent = 0; - self->bounds.x = 0; - self->bounds.y = 0; - self->bounds.width = 0; - self->bounds.height = 0; - self->id = 0; - self->preferred_width = -1; - self->preferred_height = -1; + self->comp.ops = &circprog_ops; self->visible = 1; - self->start = 0; - self->end = 0; - self->value = 0; self->num_ticks = 64; self->start_angle = -64; - self->ticks_disappear = 0; - - self->theme_dir = 0; - self->need_to_load_pixmaps = 0; - self->center_file = 0; - self->tick_file = 0; - self->center_bitmap = 0; - self->tick_bitmap = 0; return (grub_gui_component_t) self; } diff --git a/gfxmenu/gui_image.c b/gfxmenu/gui_image.c index eb2ff1ee0..ef8bcbe9a 100644 --- a/gfxmenu/gui_image.c +++ b/gfxmenu/gui_image.c @@ -26,13 +26,11 @@ struct grub_gui_image { - struct grub_gui_component_ops *image; + struct grub_gui_component component; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; struct grub_video_bitmap *raw_bitmap; struct grub_video_bitmap *bitmap; }; @@ -172,8 +170,9 @@ image_get_bounds (void *vself, grub_video_rect_t *bounds) *bounds = self->bounds; } +/* FIXME: inform rendering system it's not forced minimum. */ static void -image_get_preferred_size (void *vself, int *width, int *height) +image_get_minimal_size (void *vself, unsigned *width, unsigned *height) { grub_gui_image_t self = vself; @@ -187,12 +186,6 @@ image_get_preferred_size (void *vself, int *width, int *height) *width = 0; *height = 0; } - - /* Allow preferred dimensions to override the image dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; } static grub_err_t @@ -217,15 +210,6 @@ image_set_property (void *vself, const char *name, const char *value) grub_gui_image_t self = vself; if (grub_strcmp (name, "file") == 0) return load_image (self, value); - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) - return grub_errno; - self->preferred_width = w; - self->preferred_height = h; - } else if (grub_strcmp (name, "id") == 0) { grub_free (self->id); @@ -247,7 +231,7 @@ static struct grub_gui_component_ops image_ops = .get_parent = image_get_parent, .set_bounds = image_set_bounds, .get_bounds = image_get_bounds, - .get_preferred_size = image_get_preferred_size, + .get_minimal_size = image_get_minimal_size, .set_property = image_set_property }; @@ -255,20 +239,10 @@ grub_gui_component_t grub_gui_image_new (void) { grub_gui_image_t image; - image = grub_malloc (sizeof (*image)); + image = grub_zalloc (sizeof (*image)); if (! image) return 0; - image->image = &image_ops; - image->parent = 0; - image->bounds.x = 0; - image->bounds.y = 0; - image->bounds.width = 0; - image->bounds.height = 0; - image->id = 0; - image->preferred_width = -1; - image->preferred_height = -1; - image->raw_bitmap = 0; - image->bitmap = 0; + image->component.ops = &image_ops; return (grub_gui_component_t) image; } diff --git a/gfxmenu/gui_label.c b/gfxmenu/gui_label.c index 30474f52f..b2835ea1a 100644 --- a/gfxmenu/gui_label.c +++ b/gfxmenu/gui_label.c @@ -39,13 +39,11 @@ enum align_mode { struct grub_gui_label { - struct grub_gui_component_ops *label; + struct grub_gui_component comp; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; int visible; char *text; grub_font_t font; @@ -140,18 +138,12 @@ label_get_bounds (void *vself, grub_video_rect_t *bounds) } static void -label_get_preferred_size (void *vself, int *width, int *height) +label_get_minimal_size (void *vself, unsigned *width, unsigned *height) { grub_gui_label_t self = vself; *width = grub_font_get_string_width (self->font, self->text); *height = (grub_font_get_ascent (self->font) + grub_font_get_descent (self->font)); - - /* Allow preferred dimensions to override the computed dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; } static grub_err_t @@ -189,16 +181,6 @@ label_set_property (void *vself, const char *name, const char *value) { self->visible = grub_strcmp (value, "false") != 0; } - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) == GRUB_ERR_NONE) - { - self->preferred_width = w; - self->preferred_height = h; - } - } else if (grub_strcmp (name, "id") == 0) { grub_free (self->id); @@ -220,7 +202,7 @@ static struct grub_gui_component_ops label_ops = .get_parent = label_get_parent, .set_bounds = label_set_bounds, .get_bounds = label_get_bounds, - .get_preferred_size = label_get_preferred_size, + .get_minimal_size = label_get_minimal_size, .set_property = label_set_property }; @@ -228,18 +210,10 @@ grub_gui_component_t grub_gui_label_new (void) { grub_gui_label_t label; - label = grub_malloc (sizeof (*label)); + label = grub_zalloc (sizeof (*label)); if (! label) return 0; - label->label = &label_ops; - label->parent = 0; - label->bounds.x = 0; - label->bounds.y = 0; - label->bounds.width = 0; - label->bounds.height = 0; - label->id = 0; - label->preferred_width = -1; - label->preferred_height = -1; + label->comp.ops = &label_ops; label->visible = 1; label->text = grub_strdup (""); label->font = grub_font_get ("Helvetica 10"); diff --git a/gfxmenu/gui_list.c b/gfxmenu/gui_list.c index bf6d94657..c55cfd85c 100644 --- a/gfxmenu/gui_list.c +++ b/gfxmenu/gui_list.c @@ -26,13 +26,11 @@ struct grub_gui_list_impl { - struct grub_gui_list_ops *list_ops; + struct grub_gui_list list; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; int visible; int icon_width; @@ -357,7 +355,7 @@ list_get_bounds (void *vself, grub_video_rect_t *bounds) } static void -list_get_preferred_size (void *vself, int *width, int *height) +list_get_minimal_size (void *vself, unsigned *width, unsigned *height) { list_impl_t self = vself; @@ -387,12 +385,6 @@ list_get_preferred_size (void *vself, int *width, int *height) *width = 0; *height = 0; } - - /* Allow preferred dimensions to override the computed dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; } static grub_err_t @@ -507,15 +499,6 @@ list_set_property (void *vself, const char *name, const char *value) grub_free (self->theme_dir); self->theme_dir = value ? grub_strdup (value) : 0; } - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) - return grub_errno; - self->preferred_width = w; - self->preferred_height = h; - } else if (grub_strcmp (name, "id") == 0) { grub_free (self->id); @@ -538,21 +521,22 @@ list_set_view_info (void *vself, self->menu = menu; } +static struct grub_gui_component_ops list_comp_ops = + { + .destroy = list_destroy, + .get_id = list_get_id, + .is_instance = list_is_instance, + .paint = list_paint, + .set_parent = list_set_parent, + .get_parent = list_get_parent, + .set_bounds = list_set_bounds, + .get_bounds = list_get_bounds, + .get_minimal_size = list_get_minimal_size, + .set_property = list_set_property + }; + static struct grub_gui_list_ops list_ops = { - .component_ops = - { - .destroy = list_destroy, - .get_id = list_get_id, - .is_instance = list_is_instance, - .paint = list_paint, - .set_parent = list_set_parent, - .get_parent = list_get_parent, - .set_bounds = list_set_bounds, - .get_bounds = list_get_bounds, - .get_preferred_size = list_get_preferred_size, - .set_property = list_set_property - }, .set_view_info = list_set_view_info }; @@ -564,19 +548,13 @@ grub_gui_list_new (void) grub_gui_color_t default_fg_color; grub_gui_color_t default_bg_color; - self = grub_malloc (sizeof (*self)); + self = grub_zalloc (sizeof (*self)); if (! self) return 0; - self->list_ops = &list_ops; - self->parent = 0; - self->bounds.x = 0; - self->bounds.y = 0; - self->bounds.width = 0; - self->bounds.height = 0; - self->id = 0; - self->preferred_width = -1; - self->preferred_height = -1; + self->list.ops = &list_ops; + self->list.component.ops = &list_comp_ops; + self->visible = 1; default_font = grub_font_get ("Helvetica 12"); @@ -617,7 +595,7 @@ grub_gui_list_new (void) self->icon_manager = grub_gfxmenu_icon_manager_new (); if (! self->icon_manager) { - self->list_ops->component_ops.destroy (self); + self->list.component.ops->destroy (self); return 0; } grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager, diff --git a/gfxmenu/gui_progress_bar.c b/gfxmenu/gui_progress_bar.c index 498711169..9af93cff5 100644 --- a/gfxmenu/gui_progress_bar.c +++ b/gfxmenu/gui_progress_bar.c @@ -27,13 +27,11 @@ struct grub_gui_progress_bar { - struct grub_gui_component_ops *progress_bar; + struct grub_gui_component component; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; int visible; int start; int end; @@ -221,18 +219,11 @@ progress_bar_get_bounds (void *vself, grub_video_rect_t *bounds) } static void -progress_bar_get_preferred_size (void *vself, int *width, int *height) +progress_bar_get_minimal_size (void *vself __attribute__ ((unused)), + unsigned *width, unsigned *height) { - grub_gui_progress_bar_t self = vself; - *width = 200; *height = 28; - - /* Allow preferred dimensions to override the progress_bar dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; } static grub_err_t @@ -296,15 +287,6 @@ progress_bar_set_property (void *vself, const char *name, const char *value) grub_free (self->theme_dir); self->theme_dir = value ? grub_strdup (value) : 0; } - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) - return grub_errno; - self->preferred_width = w; - self->preferred_height = h; - } else if (grub_strcmp (name, "visible") == 0) { self->visible = grub_strcmp (value, "false") != 0; @@ -334,7 +316,7 @@ static struct grub_gui_component_ops progress_bar_ops = .get_parent = progress_bar_get_parent, .set_bounds = progress_bar_set_bounds, .get_bounds = progress_bar_get_bounds, - .get_preferred_size = progress_bar_get_preferred_size, + .get_minimal_size = progress_bar_get_minimal_size, .set_property = progress_bar_set_property }; @@ -342,22 +324,11 @@ grub_gui_component_t grub_gui_progress_bar_new (void) { grub_gui_progress_bar_t self; - self = grub_malloc (sizeof (*self)); + self = grub_zalloc (sizeof (*self)); if (! self) return 0; - self->progress_bar = &progress_bar_ops; - self->parent = 0; - self->bounds.x = 0; - self->bounds.y = 0; - self->bounds.width = 0; - self->bounds.height = 0; - self->id = 0; - self->preferred_width = -1; - self->preferred_height = -1; + self->component.ops = &progress_bar_ops; self->visible = 1; - self->start = 0; - self->end = 0; - self->value = 0; self->show_text = 1; self->text = grub_strdup (""); self->font = grub_font_get ("Helvetica 10"); @@ -369,12 +340,5 @@ grub_gui_progress_bar_new (void) self->bg_color = gray; self->fg_color = lightgray; - self->theme_dir = 0; - self->need_to_recreate_pixmaps = 0; - self->bar_pattern = 0; - self->highlight_pattern = 0; - self->bar_box = 0; - self->highlight_box = 0; - return (grub_gui_component_t) self; } diff --git a/gfxmenu/gui_string_util.c b/gfxmenu/gui_string_util.c index 8ea7c497b..8c51e396a 100644 --- a/gfxmenu/gui_string_util.c +++ b/gfxmenu/gui_string_util.c @@ -325,41 +325,3 @@ grub_gui_parse_color (const char *s, grub_gui_color_t *color) *color = c; return grub_errno; } - -/* Parse a value in the form "(x, y)", storing the first element (x) into - *PX and the second element (y) into *PY. - Returns GRUB_ERR_NONE if successfully parsed. */ -grub_err_t -grub_gui_parse_2_tuple (const char *s, int *px, int *py) -{ - int x; - int y; - - while (*s && grub_isspace (*s)) - s++; - if (*s != '(') - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "missing `(' in 2-tuple `%s'", s); - - /* Skip the opening parentheses. */ - s++; - if (*s == 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "unexpected end of 2-tuple after `(' in `%s'", s); - - /* Parse the first element. */ - x = grub_strtol (s, 0, 10); - if ((s = grub_strchr (s, ',')) == 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "missing comma in 2-tuple `%s'", s); - - /* Skip the element separator (the comma). */ - s++; - /* Parse the second element. */ - y = grub_strtol (s, 0, 10); - - *px = x; - *py = y; - - return grub_errno; -} diff --git a/gfxmenu/theme_loader.c b/gfxmenu/theme_loader.c index 3512c7bf1..29bc1d2a6 100644 --- a/gfxmenu/theme_loader.c +++ b/gfxmenu/theme_loader.c @@ -510,35 +510,73 @@ read_object (struct parsebuf *p, grub_gui_container_t parent) } /* Handle the property value. */ - if (grub_strcmp (property, "position") == 0) + if (grub_strcmp (property, "left") == 0) { - /* Special case for position value. */ - int x; - int y; - - if (grub_gui_parse_2_tuple (value, &x, &y) == GRUB_ERR_NONE) - { - grub_video_rect_t r; - component->ops->get_bounds (component, &r); - r.x = x; - r.y = y; - component->ops->set_bounds (component, &r); - } + unsigned num; + char *ptr; + num = grub_strtoul (value, &ptr, 0); + if (*ptr == '%') + { + component->isxfrac = 1; + component->xfrac + = grub_fixed_fuf_divide (grub_unsigned_to_fixed (num), 100); + } + else + { + component->isxfrac = 0; + component->x = num; + } } - else if (grub_strcmp (property, "size") == 0) + else if (grub_strcmp (property, "top") == 0) { - /* Special case for size value. */ - int w; - int h; - - if (grub_gui_parse_2_tuple (value, &w, &h) == GRUB_ERR_NONE) - { - grub_video_rect_t r; - component->ops->get_bounds (component, &r); - r.width = w; - r.height = h; - component->ops->set_bounds (component, &r); - } + unsigned num; + char *ptr; + num = grub_strtoul (value, &ptr, 0); + if (*ptr == '%') + { + component->isyfrac = 1; + component->yfrac + = grub_fixed_fuf_divide (grub_unsigned_to_fixed (num), 100); + } + else + { + component->isyfrac = 0; + component->y = num; + } + } + else if (grub_strcmp (property, "width") == 0) + { + unsigned num; + char *ptr; + num = grub_strtoul (value, &ptr, 0); + if (*ptr == '%') + { + component->iswfrac = 1; + component->wfrac + = grub_fixed_fuf_divide (grub_unsigned_to_fixed (num), 100); + } + else + { + component->iswfrac = 0; + component->w = num; + } + } + else if (grub_strcmp (property, "height") == 0) + { + unsigned num; + char *ptr; + num = grub_strtoul (value, &ptr, 0); + if (*ptr == '%') + { + component->ishfrac = 1; + component->hfrac + = grub_fixed_fuf_divide (grub_unsigned_to_fixed (num), 100); + } + else + { + component->ishfrac = 0; + component->h = num; + } } else { @@ -552,16 +590,6 @@ read_object (struct parsebuf *p, grub_gui_container_t parent) goto cleanup; } - /* Set the object's size to its preferred size unless the user has - explicitly specified the size. */ - component->ops->get_bounds (component, &bounds); - if (bounds.width == -1 || bounds.height == -1) - { - component->ops->get_preferred_size (component, - &bounds.width, &bounds.height); - component->ops->set_bounds (component, &bounds); - } - cleanup: grub_free (name); return grub_errno; @@ -665,7 +693,7 @@ grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path) } if (view->canvas) - view->canvas->ops->component.destroy (view->canvas); + view->canvas->component.ops->destroy (view->canvas); view->canvas = grub_gui_canvas_new (); ((grub_gui_component_t) view->canvas) @@ -708,7 +736,7 @@ grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path) fail: if (view->canvas) { - view->canvas->ops->component.destroy (view->canvas); + view->canvas->component.ops->destroy (view->canvas); view->canvas = 0; } diff --git a/gfxmenu/view.c b/gfxmenu/view.c index e2348b6ef..414541dda 100644 --- a/gfxmenu/view.c +++ b/gfxmenu/view.c @@ -146,7 +146,7 @@ grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view) grub_free (view->progress_message_text); grub_free (view->theme_path); if (view->canvas) - view->canvas->ops->component.destroy (view->canvas); + view->canvas->component.ops->destroy (view->canvas); grub_free (view); set_text_mode (); @@ -354,7 +354,7 @@ grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, redraw_background (view, region); if (view->canvas) - view->canvas->ops->component.paint (view->canvas, region); + view->canvas->component.ops->paint (view->canvas, region); draw_title (view); if (grub_video_have_common_points (&view->progress_message_frame, region)) draw_message (view); diff --git a/include/grub/gui.h b/include/grub/gui.h index 385c0962b..873d29e76 100644 --- a/include/grub/gui.h +++ b/include/grub/gui.h @@ -55,14 +55,13 @@ struct grub_gui_component_ops grub_gui_container_t (*get_parent) (void *self); void (*set_bounds) (void *self, const grub_video_rect_t *bounds); void (*get_bounds) (void *self, grub_video_rect_t *bounds); - void (*get_preferred_size) (void *self, int *width, int *height); + void (*get_minimal_size) (void *self, unsigned *width, unsigned *height); grub_err_t (*set_property) (void *self, const char *name, const char *value); void (*repaint) (void *self, int second_pass); }; struct grub_gui_container_ops { - struct grub_gui_component_ops component; void (*add) (void *self, grub_gui_component_t comp); void (*remove) (void *self, grub_gui_component_t comp); void (*iterate_children) (void *self, @@ -71,24 +70,78 @@ struct grub_gui_container_ops struct grub_gui_list_ops { - struct grub_gui_component_ops component_ops; void (*set_view_info) (void *self, const char *theme_path, grub_gfxmenu_model_t menu); }; +typedef grub_uint32_t grub_fixed_unsigned_t; +#define GRUB_FIXED_1 0x10000 + +static inline unsigned +grub_fixed_ufu_divide (grub_uint32_t a, grub_fixed_unsigned_t b) +{ + return (a << 16) / b; +} + +static inline grub_fixed_unsigned_t +grub_fixed_fuf_divide (grub_fixed_unsigned_t a, grub_uint32_t b) +{ + return a / b; +} + +static inline unsigned +grub_fixed_ufu_multiply (grub_uint32_t a, grub_fixed_unsigned_t b) +{ + return (a * b) >> 16; +} + +static inline unsigned +grub_fixed_to_unsigned (grub_fixed_unsigned_t in) +{ + return in >> 16; +} + +static inline grub_fixed_unsigned_t +grub_unsigned_to_fixed (unsigned in) +{ + return in << 16; +} + struct grub_gui_component { struct grub_gui_component_ops *ops; + int isxfrac:1; + int isyfrac:1; + int iswfrac:1; + int ishfrac:1; + union { + unsigned x; + grub_fixed_unsigned_t xfrac; + }; + union { + unsigned y; + grub_fixed_unsigned_t yfrac; + }; + union { + unsigned w; + grub_fixed_unsigned_t wfrac; + }; + union { + unsigned h; + grub_fixed_unsigned_t hfrac; + }; }; struct grub_gui_container { + struct grub_gui_component component; struct grub_gui_container_ops *ops; }; struct grub_gui_list { + struct grub_gui_component component; struct grub_gui_list_ops *ops; }; diff --git a/include/grub/gui_string_util.h b/include/grub/gui_string_util.h index 7b5fbb3ea..1baa2eede 100644 --- a/include/grub/gui_string_util.h +++ b/include/grub/gui_string_util.h @@ -34,6 +34,4 @@ int grub_gui_get_named_color (const char *name, grub_gui_color_t *color); grub_err_t grub_gui_parse_color (const char *s, grub_gui_color_t *color); -grub_err_t grub_gui_parse_2_tuple (const char *s, int *px, int *py); - #endif /* GRUB_GUI_STRING_UTIL_HEADER */ diff --git a/include/grub/video.h b/include/grub/video.h index 833df04c8..868e87871 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -160,10 +160,10 @@ struct grub_video_mode_info /* A 2D rectangle type. */ struct grub_video_rect { - int x; - int y; - int width; - int height; + unsigned x; + unsigned y; + unsigned width; + unsigned height; }; typedef struct grub_video_rect grub_video_rect_t; From 7a68c375f36455f16d5aeae14d9055bb164537aa Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 29 Dec 2009 17:57:20 +0100 Subject: [PATCH 41/67] Fix warnings --- gfxmenu/gfxmenu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gfxmenu/gfxmenu.c b/gfxmenu/gfxmenu.c index 1fe6e7297..1db96a80f 100644 --- a/gfxmenu/gfxmenu.c +++ b/gfxmenu/gfxmenu.c @@ -39,13 +39,13 @@ grub_gfxmenu_view_t cached_view; -void +static void grub_gfxmenu_viewer_fini (void *data __attribute__ ((unused))) { } /* FIXME: Previously 't' changed to text menu is it necessary? */ -grub_err_t +static grub_err_t grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) { grub_gfxmenu_view_t view = NULL; @@ -76,8 +76,8 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) } if (!cached_view || grub_strcmp (cached_view->theme_path, theme_path) != 0 - || cached_view->screen.width != (int) mode_info.width - || cached_view->screen.height != (int) mode_info.height) + || cached_view->screen.width != mode_info.width + || cached_view->screen.height != mode_info.height) { grub_free (cached_view); /* Create the view. */ From f8882fe8f92af456ebd629038d931276bdb0a1ff Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 29 Dec 2009 22:50:38 +0100 Subject: [PATCH 42/67] Fix mismerge --- normal/menu.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/normal/menu.c b/normal/menu.c index 850350edd..17730eff3 100644 --- a/normal/menu.c +++ b/normal/menu.c @@ -232,9 +232,6 @@ menu_fini (void) viewers = NULL; } -/* FIXME: allow text menu in parallel with gfxmenu. */ -grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu, - int nested) = NULL; static void menu_init (int entry, grub_menu_t menu, int nested) { From b9da1700808ea5d8492aaf7c9daa0dcc048e5271 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 5 Jan 2010 19:38:11 +0100 Subject: [PATCH 43/67] Preliminary support for mixed percent and linear declarations --- gfxmenu/gui_box.c | 50 ++++++++----------- gfxmenu/gui_canvas.c | 66 +++++++++++++------------ gfxmenu/theme_loader.c | 108 +++++++++++++++-------------------------- include/grub/gui.h | 58 +++++++++------------- 4 files changed, 117 insertions(+), 165 deletions(-) diff --git a/gfxmenu/gui_box.c b/gfxmenu/gui_box.c index 45028e5b1..38b15f96d 100644 --- a/gfxmenu/gui_box.c +++ b/gfxmenu/gui_box.c @@ -93,7 +93,7 @@ layout_horizontally (grub_gui_box_t self, int modify_layout, struct component_node *cur; unsigned w = 0, mwfrac = 0, h = 0, x = 0; - grub_fixed_unsigned_t wfrac = 0; + grub_fixed_signed_t wfrac = 0; int bogus_frac = 0; for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) @@ -104,17 +104,14 @@ layout_horizontally (grub_gui_box_t self, int modify_layout, if (c->ops->get_minimal_size) c->ops->get_minimal_size (c, &mw, &mh); - if (!c->ishfrac && c->h > h) + if (c->h > (signed) h) h = c->h; if (mh > h) h = mh; - if (!c->iswfrac) - w += mw > c->w ? mw : c->w; - if (c->iswfrac) - { - wfrac += c->wfrac; - mwfrac += mw; - } + wfrac += c->wfrac; + w += c->w; + if (mw - c->w > 0) + mwfrac += mw - c->w; } if (wfrac > GRUB_FIXED_1 || (w > 0 && wfrac == GRUB_FIXED_1)) bogus_frac = 1; @@ -122,7 +119,7 @@ layout_horizontally (grub_gui_box_t self, int modify_layout, if (min_width) { if (wfrac < GRUB_FIXED_1) - *min_width = grub_fixed_ufu_divide (w, GRUB_FIXED_1 - wfrac); + *min_width = grub_fixed_sfs_divide (w, GRUB_FIXED_1 - wfrac); else *min_width = w; if (*min_width < w + mwfrac) @@ -142,16 +139,14 @@ layout_horizontally (grub_gui_box_t self, int modify_layout, r.x = x; r.y = 0; - r.width = 32; r.height = h; if (c->ops->get_minimal_size) c->ops->get_minimal_size (c, &mw, &mh); - if (!c->iswfrac) - r.width = c->w; - if (c->iswfrac && !bogus_frac) - r.width = grub_fixed_ufu_multiply (self->bounds.width, c->wfrac); + r.width = c->w; + if (!bogus_frac) + r.width += grub_fixed_sfs_multiply (self->bounds.width, c->wfrac); if (r.width < mw) r.width = mw; @@ -171,7 +166,7 @@ layout_vertically (grub_gui_box_t self, int modify_layout, struct component_node *cur; unsigned h = 0, mhfrac = 0, w = 0, y = 0; - grub_fixed_unsigned_t hfrac = 0; + grub_fixed_signed_t hfrac = 0; int bogus_frac = 0; for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) @@ -182,17 +177,14 @@ layout_vertically (grub_gui_box_t self, int modify_layout, if (c->ops->get_minimal_size) c->ops->get_minimal_size (c, &mw, &mh); - if (!c->iswfrac && c->w > w) + if (c->w > (signed) w) w = c->w; if (mw > w) w = mw; - if (!c->ishfrac) - h += mh > c->h ? mh : c->h; - if (c->ishfrac) - { - hfrac += c->hfrac; - mhfrac += mh; - } + hfrac += c->hfrac; + h += c->h; + if (mh - c->h > 0) + mhfrac += mh - c->h; } if (hfrac > GRUB_FIXED_1 || (h > 0 && hfrac == GRUB_FIXED_1)) bogus_frac = 1; @@ -200,7 +192,7 @@ layout_vertically (grub_gui_box_t self, int modify_layout, if (min_height) { if (hfrac < GRUB_FIXED_1) - *min_height = grub_fixed_ufu_divide (h, GRUB_FIXED_1 - hfrac); + *min_height = grub_fixed_sfs_divide (h, GRUB_FIXED_1 - hfrac); else *min_height = h; if (*min_height < h + mhfrac) @@ -221,15 +213,13 @@ layout_vertically (grub_gui_box_t self, int modify_layout, r.x = 0; r.y = y; r.width = w; - r.height = 32; if (c->ops->get_minimal_size) c->ops->get_minimal_size (c, &mw, &mh); - if (!c->ishfrac) - r.height = c->h; - if (c->ishfrac) - r.height = grub_fixed_ufu_multiply (self->bounds.height, c->hfrac); + r.height = c->h; + if (!bogus_frac) + r.height += grub_fixed_sfs_multiply (self->bounds.height, c->hfrac); if (r.height < mh) r.height = mh; diff --git a/gfxmenu/gui_canvas.c b/gfxmenu/gui_canvas.c index 8b55b2a73..b3919c2d3 100644 --- a/gfxmenu/gui_canvas.c +++ b/gfxmenu/gui_canvas.c @@ -88,49 +88,51 @@ canvas_paint (void *vself, const grub_video_rect_t *region) { grub_video_rect_t r; grub_gui_component_t comp; + signed x, y, w, h; comp = cur->component; - r.x = 0; - r.y = 0; - r.width = 32; - r.height = 32; - - if (!comp->iswfrac && comp->w) - r.width = comp->w; - - if (!comp->ishfrac && comp->h) - r.height = comp->h; - - if (!comp->isxfrac && comp->x) - r.x = comp->x; - - if (!comp->isyfrac && comp->y) - r.y = comp->y; - - if (comp->ishfrac && comp->hfrac) - r.height = grub_fixed_ufu_multiply (self->bounds.height, comp->hfrac); - - if (comp->iswfrac && comp->wfrac) - r.width = grub_fixed_ufu_multiply (self->bounds.width, comp->wfrac); - - if (comp->isxfrac && comp->xfrac) - r.x = grub_fixed_ufu_multiply (self->bounds.width, comp->xfrac); - - if (comp->isyfrac && comp->yfrac) - r.y = grub_fixed_ufu_multiply (self->bounds.height, comp->yfrac); + w = grub_fixed_sfs_multiply (self->bounds.width, comp->wfrac) + comp->w; + h = grub_fixed_sfs_multiply (self->bounds.height, comp->hfrac) + comp->h; + x = grub_fixed_sfs_multiply (self->bounds.width, comp->xfrac) + comp->x; + y = grub_fixed_sfs_multiply (self->bounds.height, comp->yfrac) + comp->y; if (comp->ops->get_minimal_size) { unsigned mw; unsigned mh; comp->ops->get_minimal_size (comp, &mw, &mh); - if (r.width < mw) - r.width = mw; - if (r.height < mh) - r.height = mh; + if (w < (signed) mw) + w = mw; + if (h < (signed) mh) + h = mh; } + /* Sanity checks. */ + if (w <= 0) + w = 32; + if (h <= 0) + h = 32; + + if (x >= (signed) self->bounds.width) + x = self->bounds.width - 32; + if (y >= (signed) self->bounds.height) + y = self->bounds.height - 32; + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + if (x + w >= (signed) self->bounds.width) + w = self->bounds.width - x; + if (y + h >= (signed) self->bounds.height) + h = self->bounds.height - y; + + r.x = x; + r.y = y; + r.width = w; + r.height = h; comp->ops->set_bounds (comp, &r); /* Paint the child. */ diff --git a/gfxmenu/theme_loader.c b/gfxmenu/theme_loader.c index 29bc1d2a6..09637d6b4 100644 --- a/gfxmenu/theme_loader.c +++ b/gfxmenu/theme_loader.c @@ -361,6 +361,40 @@ read_expression (struct parsebuf *p) return grub_new_substring (p->buf, start, end); } +static grub_err_t +parse_proportional_spec (char *value, signed *abs, grub_fixed_signed_t *prop) +{ + signed num; + char *ptr; + int sig = 0; + *abs = 0; + *prop = 0; + ptr = value; + while (*ptr) + { + sig = 0; + + while (*ptr == '-' || *ptr == '+') + { + if (*ptr == '-') + sig = !sig; + ptr++; + } + + num = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + return grub_errno; + if (sig) + num = -num; + if (*ptr == '%') + *prop += grub_fixed_fsf_divide (grub_signed_to_fixed (num), 100); + else + *abs += num; + } + return GRUB_ERR_NONE; +} + + /* Read a GUI object specification from the theme file. Any components created will be added to the GUI container PARENT. */ static grub_err_t @@ -511,78 +545,16 @@ read_object (struct parsebuf *p, grub_gui_container_t parent) /* Handle the property value. */ if (grub_strcmp (property, "left") == 0) - { - unsigned num; - char *ptr; - num = grub_strtoul (value, &ptr, 0); - if (*ptr == '%') - { - component->isxfrac = 1; - component->xfrac - = grub_fixed_fuf_divide (grub_unsigned_to_fixed (num), 100); - } - else - { - component->isxfrac = 0; - component->x = num; - } - } + parse_proportional_spec (value, &component->x, &component->xfrac); else if (grub_strcmp (property, "top") == 0) - { - unsigned num; - char *ptr; - num = grub_strtoul (value, &ptr, 0); - if (*ptr == '%') - { - component->isyfrac = 1; - component->yfrac - = grub_fixed_fuf_divide (grub_unsigned_to_fixed (num), 100); - } - else - { - component->isyfrac = 0; - component->y = num; - } - } + parse_proportional_spec (value, &component->y, &component->yfrac); else if (grub_strcmp (property, "width") == 0) - { - unsigned num; - char *ptr; - num = grub_strtoul (value, &ptr, 0); - if (*ptr == '%') - { - component->iswfrac = 1; - component->wfrac - = grub_fixed_fuf_divide (grub_unsigned_to_fixed (num), 100); - } - else - { - component->iswfrac = 0; - component->w = num; - } - } + parse_proportional_spec (value, &component->w, &component->wfrac); else if (grub_strcmp (property, "height") == 0) - { - unsigned num; - char *ptr; - num = grub_strtoul (value, &ptr, 0); - if (*ptr == '%') - { - component->ishfrac = 1; - component->hfrac - = grub_fixed_fuf_divide (grub_unsigned_to_fixed (num), 100); - } - else - { - component->ishfrac = 0; - component->h = num; - } - } + parse_proportional_spec (value, &component->h, &component->hfrac); else - { - /* General property handling. */ - component->ops->set_property (component, property, value); - } + /* General property handling. */ + component->ops->set_property (component, property, value); grub_free (value); grub_free (property); diff --git a/include/grub/gui.h b/include/grub/gui.h index 873d29e76..7c4774838 100644 --- a/include/grub/gui.h +++ b/include/grub/gui.h @@ -75,62 +75,50 @@ struct grub_gui_list_ops grub_gfxmenu_model_t menu); }; -typedef grub_uint32_t grub_fixed_unsigned_t; +typedef signed grub_fixed_signed_t; #define GRUB_FIXED_1 0x10000 -static inline unsigned -grub_fixed_ufu_divide (grub_uint32_t a, grub_fixed_unsigned_t b) +static inline signed +grub_fixed_sfs_divide (signed a, grub_fixed_signed_t b) { - return (a << 16) / b; + return (a * GRUB_FIXED_1) / b; } -static inline grub_fixed_unsigned_t -grub_fixed_fuf_divide (grub_fixed_unsigned_t a, grub_uint32_t b) +static inline grub_fixed_signed_t +grub_fixed_fsf_divide (grub_fixed_signed_t a, signed b) { return a / b; } -static inline unsigned -grub_fixed_ufu_multiply (grub_uint32_t a, grub_fixed_unsigned_t b) +static inline signed +grub_fixed_sfs_multiply (signed a, grub_fixed_signed_t b) { - return (a * b) >> 16; + return (a * b) / GRUB_FIXED_1; } -static inline unsigned -grub_fixed_to_unsigned (grub_fixed_unsigned_t in) +static inline signed +grub_fixed_to_signed (grub_fixed_signed_t in) { - return in >> 16; + return in / GRUB_FIXED_1; } -static inline grub_fixed_unsigned_t -grub_unsigned_to_fixed (unsigned in) +static inline grub_fixed_signed_t +grub_signed_to_fixed (signed in) { - return in << 16; + return in * GRUB_FIXED_1; } struct grub_gui_component { struct grub_gui_component_ops *ops; - int isxfrac:1; - int isyfrac:1; - int iswfrac:1; - int ishfrac:1; - union { - unsigned x; - grub_fixed_unsigned_t xfrac; - }; - union { - unsigned y; - grub_fixed_unsigned_t yfrac; - }; - union { - unsigned w; - grub_fixed_unsigned_t wfrac; - }; - union { - unsigned h; - grub_fixed_unsigned_t hfrac; - }; + signed x; + grub_fixed_signed_t xfrac; + signed y; + grub_fixed_signed_t yfrac; + signed w; + grub_fixed_signed_t wfrac; + signed h; + grub_fixed_signed_t hfrac; }; struct grub_gui_container From 6812d2e72d05e88645c8daabf72c3848170a5b91 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 5 Jan 2010 21:06:27 +0100 Subject: [PATCH 44/67] Fix non-skipping of percent sign --- gfxmenu/theme_loader.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gfxmenu/theme_loader.c b/gfxmenu/theme_loader.c index 09637d6b4..3854c6c53 100644 --- a/gfxmenu/theme_loader.c +++ b/gfxmenu/theme_loader.c @@ -387,7 +387,10 @@ parse_proportional_spec (char *value, signed *abs, grub_fixed_signed_t *prop) if (sig) num = -num; if (*ptr == '%') - *prop += grub_fixed_fsf_divide (grub_signed_to_fixed (num), 100); + { + *prop += grub_fixed_fsf_divide (grub_signed_to_fixed (num), 100); + ptr++; + } else *abs += num; } From be42af388421dcb922fb8b55388f2b852df4d275 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 5 Jan 2010 21:07:06 +0100 Subject: [PATCH 45/67] Compute list size automatically --- gfxmenu/gui_list.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/gfxmenu/gui_list.c b/gfxmenu/gui_list.c index c55cfd85c..b4886a2cc 100644 --- a/gfxmenu/gui_list.c +++ b/gfxmenu/gui_list.c @@ -53,8 +53,6 @@ struct grub_gui_list_impl grub_gfxmenu_box_t scrollbar_thumb; int scrollbar_width; - int min_items_shown; - int max_items_shown; int first_shown_index; int need_to_recreate_boxes; @@ -91,12 +89,16 @@ list_destroy (void *vself) static int get_num_shown_items (list_impl_t self) { - int n = grub_gfxmenu_model_get_num_entries (self->menu); - if (self->min_items_shown != -1 && n < self->min_items_shown) - n = self->min_items_shown; - if (self->max_items_shown != -1 && n > self->max_items_shown) - n = self->max_items_shown; - return n; + int boxpad = self->item_padding; + int item_vspace = self->item_spacing; + int item_height = self->item_height; + + grub_gfxmenu_box_t box = self->menu_box; + int box_top_pad = box->get_top_pad (box); + int box_bottom_pad = box->get_bottom_pad (box); + + return (self->bounds.height + item_vspace - 2 * boxpad + - box_top_pad - box_bottom_pad) / (item_height + item_vspace); } static int @@ -364,15 +366,22 @@ list_get_minimal_size (void *vself, unsigned *width, unsigned *height) int boxpad = self->item_padding; int item_vspace = self->item_spacing; int item_height = self->item_height; - int num_items = get_num_shown_items (self); + int num_items = 3; grub_gfxmenu_box_t box = self->menu_box; int box_left_pad = box->get_left_pad (box); int box_top_pad = box->get_top_pad (box); int box_right_pad = box->get_right_pad (box); int box_bottom_pad = box->get_bottom_pad (box); + unsigned width_s; + + *width = grub_font_get_string_width (self->item_font, "Typical OS"); + width_s = grub_font_get_string_width (self->selected_item_font, + "Typical OS"); + if (*width < width_s) + *width = width_s; - *width = 400 + 2 * boxpad + box_left_pad + box_right_pad; + *width += 2 * boxpad + box_left_pad + box_right_pad; /* Set the menu box height to fit the items. */ *height = (item_height * num_items @@ -485,14 +494,6 @@ list_set_property (void *vself, const char *name, const char *value) { self->draw_scrollbar = grub_strcmp (value, "false") != 0; } - else if (grub_strcmp (name, "min_items_shown") == 0) - { - self->min_items_shown = grub_strtol (value, 0, 10); - } - else if (grub_strcmp (name, "max_items_shown") == 0) - { - self->max_items_shown = grub_strtol (value, 0, 10); - } else if (grub_strcmp (name, "theme_dir") == 0) { self->need_to_recreate_boxes = 1; @@ -581,8 +582,6 @@ grub_gui_list_new (void) self->scrollbar_thumb_pattern = 0; self->scrollbar_width = 16; - self->min_items_shown = -1; - self->max_items_shown = -1; self->first_shown_index = 0; self->need_to_recreate_boxes = 0; From eb1c959440899c2bfd7dbc514b5ec11b17a2a283 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 5 Jan 2010 21:24:33 +0100 Subject: [PATCH 46/67] grub-mkconfig support for themes --- util/grub-mkconfig.in | 1 + util/grub.d/00_header.in | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in index 49e52b313..7e667fb3e 100644 --- a/util/grub-mkconfig.in +++ b/util/grub-mkconfig.in @@ -220,6 +220,7 @@ export GRUB_DEFAULT \ GRUB_DISABLE_LINUX_UUID \ GRUB_DISABLE_LINUX_RECOVERY \ GRUB_GFXMODE \ + GRUB_THEME \ GRUB_DISABLE_OS_PROBER if test "x${grub_cfg}" != "x"; then diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in index 0adfe6b76..da394783a 100644 --- a/util/grub.d/00_header.in +++ b/util/grub.d/00_header.in @@ -93,6 +93,15 @@ if loadfont `make_system_path_relative_to_its_root ${GRUB_FONT_PATH}` ; then # understand terminal_output terminal gfxterm fi +EOF +if [ x$GRUB_THEME != x ] && [ -f $GRUB_THEME ] \ + && is_path_readable_by_grub $GRUB_THEME; then + echo "Found theme: $GRUB_THEME" >&2 + prepare_grub_to_access_device `${grub_probe} --target=device $GRUB_THEME` + echo "insmod gfxmenu" + echo "set theme=(\$root)/`make_system_path_relative_to_its_root $GRUB_THEME`" +fi + cat << EOF fi EOF ;; From b9d28aa05fdd761074189b0acb1f3fd666f3894e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 5 Jan 2010 23:22:02 +0100 Subject: [PATCH 47/67] Fix missing viewport in gui_list --- gfxmenu/gui_list.c | 82 +++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/gfxmenu/gui_list.c b/gfxmenu/gui_list.c index b4886a2cc..fd0f11635 100644 --- a/gfxmenu/gui_list.c +++ b/gfxmenu/gui_list.c @@ -209,7 +209,8 @@ draw_scrollbar (list_impl_t self, /* Draw the list of items. */ static void -draw_menu (list_impl_t self) +draw_menu (list_impl_t self, int width, int drawing_scrollbar, + int num_shown_items) { if (! self->menu_box || ! self->selected_item_box) return; @@ -222,38 +223,19 @@ draw_menu (list_impl_t self) int descent = grub_font_get_descent (self->item_font); int item_height = self->item_height; - int total_num_items = grub_gfxmenu_model_get_num_entries (self->menu); - int num_shown_items = get_num_shown_items (self); - grub_gfxmenu_box_t box = self->menu_box; - int width = self->bounds.width; - int height = self->bounds.height; - - int box_left_pad = box->get_left_pad (box); - int box_top_pad = box->get_top_pad (box); - int box_right_pad = box->get_right_pad (box); - int box_bottom_pad = box->get_bottom_pad (box); - - box->set_content_size (box, - width - box_left_pad - box_right_pad, - height - box_top_pad - box_bottom_pad); - - box->draw (box, 0, 0); - make_selected_item_visible (self); - int drawing_scrollbar = (self->draw_scrollbar - && (num_shown_items < total_num_items) - && check_scrollbar (self)); - int scrollbar_h_space = drawing_scrollbar ? self->scrollbar_width : 0; - int item_top = box_top_pad + boxpad; - int item_left = box_left_pad + boxpad; + grub_gfxmenu_box_t selbox = self->selected_item_box; + int sel_leftpad = selbox->get_left_pad (selbox); + int item_top = boxpad; + int item_left = boxpad + sel_leftpad; int menu_index; int visible_index; for (visible_index = 0, menu_index = self->first_shown_index; - visible_index < num_shown_items && menu_index < total_num_items; + visible_index < num_shown_items && menu_index < self->menu->size; visible_index++, menu_index++) { int is_selected = @@ -261,12 +243,9 @@ draw_menu (list_impl_t self) if (is_selected) { - grub_gfxmenu_box_t selbox = self->selected_item_box; - int sel_leftpad = selbox->get_left_pad (selbox); int sel_toppad = selbox->get_top_pad (selbox); selbox->set_content_size (selbox, (width - 2 * boxpad - - box_left_pad - box_right_pad - scrollbar_h_space), item_height); selbox->draw (selbox, @@ -300,14 +279,6 @@ draw_menu (list_impl_t self) item_top += item_height + item_vspace; } - - if (drawing_scrollbar) - draw_scrollbar (self, - self->first_shown_index, num_shown_items, - 0, total_num_items, - width - box_right_pad + self->scrollbar_width, - box_top_pad + boxpad, - height - box_top_pad - box_bottom_pad); } static void @@ -323,8 +294,45 @@ list_paint (void *vself, const grub_video_rect_t *region) check_boxes (self); + if (! self->menu_box || ! self->selected_item_box) + return; + grub_gui_set_viewport (&self->bounds, &vpsave); - draw_menu (self); + { + grub_gfxmenu_box_t box = self->menu_box; + int box_left_pad = box->get_left_pad (box); + int box_top_pad = box->get_top_pad (box); + int box_right_pad = box->get_right_pad (box); + int box_bottom_pad = box->get_bottom_pad (box); + grub_video_rect_t vpsave2, content_rect; + int num_shown_items = get_num_shown_items (self); + int drawing_scrollbar = (self->draw_scrollbar + && (num_shown_items < self->menu->size) + && check_scrollbar (self)); + + content_rect.x = box_left_pad; + content_rect.y = box_top_pad; + content_rect.width = self->bounds.width - box_left_pad - box_right_pad; + content_rect.height = self->bounds.height - box_top_pad - box_bottom_pad; + + box->set_content_size (box, content_rect.width, content_rect.height); + + box->draw (box, 0, 0); + + grub_gui_set_viewport (&content_rect, &vpsave2); + draw_menu (self, content_rect.width, drawing_scrollbar, num_shown_items); + grub_gui_restore_viewport (&vpsave2); + + if (drawing_scrollbar) + draw_scrollbar (self, + self->first_shown_index, num_shown_items, + 0, self->menu->size, + content_rect.width - box_right_pad + + self->scrollbar_width, + box_top_pad + self->item_padding, + content_rect.height - box_top_pad - box_bottom_pad); + } + grub_gui_restore_viewport (&vpsave); } From ea51afb099a6a88288f6b4f0800b16e0ca76d9dc Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 5 Jan 2010 23:49:40 +0100 Subject: [PATCH 48/67] Use pixmapbar only when images available --- gfxmenu/gui_progress_bar.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gfxmenu/gui_progress_bar.c b/gfxmenu/gui_progress_bar.c index 9af93cff5..95be91e2a 100644 --- a/gfxmenu/gui_progress_bar.c +++ b/gfxmenu/gui_progress_bar.c @@ -46,6 +46,7 @@ struct grub_gui_progress_bar char *theme_dir; int need_to_recreate_pixmaps; + int pixmapbar_available; char *bar_pattern; char *highlight_pattern; grub_gfxmenu_box_t bar_box; @@ -77,6 +78,8 @@ progress_bar_is_instance (void *vself __attribute__((unused)), const char *type) static int check_pixmaps (grub_gui_progress_bar_t self) { + if (!self->pixmapbar_available) + return 0; if (self->need_to_recreate_pixmaps) { grub_gui_recreate_box (&self->bar_box, @@ -137,6 +140,7 @@ draw_pixmap_bar (grub_gui_progress_bar_t self) int bar_v_pad = bar_t_pad + bar_b_pad; int tracklen = w - bar_h_pad; int trackheight = h - bar_v_pad; + bar->set_content_size (bar, tracklen, trackheight); int barwidth = (tracklen @@ -172,12 +176,16 @@ static void progress_bar_paint (void *vself, const grub_video_rect_t *region) { grub_gui_progress_bar_t self = vself; + grub_video_rect_t vpsave; + if (! self->visible) return; if (!grub_video_have_common_points (region, &self->bounds)) return; - grub_video_rect_t vpsave; + if (self->end == self->start) + return; + grub_gui_set_viewport (&self->bounds, &vpsave); if (check_pixmaps (self)) @@ -272,12 +280,14 @@ progress_bar_set_property (void *vself, const char *name, const char *value) else if (grub_strcmp (name, "bar_style") == 0) { self->need_to_recreate_pixmaps = 1; + self->pixmapbar_available = 1; grub_free (self->bar_pattern); self->bar_pattern = value ? grub_strdup (value) : 0; } else if (grub_strcmp (name, "highlight_style") == 0) { self->need_to_recreate_pixmaps = 1; + self->pixmapbar_available = 1; grub_free (self->highlight_pattern); self->highlight_pattern = value ? grub_strdup (value) : 0; } From 4d253049d5139b34e35154e74850d3c68e4d0b8b Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 6 Jan 2010 01:42:21 +0100 Subject: [PATCH 49/67] Fix non-clearing of timeout. Template support for timeout text. --- gfxmenu/gui_circular_progress.c | 39 +++++++------- gfxmenu/gui_progress_bar.c | 96 +++++++++++++++++++++------------ gfxmenu/view.c | 44 ++++++--------- include/grub/gui.h | 11 ++++ normal/menu.c | 2 + 5 files changed, 110 insertions(+), 82 deletions(-) diff --git a/gfxmenu/gui_circular_progress.c b/gfxmenu/gui_circular_progress.c index 7634c368d..9a859ee2e 100644 --- a/gfxmenu/gui_circular_progress.c +++ b/gfxmenu/gui_circular_progress.c @@ -28,7 +28,7 @@ struct grub_gui_circular_progress { - struct grub_gui_component comp; + struct grub_gui_progress progress; grub_gui_container_t parent; grub_video_rect_t bounds; @@ -215,19 +215,7 @@ static grub_err_t circprog_set_property (void *vself, const char *name, const char *value) { circular_progress_t self = vself; - if (grub_strcmp (name, "value") == 0) - { - self->value = grub_strtol (value, 0, 10); - } - else if (grub_strcmp (name, "start") == 0) - { - self->start = grub_strtol (value, 0, 10); - } - else if (grub_strcmp (name, "end") == 0) - { - self->end = grub_strtol (value, 0, 10); - } - else if (grub_strcmp (name, "num_ticks") == 0) + if (grub_strcmp (name, "num_ticks") == 0) { self->num_ticks = grub_strtol (value, 0, 10); } @@ -257,10 +245,6 @@ circprog_set_property (void *vself, const char *name, const char *value) grub_free (self->theme_dir); self->theme_dir = value ? grub_strdup (value) : 0; } - else if (grub_strcmp (name, "visible") == 0) - { - self->visible = grub_strcmp (value, "false") != 0; - } else if (grub_strcmp (name, "id") == 0) { grub_free (self->id); @@ -272,6 +256,17 @@ circprog_set_property (void *vself, const char *name, const char *value) return grub_errno; } +static void +circprog_set_state (void *vself, int visible, int start, + int current, int end) +{ + circular_progress_t self = vself; + self->visible = visible; + self->start = start; + self->value = current; + self->end = end; +} + static struct grub_gui_component_ops circprog_ops = { .destroy = circprog_destroy, @@ -285,6 +280,11 @@ static struct grub_gui_component_ops circprog_ops = .set_property = circprog_set_property }; +static struct grub_gui_progress_ops circprog_prog_ops = + { + .set_state = circprog_set_state + }; + grub_gui_component_t grub_gui_circular_progress_new (void) { @@ -292,7 +292,8 @@ grub_gui_circular_progress_new (void) self = grub_zalloc (sizeof (*self)); if (! self) return 0; - self->comp.ops = &circprog_ops; + self->progress.ops = &circprog_prog_ops; + self->progress.component.ops = &circprog_ops; self->visible = 1; self->num_ticks = 64; self->start_angle = -64; diff --git a/gfxmenu/gui_progress_bar.c b/gfxmenu/gui_progress_bar.c index d982924cb..6a7f43962 100644 --- a/gfxmenu/gui_progress_bar.c +++ b/gfxmenu/gui_progress_bar.c @@ -24,10 +24,11 @@ #include #include #include +#include struct grub_gui_progress_bar { - struct grub_gui_component component; + struct grub_gui_progress progress; grub_gui_container_t parent; grub_video_rect_t bounds; @@ -37,7 +38,7 @@ struct grub_gui_progress_bar int end; int value; int show_text; - char *text; + char *template; grub_font_t font; grub_gui_color_t text_color; grub_gui_color_t border_color; @@ -156,14 +157,20 @@ draw_pixmap_bar (grub_gui_progress_bar_t self) static void draw_text (grub_gui_progress_bar_t self) { - const char *text = self->text; - if (text && self->show_text) + if (self->template) { grub_font_t font = self->font; grub_video_color_t text_color = grub_gui_map_color (self->text_color); int width = self->bounds.width; int height = self->bounds.height; - + char *text = grub_asprintf (self->template, + self->value > 0 ? self->value : -self->value); + if (!text) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return; + } /* Center the text. */ int text_width = grub_font_get_string_width (font, text); int x = (width - text_width) / 2; @@ -228,35 +235,60 @@ progress_bar_get_bounds (void *vself, grub_video_rect_t *bounds) } static void -progress_bar_get_minimal_size (void *vself __attribute__ ((unused)), +progress_bar_get_minimal_size (void *vself, unsigned *width, unsigned *height) { + unsigned text_width = 0, text_height = 0; + grub_gui_progress_bar_t self = vself; + + if (self->template) + { + text_width = grub_font_get_string_width (self->font, self->template); + text_width += grub_font_get_string_width (self->font, "XXXXXXXXXX"); + text_height = grub_font_get_descent (self->font) + + grub_font_get_ascent (self->font); + } *width = 200; + if (*width < text_width) + *width = text_width; *height = 28; + if (*height < text_height) + *height = text_height; +} + +static void +progress_bar_set_state (void *vself, int visible, int start, + int current, int end) +{ + grub_gui_progress_bar_t self = vself; + self->visible = visible; + self->start = start; + self->value = current; + self->end = end; } static grub_err_t progress_bar_set_property (void *vself, const char *name, const char *value) { grub_gui_progress_bar_t self = vself; - if (grub_strcmp (name, "value") == 0) + if (grub_strcmp (name, "text") == 0) { - self->value = grub_strtol (value, 0, 10); - } - else if (grub_strcmp (name, "start") == 0) - { - self->start = grub_strtol (value, 0, 10); - } - else if (grub_strcmp (name, "end") == 0) - { - self->end = grub_strtol (value, 0, 10); - } - else if (grub_strcmp (name, "text") == 0) - { - grub_free (self->text); - if (! value) - value = ""; - self->text = grub_strdup (value); + grub_free (self->template); + if (grub_strcmp (value, "@TIMEOUT_NOTIFICATION_LONG@") == 0) + value + = _("The highlighted entry will be executed automatically in %ds."); + else if (grub_strcmp (value, "@TIMEOUT_NOTIFICATION_MIDDLE@") == 0) + /* TRANSLATORS: 's' stands for seconds. + It's a standalone timeout notification. + Please use the short form in your language. */ + value = _("%ds remaining."); + else if (grub_strcmp (value, "@TIMEOUT_NOTIFICATION_SHORT@") == 0) + /* TRANSLATORS: 's' stands for seconds. + It's a standalone timeout notification. + Please use the shortest form available in you language. */ + value = _("%ds"); + + self->template = grub_strdup (value); } else if (grub_strcmp (name, "font") == 0) { @@ -298,14 +330,6 @@ progress_bar_set_property (void *vself, const char *name, const char *value) grub_free (self->theme_dir); self->theme_dir = value ? grub_strdup (value) : 0; } - else if (grub_strcmp (name, "visible") == 0) - { - self->visible = grub_strcmp (value, "false") != 0; - } - else if (grub_strcmp (name, "show_text") == 0) - { - self->show_text = grub_strcmp (value, "false") != 0; - } else if (grub_strcmp (name, "id") == 0) { grub_free (self->id); @@ -331,6 +355,11 @@ static struct grub_gui_component_ops progress_bar_ops = .set_property = progress_bar_set_property }; +static struct grub_gui_progress_ops progress_bar_pb_ops = + { + .set_state = progress_bar_set_state + }; + grub_gui_component_t grub_gui_progress_bar_new (void) { @@ -338,10 +367,9 @@ grub_gui_progress_bar_new (void) self = grub_zalloc (sizeof (*self)); if (! self) return 0; - self->component.ops = &progress_bar_ops; + self->progress.ops = &progress_bar_pb_ops; + self->progress.component.ops = &progress_bar_ops; self->visible = 1; - self->show_text = 1; - self->text = grub_strdup (""); self->font = grub_font_get ("Helvetica 10"); grub_gui_color_t black = { .red = 0, .green = 0, .blue = 0, .alpha = 255 }; grub_gui_color_t gray = { .red = 128, .green = 128, .blue = 128, .alpha = 255 }; diff --git a/gfxmenu/view.c b/gfxmenu/view.c index 5008b105b..611c01e1b 100644 --- a/gfxmenu/view.c +++ b/gfxmenu/view.c @@ -160,11 +160,10 @@ draw_title (grub_gfxmenu_view_t view) struct progress_value_data { - const char *visible; - const char *start; - const char *end; - const char *value; - const char *text; + int visible; + int start; + int end; + int value; }; static void @@ -174,19 +173,14 @@ update_timeout_visit (grub_gui_component_t component, struct progress_value_data *pv; pv = (struct progress_value_data *) userdata; - component->ops->set_property (component, "visible", pv->visible); - component->ops->set_property (component, "start", pv->start); - component->ops->set_property (component, "end", pv->end); - component->ops->set_property (component, "value", pv->value); - component->ops->set_property (component, "text", pv->text); + ((struct grub_gui_progress *) component)->ops + ->set_state ((struct grub_gui_progress *) component, + pv->visible, pv->start, pv->value, pv->end); } void grub_gfxmenu_print_timeout (int timeout, void *data) { - char valuebuf[sizeof ("-XXXXXXXXXXX")]; - char startbuf[sizeof ("-XXXXXXXXXXX")]; - char msgbuf[120]; struct grub_gfxmenu_view *view = data; struct progress_value_data pv; @@ -205,17 +199,10 @@ grub_gfxmenu_print_timeout (int timeout, void *data) if (view->first_timeout == -1) view->first_timeout = timeout; - pv.visible = "true"; - grub_sprintf (startbuf, "%d", -(view->first_timeout + 1)); - pv.start = startbuf; - pv.end = "0"; - grub_sprintf (valuebuf, "%d", -timeout); - pv.value = valuebuf; - - grub_sprintf (msgbuf, - "The highlighted entry will be booted automatically in %d s.", - timeout); - pv.text = msgbuf; + pv.visible = 1; + pv.start = -(view->first_timeout + 1); + pv.end = 0; + pv.value = -timeout; grub_gui_find_by_id ((grub_gui_component_t) view->canvas, TIMEOUT_COMPONENT_ID, update_timeout_visit, &pv); @@ -244,11 +231,10 @@ grub_gfxmenu_clear_timeout (void *data) grub_gfxmenu_view_redraw (view, &bounds); } - pv.visible = "false"; - pv.start = "1"; - pv.end = "0"; - pv.value = "0"; - pv.text = ""; + pv.visible = 0; + pv.start = 1; + pv.end = 0; + pv.value = 0; grub_gui_find_by_id ((grub_gui_component_t) view->canvas, TIMEOUT_COMPONENT_ID, update_timeout_visit, &pv); diff --git a/include/grub/gui.h b/include/grub/gui.h index 6f8f44805..7bd71acd3 100644 --- a/include/grub/gui.h +++ b/include/grub/gui.h @@ -74,6 +74,11 @@ struct grub_gui_list_ops grub_gfxmenu_view_t view); }; +struct grub_gui_progress_ops +{ + void (*set_state) (void *self, int visible, int start, int current, int end); +}; + typedef signed grub_fixed_signed_t; #define GRUB_FIXED_1 0x10000 @@ -120,6 +125,12 @@ struct grub_gui_component grub_fixed_signed_t hfrac; }; +struct grub_gui_progress +{ + struct grub_gui_component component; + struct grub_gui_progress_ops *ops; +}; + struct grub_gui_container { struct grub_gui_component component; diff --git a/normal/menu.c b/normal/menu.c index 17730eff3..bbd1049e4 100644 --- a/normal/menu.c +++ b/normal/menu.c @@ -362,6 +362,8 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) if (timeout > 0) menu_print_timeout (timeout); + else + clear_timeout (); while (1) { From 2ab45155287b5a6088fab6b65a95069f83904ce9 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 6 Jan 2010 10:50:50 +0100 Subject: [PATCH 50/67] Push error before calling grub_gfxterm_fullscreen --- gfxmenu/gfxmenu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gfxmenu/gfxmenu.c b/gfxmenu/gfxmenu.c index 1db96a80f..a2e765156 100644 --- a/gfxmenu/gfxmenu.c +++ b/gfxmenu/gfxmenu.c @@ -57,21 +57,27 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) theme_path = grub_env_get ("theme"); if (! theme_path) { + grub_error_push (); grub_gfxterm_fullscreen (); + grub_error_pop (); return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no theme specified"); } instance = grub_zalloc (sizeof (*instance)); if (!instance) { + grub_error_push (); grub_gfxterm_fullscreen (); + grub_error_pop (); return grub_errno; } err = grub_video_get_info (&mode_info); if (err) { + grub_error_push (); grub_gfxterm_fullscreen (); + grub_error_pop (); return err; } @@ -88,7 +94,9 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) if (! cached_view) { grub_free (instance); + grub_error_push (); grub_gfxterm_fullscreen (); + grub_error_pop (); return grub_errno; } From cd622720c84608c9ab561f41a689ed58e3804bb4 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 6 Jan 2010 10:51:23 +0100 Subject: [PATCH 51/67] Clear both buffers on gfxterm init --- term/gfxterm.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/term/gfxterm.c b/term/gfxterm.c index 0abe0f07d..26e94e474 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -315,6 +315,7 @@ grub_gfxterm_fullscreen (void) struct grub_video_mode_info mode_info; grub_video_color_t color; grub_err_t err; + int double_redraw; err = grub_video_get_info (&mode_info); /* Figure out what mode we ended up. */ @@ -323,9 +324,17 @@ grub_gfxterm_fullscreen (void) grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + double_redraw = mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); + /* Make sure screen is black. */ color = grub_video_map_rgb (0, 0, 0); grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height); + if (double_redraw) + { + grub_video_swap_buffers (); + grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height); + } bitmap = 0; /* Select the font to use. */ @@ -337,10 +346,7 @@ grub_gfxterm_fullscreen (void) return grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, 0, 0, mode_info.width, mode_info.height, - mode_info.mode_type - & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED - && !(mode_info.mode_type - & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP), + double_redraw, font_name, DEFAULT_BORDER_WIDTH); } From 34d2c9a10faf2abb7d4dc1562b272f692008a878 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 6 Jan 2010 22:19:28 +0100 Subject: [PATCH 52/67] Fix compilation error --- gfxmenu/gui_progress_bar.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gfxmenu/gui_progress_bar.c b/gfxmenu/gui_progress_bar.c index 6a7f43962..550b5d43c 100644 --- a/gfxmenu/gui_progress_bar.c +++ b/gfxmenu/gui_progress_bar.c @@ -163,14 +163,15 @@ draw_text (grub_gui_progress_bar_t self) grub_video_color_t text_color = grub_gui_map_color (self->text_color); int width = self->bounds.width; int height = self->bounds.height; - char *text = grub_asprintf (self->template, - self->value > 0 ? self->value : -self->value); + char *text = grub_malloc (grub_strlen (self->template) + 10); if (!text) { grub_print_error (); grub_errno = GRUB_ERR_NONE; return; } + grub_sprintf (text, self->template, + self->value > 0 ? self->value : -self->value); /* Center the text. */ int text_width = grub_font_get_string_width (font, text); int x = (width - text_width) / 2; From c1b952d3d9a79ad03ded72d8abc58c0190f8a065 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Thu, 7 Jan 2010 18:20:11 +0000 Subject: [PATCH 53/67] 2010-01-07 Robert Millan * util/grub.d/10_hurd.in: Add --class information to menuentries. * util/grub.d/10_kfreebsd.in: Likewise. * util/grub.d/10_linux.in: Likewise. --- ChangeLog.mkconfig | 5 +++++ util/grub.d/10_hurd.in | 7 +++++-- util/grub.d/10_kfreebsd.in | 16 ++++++++++++---- util/grub.d/10_linux.in | 7 +++++-- 4 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 ChangeLog.mkconfig diff --git a/ChangeLog.mkconfig b/ChangeLog.mkconfig new file mode 100644 index 000000000..665c938c7 --- /dev/null +++ b/ChangeLog.mkconfig @@ -0,0 +1,5 @@ +2010-01-07 Robert Millan + + * util/grub.d/10_hurd.in: Add --class information to menuentries. + * util/grub.d/10_kfreebsd.in: Likewise. + * util/grub.d/10_linux.in: Likewise. diff --git a/util/grub.d/10_hurd.in b/util/grub.d/10_hurd.in index c1871e07a..b56c585ee 100644 --- a/util/grub.d/10_hurd.in +++ b/util/grub.d/10_hurd.in @@ -1,7 +1,7 @@ #! /bin/sh -e # grub-mkconfig helper script. -# Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. +# Copyright (C) 2006,2007,2008,2010 Free Software Foundation, Inc. # # GRUB is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,10 +21,13 @@ exec_prefix=@exec_prefix@ libdir=@libdir@ . ${libdir}/grub/grub-mkconfig_lib +CLASS="--class gnu --class os" + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then OS=GNU else OS="${GRUB_DISTRIBUTOR} GNU/Hurd" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]') ${CLASS}" fi at_least_one=false @@ -69,7 +72,7 @@ if ${all_of_them} && test -e /lib/ld.so.1 ; then : ; else fi cat << EOF -menuentry "${OS}" { +menuentry "${OS}" ${CLASS} { EOF prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" cat << EOF diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in index 026f1d7ac..7eb26072c 100644 --- a/util/grub.d/10_kfreebsd.in +++ b/util/grub.d/10_kfreebsd.in @@ -1,7 +1,7 @@ #! /bin/sh -e # grub-mkconfig helper script. -# Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. +# Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. # # GRUB is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,9 +26,17 @@ libdir=@libdir@ export TEXTDOMAIN=@PACKAGE@ export TEXTDOMAINDIR=@LOCALEDIR@ +CLASS="--class os" + case "${GRUB_DISTRIBUTOR}" in - Debian) OS="${GRUB_DISTRIBUTOR} GNU/kFreeBSD" ;; - *) OS="FreeBSD" ;; + Debian) + OS="${GRUB_DISTRIBUTOR} GNU/kFreeBSD" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]') --class gnu-kfreebsd --class gnu ${CLASS}" + ;; + *) + OS="FreeBSD" + CLASS="--class freebsd --class bsd ${CLASS}" + ;; esac kfreebsd_entry () @@ -38,7 +46,7 @@ kfreebsd_entry () recovery="$3" # not used yet args="$4" # not used yet title="$(gettext "%s, with kFreeBSD %s")" - printf "menuentry \"${title}\" {" ${os} ${version} + printf "menuentry \"${title}\" ${CLASS} {" ${os} ${version} save_default_entry | sed -e "s/^/\t/" if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in index dc9696ec8..74d880641 100644 --- a/util/grub.d/10_linux.in +++ b/util/grub.d/10_linux.in @@ -1,7 +1,7 @@ #! /bin/sh -e # grub-mkconfig helper script. -# Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. +# Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. # # GRUB is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,10 +26,13 @@ libdir=@libdir@ export TEXTDOMAIN=@PACKAGE@ export TEXTDOMAINDIR=@LOCALEDIR@ +CLASS="--class gnu-linux --class gnu --class os" + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then OS=GNU/Linux else OS="${GRUB_DISTRIBUTOR} GNU/Linux" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]') ${CLASS}" fi # loop-AES arranges things so that /dev/loop/X can be our root device, but @@ -58,7 +61,7 @@ linux_entry () else title="$(gettext "%s, with Linux %s")" fi - printf "menuentry \"${title}\" {" ${os} ${version} + printf "menuentry \"${title}\" ${CLASS} {" ${os} ${version} save_default_entry | sed -e "s/^/\t/" if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" From b5c72e3b0f2f09274cc67cbc335f1e3ca73f289e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 8 Jan 2010 19:15:49 +0100 Subject: [PATCH 54/67] Fix list scrollbar position miscalculation --- gfxmenu/gui_list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfxmenu/gui_list.c b/gfxmenu/gui_list.c index ccf360ad3..8377bf4bb 100644 --- a/gfxmenu/gui_list.c +++ b/gfxmenu/gui_list.c @@ -327,7 +327,7 @@ list_paint (void *vself, const grub_video_rect_t *region) draw_scrollbar (self, self->first_shown_index, num_shown_items, 0, self->view->menu->size, - content_rect.width - box_right_pad + self->bounds.width - box_right_pad + self->scrollbar_width, box_top_pad + self->item_padding, content_rect.height - box_top_pad - box_bottom_pad); From 2810a4ef1c2462f44da08a66b9337793a2b3fdd5 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 9 Jan 2010 11:48:38 +0100 Subject: [PATCH 55/67] Fix scrollbar height --- gfxmenu/gui_list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfxmenu/gui_list.c b/gfxmenu/gui_list.c index 8377bf4bb..a78339385 100644 --- a/gfxmenu/gui_list.c +++ b/gfxmenu/gui_list.c @@ -330,7 +330,7 @@ list_paint (void *vself, const grub_video_rect_t *region) self->bounds.width - box_right_pad + self->scrollbar_width, box_top_pad + self->item_padding, - content_rect.height - box_top_pad - box_bottom_pad); + self->bounds.height - box_top_pad - box_bottom_pad); } grub_gui_restore_viewport (&vpsave); From 3b6f7ab75d3c4aa8bc59d56b71284ece7c809b5f Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Mon, 11 Jan 2010 19:19:24 +0100 Subject: [PATCH 56/67] Add missing menuviewer initialization. --- util/grub.d/00_header.in | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in index da394783a..306bef3c3 100644 --- a/util/grub.d/00_header.in +++ b/util/grub.d/00_header.in @@ -1,7 +1,7 @@ #! /bin/sh -e # grub-mkconfig helper script. -# Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. +# Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. # # GRUB is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -98,8 +98,11 @@ if [ x$GRUB_THEME != x ] && [ -f $GRUB_THEME ] \ && is_path_readable_by_grub $GRUB_THEME; then echo "Found theme: $GRUB_THEME" >&2 prepare_grub_to_access_device `${grub_probe} --target=device $GRUB_THEME` - echo "insmod gfxmenu" - echo "set theme=(\$root)/`make_system_path_relative_to_its_root $GRUB_THEME`" + cat << EOF +insmod gfxmenu +set theme=(\$root)`make_system_path_relative_to_its_root $GRUB_THEME` +set menuviewer=gfxmenu +EOF fi cat << EOF fi From 6419c43e4f767cd5f3dcf4258c45bd3edcb60efa Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Wed, 20 Jan 2010 13:56:45 +0000 Subject: [PATCH 57/67] Fix indentation in util/grub.d/00_header.in output --- util/grub.d/00_header.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in index 306bef3c3..7cee825d2 100644 --- a/util/grub.d/00_header.in +++ b/util/grub.d/00_header.in @@ -97,11 +97,11 @@ EOF if [ x$GRUB_THEME != x ] && [ -f $GRUB_THEME ] \ && is_path_readable_by_grub $GRUB_THEME; then echo "Found theme: $GRUB_THEME" >&2 - prepare_grub_to_access_device `${grub_probe} --target=device $GRUB_THEME` + prepare_grub_to_access_device `${grub_probe} --target=device $GRUB_THEME` | sed -e "s/^/ /" cat << EOF -insmod gfxmenu -set theme=(\$root)`make_system_path_relative_to_its_root $GRUB_THEME` -set menuviewer=gfxmenu + insmod gfxmenu + set theme=(\$root)`make_system_path_relative_to_its_root $GRUB_THEME` + set menuviewer=gfxmenu EOF fi cat << EOF From 3b205d4ddf7c61363f9868dba14e8b95c22c95b4 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 31 Jan 2010 11:11:03 +0100 Subject: [PATCH 58/67] 2010-01-31 Vladimir Serbinenko * disk/ieee1275/ofdisk.c (grub_ofdisk_iterate): Fix off-by-one error. --- ChangeLog | 4 ++++ disk/ieee1275/ofdisk.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index eced79d59..4598e1b74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2010-01-31 Vladimir Serbinenko + + * disk/ieee1275/ofdisk.c (grub_ofdisk_iterate): Fix off-by-one error. + 2010-01-31 Vladimir Serbinenko * font/font.c (find_glyph): Check that bmp_idx is available before diff --git a/disk/ieee1275/ofdisk.c b/disk/ieee1275/ofdisk.c index c8c4d1a4e..051ece0b9 100644 --- a/disk/ieee1275/ofdisk.c +++ b/disk/ieee1275/ofdisk.c @@ -118,7 +118,7 @@ grub_ofdisk_iterate (int (*hook) (const char *name)) static char * compute_dev_path (const char *name) { - char *devpath = grub_malloc (grub_strlen (name) + 2); + char *devpath = grub_malloc (grub_strlen (name) + 3); char *p, c; if (!devpath) From 996649b073c98b4f13d2908cf887f4bd52d2ce5f Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 3 Feb 2010 00:43:55 +0100 Subject: [PATCH 59/67] 2010-02-03 Vladimir Serbinenko * disk/i386/pc/biosdisk.c (grub_biosdisk_read): Handle non-2048 aligned CDROM reads. (grub_biosdisk_write): Refuse to write to CDROM. --- ChangeLog | 6 ++++++ disk/i386/pc/biosdisk.c | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 4598e1b74..83d0c58a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2010-02-03 Vladimir Serbinenko + + * disk/i386/pc/biosdisk.c (grub_biosdisk_read): Handle non-2048 aligned + CDROM reads. + (grub_biosdisk_write): Refuse to write to CDROM. + 2010-01-31 Vladimir Serbinenko * disk/ieee1275/ofdisk.c (grub_ofdisk_iterate): Fix off-by-one error. diff --git a/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c index 682474b1a..94d0e3708 100644 --- a/disk/i386/pc/biosdisk.c +++ b/disk/i386/pc/biosdisk.c @@ -307,8 +307,17 @@ grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, while (size) { grub_size_t len; + grub_size_t cdoff = 0; len = get_safe_sectors (sector, data->sectors); + + if (data->flags & GRUB_BIOSDISK_FLAG_CDROM) + { + cdoff = (sector & 3) << GRUB_DISK_SECTOR_BITS; + len = ALIGN_UP (sector + len, 4) - (sector & ~3); + sector &= ~3; + } + if (len > size) len = size; @@ -316,7 +325,7 @@ grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, GRUB_MEMORY_MACHINE_SCRATCH_SEG)) return grub_errno; - grub_memcpy (buf, (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, + grub_memcpy (buf, (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + cdoff), len << GRUB_DISK_SECTOR_BITS); buf += len << GRUB_DISK_SECTOR_BITS; sector += len; @@ -332,6 +341,9 @@ grub_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector, { struct grub_biosdisk_data *data = disk->data; + if (data->flags & GRUB_BIOSDISK_FLAG_CDROM) + return grub_error (GRUB_ERR_IO, "can't write to CDROM"); + while (size) { grub_size_t len; From 399f6e4d9cf9c1a3aedf2a113f81680e03395c08 Mon Sep 17 00:00:00 2001 From: Torsten Landschoff Date: Wed, 3 Feb 2010 00:46:55 +0100 Subject: [PATCH 60/67] 2010-02-03 Torsten Landschoff * kern/disk.c (grub_disk_read): Fix offset computation when reading last sectors. --- ChangeLog | 5 +++++ kern/disk.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 83d0c58a8..d7ae963dd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2010-02-03 Torsten Landschoff + + * kern/disk.c (grub_disk_read): Fix offset computation when reading + last sectors. + 2010-02-03 Vladimir Serbinenko * disk/i386/pc/biosdisk.c (grub_biosdisk_read): Handle non-2048 aligned diff --git a/kern/disk.c b/kern/disk.c index a01373072..5c30e1727 100644 --- a/kern/disk.c +++ b/kern/disk.c @@ -441,7 +441,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, grub_errno = GRUB_ERR_NONE; - num = ((size + real_offset + pos + GRUB_DISK_SECTOR_SIZE - 1) + num = ((size + real_offset + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); p = grub_realloc (tmp_buf, num << GRUB_DISK_SECTOR_BITS); @@ -458,7 +458,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, goto finish; } - grub_memcpy (buf, tmp_buf + pos + real_offset, size); + grub_memcpy (buf, tmp_buf + real_offset, size); /* Call the read hook, if any. */ if (disk->read_hook) From 2b4068e99251e7e6e123b8440375b6f64fe73291 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 3 Feb 2010 00:49:35 +0100 Subject: [PATCH 61/67] 2010-02-03 Vladimir Serbinenko * util/hostdisk.c (open_device): Don't use partition device when reading before the partition. (grub_util_biosdisk_read): Don't read from partition and before the partition in single operation. (grub_util_biosdisk_write): Don't write to partition and before the partition in single operation. --- ChangeLog | 9 +++++++++ util/hostdisk.c | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index d7ae963dd..54a51afc0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2010-02-03 Vladimir Serbinenko + + * util/hostdisk.c (open_device): Don't use partition device when reading + before the partition. + (grub_util_biosdisk_read): Don't read from partition and before the + partition in single operation. + (grub_util_biosdisk_write): Don't write to partition and before the + partition in single operation. + 2010-02-03 Torsten Landschoff * kern/disk.c (grub_disk_read): Fix offset computation when reading diff --git a/util/hostdisk.c b/util/hostdisk.c index a594f75ec..5c56b7579 100644 --- a/util/hostdisk.c +++ b/util/hostdisk.c @@ -336,7 +336,8 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) char dev[PATH_MAX]; strcpy (dev, map[disk->id].device); - if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0) + if (disk->partition && sector >= disk->partition->start + && strncmp (map[disk->id].device, "/dev/", 5) == 0) is_partition = linux_find_partition (dev, disk->partition->start); /* Open the partition. */ @@ -490,6 +491,23 @@ grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, { int fd; + /* Split pre-partition and partition reads. */ + if (disk->partition && sector < disk->partition->start + && sector + size > disk->partition->start) + { + grub_err_t err; + err = grub_util_biosdisk_read (disk, sector, + disk->partition->start - sector, + buf); + if (err) + return err; + + return grub_util_biosdisk_read (disk, disk->partition->start, + size - (disk->partition->start - sector), + buf + ((disk->partition->start - sector) + << GRUB_DISK_SECTOR_BITS)); + } + fd = open_device (disk, sector, O_RDONLY); if (fd < 0) return grub_errno; @@ -527,6 +545,23 @@ grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector, { int fd; + /* Split pre-partition and partition writes. */ + if (disk->partition && sector < disk->partition->start + && sector + size > disk->partition->start) + { + grub_err_t err; + err = grub_util_biosdisk_write (disk, sector, + disk->partition->start - sector, + buf); + if (err) + return err; + + return grub_util_biosdisk_write (disk, disk->partition->start, + size - (disk->partition->start - sector), + buf + ((disk->partition->start - sector) + << GRUB_DISK_SECTOR_BITS)); + } + fd = open_device (disk, sector, O_WRONLY); if (fd < 0) return grub_errno; From 98f5714739f9978b4e2c16941ba0b75a9b9bb826 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 3 Feb 2010 01:34:55 +0100 Subject: [PATCH 62/67] Fix mips compilation --- conf/mips-yeeloong.rmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/mips-yeeloong.rmk b/conf/mips-yeeloong.rmk index 964f29384..eb0dc9676 100644 --- a/conf/mips-yeeloong.rmk +++ b/conf/mips-yeeloong.rmk @@ -21,7 +21,7 @@ kernel_img_SOURCES = kern/$(target_cpu)/startup.S \ font/font_cmd.c font/font.c io/bufio.c \ video/video.c video/fb/video_fb.c video/fb/fbblit.c \ video/fb/fbfill.c video/fb/fbutil.c video/bitmap.c \ - video/sm712.c bus/pci.c bus/bonito.c \ + video/bitmap_scale.c video/sm712.c bus/pci.c bus/bonito.c \ term/gfxterm.c commands/extcmd.c lib/arg.c \ symlist.c kernel_img_CFLAGS = $(COMMON_CFLAGS) -DUSE_ASCII_FAILBACK From 4f8528fc2b30a7ef05f7896f54cec961ce49276b Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 6 Feb 2010 00:30:25 +0100 Subject: [PATCH 63/67] 2010-02-06 Vladimir Serbinenko * kern/ieee1275/openfw.c (grub_devalias_iterate): Stop iterating on error. --- ChangeLog | 5 +++++ kern/ieee1275/openfw.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 54a51afc0..d92d92117 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2010-02-06 Vladimir Serbinenko + + * kern/ieee1275/openfw.c (grub_devalias_iterate): Stop iterating on + error. + 2010-02-03 Vladimir Serbinenko * util/hostdisk.c (open_device): Don't use partition device when reading diff --git a/kern/ieee1275/openfw.c b/kern/ieee1275/openfw.c index 5f0aad119..39432c584 100644 --- a/kern/ieee1275/openfw.c +++ b/kern/ieee1275/openfw.c @@ -135,7 +135,7 @@ grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias)) /* Find the first property. */ aliasname[0] = '\0'; - while (grub_ieee1275_next_property (aliases, aliasname, aliasname)) + while (grub_ieee1275_next_property (aliases, aliasname, aliasname) > 0) { grub_ieee1275_phandle_t dev; grub_ssize_t pathlen; From 5562834e18004d4639dc6bcf1b9a20d925d9869c Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 6 Feb 2010 00:32:07 +0100 Subject: [PATCH 64/67] 2010-02-06 Vladimir Serbinenko * kern/ieee1275/openfw.c (grub_ieee1275_encode_devname): Support whole disk devices. --- ChangeLog | 5 +++++ kern/ieee1275/openfw.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index d92d92117..e2a8f7575 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2010-02-06 Vladimir Serbinenko + + * kern/ieee1275/openfw.c (grub_ieee1275_encode_devname): Support whole + disk devices. + 2010-02-06 Vladimir Serbinenko * kern/ieee1275/openfw.c (grub_devalias_iterate): Stop iterating on diff --git a/kern/ieee1275/openfw.c b/kern/ieee1275/openfw.c index 39432c584..dd9a9138f 100644 --- a/kern/ieee1275/openfw.c +++ b/kern/ieee1275/openfw.c @@ -374,7 +374,7 @@ grub_ieee1275_encode_devname (const char *path) char *partition = grub_ieee1275_parse_args (path, GRUB_PARSE_PARTITION); char *encoding; - if (partition) + if (partition && partition[0]) { unsigned int partno = grub_strtoul (partition, 0, 0); From 3746a6bc3191c93a41216d03f8436c838dba6d99 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 6 Feb 2010 15:25:59 +0100 Subject: [PATCH 65/67] 2010-02-06 Vladimir Serbinenko * fs/i386/pc/pxe.c (grub_pxefs_dir): Return with failure on non-pxe disk. (grub_pxefs_open): Likewise. --- ChangeLog | 6 ++++++ fs/i386/pc/pxe.c | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 117933d07..eed0f93bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2010-02-06 Vladimir Serbinenko + + * fs/i386/pc/pxe.c (grub_pxefs_dir): Return with failure on + non-pxe disk. + (grub_pxefs_open): Likewise. + 2010-02-06 Colin D Bennett * conf/common.rmk (pkglib_MODULES): Add gfxmenu.mod. diff --git a/fs/i386/pc/pxe.c b/fs/i386/pc/pxe.c index 8bfe17594..92529883e 100644 --- a/fs/i386/pc/pxe.c +++ b/fs/i386/pc/pxe.c @@ -173,12 +173,15 @@ static struct grub_disk_dev grub_pxe_dev = }; static grub_err_t -grub_pxefs_dir (grub_device_t device __attribute__ ((unused)), +grub_pxefs_dir (grub_device_t device, const char *path __attribute__ ((unused)), int (*hook) (const char *filename, const struct grub_dirhook_info *info) __attribute__ ((unused))) { + if (device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID) + return grub_error (GRUB_ERR_IO, "not a pxe disk"); + return GRUB_ERR_NONE; } @@ -194,6 +197,9 @@ grub_pxefs_open (struct grub_file *file, const char *name) struct grub_pxe_disk_data *disk_data = file->device->disk->data; grub_file_t file_int, bufio; + if (file->device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID) + return grub_error (GRUB_ERR_IO, "not a pxe disk"); + if (curr_file != 0) { grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c.c2); From 911df80c54af99b2e83a6ab1e51e813f7a9f81f0 Mon Sep 17 00:00:00 2001 From: Yves Blusseau Date: Sat, 6 Feb 2010 15:37:23 +0100 Subject: [PATCH 66/67] 2010-02-06 Yves Blusseau * conf/common.rmk (grub_script_check_SOURCES): add missing dependencies. (grub_mkpasswd_pbkdf2_SOURCES): Likewise. --- ChangeLog | 5 +++++ conf/common.rmk | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index eed0f93bc..ba2561819 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2010-02-06 Yves Blusseau + + * conf/common.rmk (grub_script_check_SOURCES): add missing dependencies. + (grub_mkpasswd_pbkdf2_SOURCES): Likewise. + 2010-02-06 Vladimir Serbinenko * fs/i386/pc/pxe.c (grub_pxefs_dir): Return with failure on diff --git a/conf/common.rmk b/conf/common.rmk index 13ca431ba..6cce36395 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -94,7 +94,8 @@ grub_bin2h_SOURCES = gnulib/progname.c util/bin2h.c # For grub-script-check. bin_UTILITIES += grub-script-check util/grub-script-check.c_DEPENDENCIES = grub_script_check_init.h -grub_script_check_SOURCES = gnulib/progname.c util/grub-script-check.c util/misc.c \ +grub_script_check_SOURCES = gnulib/progname.c gnulib/getdelim.c gnulib/getline.c \ + util/grub-script-check.c util/misc.c \ script/main.c script/script.c script/function.c script/lexer.c \ kern/handler.c kern/err.c kern/parser.c kern/list.c \ kern/misc.c kern/env.c grub_script_check_init.c grub_script.tab.c @@ -759,7 +760,7 @@ password_pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS) password_pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS) bin_UTILITIES += grub-mkpasswd-pbkdf2 -grub_mkpasswd_pbkdf2_SOURCES = gnulib/progname.c util/grub-mkpasswd-pbkdf2.c lib/crypto.c lib/libgcrypt-grub/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/err.c +grub_mkpasswd_pbkdf2_SOURCES = gnulib/progname.c gnulib/getdelim.c gnulib/getline.c util/grub-mkpasswd-pbkdf2.c lib/crypto.c lib/libgcrypt-grub/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/err.c grub_mkpasswd_pbkdf2_CFLAGS += -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap -DGRUB_MKPASSWD=1 include $(srcdir)/conf/gcry.mk From 89494cb55c887e7b3150dbcfed50fd360521a67b Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 6 Feb 2010 15:51:22 +0100 Subject: [PATCH 67/67] 2010-02-06 Vladimir Serbinenko * disk/ieee1275/ofdisk.c (grub_ofdisk_read): Correct error handling. --- ChangeLog | 4 ++++ disk/ieee1275/ofdisk.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ba2561819..72d5bd899 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ * conf/common.rmk (grub_script_check_SOURCES): add missing dependencies. (grub_mkpasswd_pbkdf2_SOURCES): Likewise. +2010-02-06 Vladimir Serbinenko + + * disk/ieee1275/ofdisk.c (grub_ofdisk_read): Correct error handling. + 2010-02-06 Vladimir Serbinenko * fs/i386/pc/pxe.c (grub_pxefs_dir): Return with failure on diff --git a/disk/ieee1275/ofdisk.c b/disk/ieee1275/ofdisk.c index 051ece0b9..238cff33d 100644 --- a/disk/ieee1275/ofdisk.c +++ b/disk/ieee1275/ofdisk.c @@ -248,7 +248,7 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, (long long) sector); grub_ieee1275_read ((grub_ieee1275_ihandle_t) (unsigned long) disk->data, buf, size * 512UL, &actual); - if (actual != actual) + if (actual != (grub_ssize_t) (size * 512UL)) return grub_error (GRUB_ERR_READ_ERROR, "read error on block: %llu", (long long) sector);