1 /* view.c - Graphical menu interface MVC view. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/types.h>
21 #include <grub/file.h>
22 #include <grub/misc.h>
26 #include <grub/normal.h>
27 #include <grub/video.h>
28 #include <grub/gfxterm.h>
29 #include <grub/bitmap.h>
30 #include <grub/bitmap_scale.h>
31 #include <grub/term.h>
32 #include <grub/gfxwidgets.h>
33 #include <grub/time.h>
34 #include <grub/menu.h>
35 #include <grub/menu_viewer.h>
36 #include <grub/gfxmenu_view.h>
37 #include <grub/gui_string_util.h>
38 #include <grub/icon_manager.h>
39 #include <grub/i18n.h>
42 init_terminal (grub_gfxmenu_view_t view
);
43 static grub_video_rect_t term_rect
;
44 static grub_gfxmenu_view_t term_view
;
46 /* Create a new view object, loading the theme specified by THEME_PATH and
47 associating MODEL with the view. */
49 grub_gfxmenu_view_new (const char *theme_path
,
50 int width
, int height
)
52 grub_gfxmenu_view_t view
;
53 grub_font_t default_font
;
54 grub_video_rgba_color_t default_fg_color
;
55 grub_video_rgba_color_t default_bg_color
;
57 view
= grub_malloc (sizeof (*view
));
63 view
->screen
.width
= width
;
64 view
->screen
.height
= height
;
66 default_font
= grub_font_get ("Unknown Regular 16");
67 default_fg_color
= grub_video_rgba_color_rgb (0, 0, 0);
68 default_bg_color
= grub_video_rgba_color_rgb (255, 255, 255);
72 view
->title_font
= default_font
;
73 view
->message_font
= default_font
;
74 view
->terminal_font_name
= grub_strdup ("Fixed 10");
75 view
->title_color
= default_fg_color
;
76 view
->message_color
= default_bg_color
;
77 view
->message_bg_color
= default_fg_color
;
78 view
->desktop_image
= 0;
79 view
->desktop_color
= default_bg_color
;
80 view
->terminal_box
= grub_gfxmenu_create_box (0, 0);
81 view
->title_text
= grub_strdup (_("GRUB Boot Menu"));
82 view
->progress_message_text
= 0;
85 /* Set the timeout bar's frame. */
86 view
->progress_message_frame
.width
= view
->screen
.width
* 4 / 5;
87 view
->progress_message_frame
.height
= 50;
88 view
->progress_message_frame
.x
= view
->screen
.x
89 + (view
->screen
.width
- view
->progress_message_frame
.width
) / 2;
90 view
->progress_message_frame
.y
= view
->screen
.y
91 + view
->screen
.height
- 90 - 20 - view
->progress_message_frame
.height
;
93 if (grub_gfxmenu_view_load_theme (view
, theme_path
) != 0)
95 grub_gfxmenu_view_destroy (view
);
102 /* Destroy the view object. All used memory is freed. */
104 grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view
)
108 grub_video_bitmap_destroy (view
->desktop_image
);
109 if (view
->terminal_box
)
110 view
->terminal_box
->destroy (view
->terminal_box
);
111 grub_free (view
->terminal_font_name
);
112 grub_free (view
->title_text
);
113 grub_free (view
->progress_message_text
);
114 grub_free (view
->theme_path
);
116 view
->canvas
->component
.ops
->destroy (view
->canvas
);
121 redraw_background (grub_gfxmenu_view_t view
,
122 const grub_video_rect_t
*bounds
)
124 if (view
->desktop_image
)
126 struct grub_video_bitmap
*img
= view
->desktop_image
;
127 grub_video_blit_bitmap (img
, GRUB_VIDEO_BLIT_REPLACE
,
128 bounds
->x
, bounds
->y
,
129 bounds
->x
- view
->screen
.x
,
130 bounds
->y
- view
->screen
.y
,
131 bounds
->width
, bounds
->height
);
135 grub_video_fill_rect (grub_video_map_rgba_color (view
->desktop_color
),
136 bounds
->x
, bounds
->y
,
137 bounds
->width
, bounds
->height
);
142 draw_title (grub_gfxmenu_view_t view
)
144 if (! view
->title_text
)
147 /* Center the title. */
148 int title_width
= grub_font_get_string_width (view
->title_font
,
150 int x
= (view
->screen
.width
- title_width
) / 2;
151 int y
= 40 + grub_font_get_ascent (view
->title_font
);
152 grub_font_draw_string (view
->title_text
,
154 grub_video_map_rgba_color (view
->title_color
),
158 struct progress_value_data
166 struct grub_gfxmenu_timeout_notify
*grub_gfxmenu_timeout_notifications
;
169 update_timeouts (int visible
, int start
, int value
, int end
)
171 struct grub_gfxmenu_timeout_notify
*cur
;
173 for (cur
= grub_gfxmenu_timeout_notifications
; cur
; cur
= cur
->next
)
174 cur
->set_state (cur
->self
, visible
, start
, value
, end
);
178 redraw_timeouts (struct grub_gfxmenu_view
*view
)
180 struct grub_gfxmenu_timeout_notify
*cur
;
182 for (cur
= grub_gfxmenu_timeout_notifications
; cur
; cur
= cur
->next
)
184 grub_video_rect_t bounds
;
185 cur
->self
->ops
->get_bounds (cur
->self
, &bounds
);
186 grub_gfxmenu_view_redraw (view
, &bounds
);
191 grub_gfxmenu_print_timeout (int timeout
, void *data
)
193 struct grub_gfxmenu_view
*view
= data
;
195 if (view
->first_timeout
== -1)
196 view
->first_timeout
= timeout
;
198 update_timeouts (1, -(view
->first_timeout
+ 1), -timeout
, 0);
199 redraw_timeouts (view
);
200 grub_video_swap_buffers ();
201 if (view
->double_repaint
)
202 redraw_timeouts (view
);
206 grub_gfxmenu_clear_timeout (void *data
)
208 struct grub_gfxmenu_view
*view
= data
;
210 update_timeouts (0, 1, 0, 0);
211 redraw_timeouts (view
);
212 grub_video_swap_buffers ();
213 if (view
->double_repaint
)
214 redraw_timeouts (view
);
218 update_menu_visit (grub_gui_component_t component
,
221 grub_gfxmenu_view_t view
;
223 if (component
->ops
->is_instance (component
, "list"))
225 grub_gui_list_t list
= (grub_gui_list_t
) component
;
226 list
->ops
->set_view_info (list
, view
);
230 /* Update any boot menu components with the current menu model and
233 update_menu_components (grub_gfxmenu_view_t view
)
235 grub_gui_iterate_recursively ((grub_gui_component_t
) view
->canvas
,
236 update_menu_visit
, view
);
240 draw_message (grub_gfxmenu_view_t view
)
242 char *text
= view
->progress_message_text
;
243 grub_video_rect_t f
= view
->progress_message_frame
;
247 grub_font_t font
= view
->message_font
;
248 grub_video_color_t color
= grub_video_map_rgba_color (view
->message_color
);
251 grub_video_fill_rect (color
,
252 f
.x
-1, f
.y
-1, f
.width
+2, f
.height
+2);
254 grub_video_fill_rect (grub_video_map_rgba_color (view
->message_bg_color
),
255 f
.x
, f
.y
, f
.width
, f
.height
);
257 /* Center the text. */
258 int text_width
= grub_font_get_string_width (font
, text
);
259 int x
= f
.x
+ (f
.width
- text_width
) / 2;
260 int y
= (f
.y
+ (f
.height
- grub_font_get_descent (font
)) / 2
261 + grub_font_get_ascent (font
) / 2);
262 grub_font_draw_string (text
, font
, color
, x
, y
);
266 grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view
,
267 const grub_video_rect_t
*region
)
269 if (grub_video_have_common_points (&term_rect
, region
))
270 grub_gfxterm_schedule_repaint ();
272 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
274 redraw_background (view
, region
);
276 view
->canvas
->component
.ops
->paint (view
->canvas
, region
);
278 if (grub_video_have_common_points (&view
->progress_message_frame
, region
))
283 grub_gfxmenu_view_draw (grub_gfxmenu_view_t view
)
285 init_terminal (view
);
287 /* Clear the screen; there may be garbage left over in video memory. */
288 grub_video_fill_rect (grub_video_map_rgb (0, 0, 0),
289 view
->screen
.x
, view
->screen
.y
,
290 view
->screen
.width
, view
->screen
.height
);
291 grub_video_swap_buffers ();
292 if (view
->double_repaint
)
293 grub_video_fill_rect (grub_video_map_rgb (0, 0, 0),
294 view
->screen
.x
, view
->screen
.y
,
295 view
->screen
.width
, view
->screen
.height
);
297 update_menu_components (view
);
299 grub_gfxmenu_view_redraw (view
, &view
->screen
);
300 grub_video_swap_buffers ();
301 if (view
->double_repaint
)
302 grub_gfxmenu_view_redraw (view
, &view
->screen
);
306 redraw_menu_visit (grub_gui_component_t component
,
309 grub_gfxmenu_view_t view
;
311 if (component
->ops
->is_instance (component
, "list"))
313 grub_video_rect_t bounds
;
315 component
->ops
->get_bounds (component
, &bounds
);
316 grub_gfxmenu_view_redraw (view
, &bounds
);
321 grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view
)
323 update_menu_components (view
);
325 grub_gui_iterate_recursively ((grub_gui_component_t
) view
->canvas
,
326 redraw_menu_visit
, view
);
327 grub_video_swap_buffers ();
328 if (view
->double_repaint
)
330 grub_gui_iterate_recursively ((grub_gui_component_t
) view
->canvas
,
331 redraw_menu_visit
, view
);
336 grub_gfxmenu_set_chosen_entry (int entry
, void *data
)
338 grub_gfxmenu_view_t view
= data
;
340 view
->selected
= entry
;
341 grub_gfxmenu_redraw_menu (view
);
345 grub_gfxmenu_draw_terminal_box (void)
347 grub_gfxmenu_box_t term_box
;
349 term_box
= term_view
->terminal_box
;
353 term_box
->set_content_size (term_box
, term_rect
.width
,
356 term_box
->draw (term_box
,
357 term_rect
.x
- term_box
->get_left_pad (term_box
),
358 term_rect
.y
- term_box
->get_top_pad (term_box
));
362 init_terminal (grub_gfxmenu_view_t view
)
364 term_rect
.width
= view
->screen
.width
* 7 / 10;
365 term_rect
.height
= view
->screen
.height
* 7 / 10;
367 term_rect
.x
= view
->screen
.x
+ view
->screen
.width
* (10 - 7) / 10 / 2;
368 term_rect
.y
= view
->screen
.y
+ view
->screen
.height
* (10 - 7) / 10 / 2;
372 /* Note: currently there is no API for changing the gfxterm font
373 on the fly, so whatever font the initially loaded theme specifies
374 will be permanent. */
375 grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY
, term_rect
.x
,
377 term_rect
.width
, term_rect
.height
,
378 view
->double_repaint
, view
->terminal_font_name
, 3);
379 grub_gfxterm_decorator_hook
= grub_gfxmenu_draw_terminal_box
;
382 /* FIXME: previously notifications were displayed in special case.
386 /* Sets MESSAGE as the progress message for the view.
387 MESSAGE can be 0, in which case no message is displayed. */
389 set_progress_message (grub_gfxmenu_view_t view
, const char *message
)
391 grub_free (view
->progress_message_text
);
393 view
->progress_message_text
= grub_strdup (message
);
395 view
->progress_message_text
= 0;
399 notify_booting (grub_menu_entry_t entry
, void *userdata
)
401 grub_gfxmenu_view_t view
= (grub_gfxmenu_view_t
) userdata
;
403 char *s
= grub_malloc (100 + grub_strlen (entry
->title
));
407 grub_sprintf (s
, "Booting '%s'", entry
->title
);
408 set_progress_message (view
, s
);
410 grub_gfxmenu_view_redraw (view
, &view
->progress_message_frame
);
411 grub_video_swap_buffers ();
412 if (view
->double_repaint
)
413 grub_gfxmenu_view_redraw (view
, &view
->progress_message_frame
);
417 notify_fallback (grub_menu_entry_t entry
, void *userdata
)
419 grub_gfxmenu_view_t view
= (grub_gfxmenu_view_t
) userdata
;
421 char *s
= grub_malloc (100 + grub_strlen (entry
->title
));
425 grub_sprintf (s
, "Falling back to '%s'", entry
->title
);
426 set_progress_message (view
, s
);
428 grub_gfxmenu_view_redraw (view
, &view
->progress_message_frame
);
429 grub_video_swap_buffers ();
430 if (view
->double_repaint
)
431 grub_gfxmenu_view_redraw (view
, &view
->progress_message_frame
);
435 notify_execution_failure (void *userdata
__attribute__ ((unused
)))
440 static struct grub_menu_execute_callback execute_callback
=
442 .notify_booting
= notify_booting
,
443 .notify_fallback
= notify_fallback
,
444 .notify_failure
= notify_execution_failure