From d3ee2d201e3a241ee1f39e9a2a2e3e6580579186 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 26 Dec 2009 16:41:54 +0100 Subject: [PATCH] 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",