~ubuntu-branches/ubuntu/trusty/grub2/trusty-updates

« back to all changes in this revision

Viewing changes to grub-core/gfxmenu/view.c

Tags: upstream-1.99~20101122
ImportĀ upstreamĀ versionĀ 1.99~20101122

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* view.c - Graphical menu interface MVC view. */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2008  Free Software Foundation, Inc.
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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/>.
 
18
 */
 
19
 
 
20
#include <grub/types.h>
 
21
#include <grub/file.h>
 
22
#include <grub/misc.h>
 
23
#include <grub/mm.h>
 
24
#include <grub/err.h>
 
25
#include <grub/dl.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
 
 
40
static void
 
41
init_terminal (grub_gfxmenu_view_t view);
 
42
static grub_video_rect_t term_rect;
 
43
static grub_gfxmenu_view_t term_view;
 
44
 
 
45
/* Create a new view object, loading the theme specified by THEME_PATH and
 
46
   associating MODEL with the view.  */
 
47
grub_gfxmenu_view_t
 
48
grub_gfxmenu_view_new (const char *theme_path,
 
49
                       int width, int height)
 
50
{
 
51
  grub_gfxmenu_view_t view;
 
52
  grub_font_t default_font;
 
53
  grub_gui_color_t default_fg_color;
 
54
  grub_gui_color_t default_bg_color;
 
55
 
 
56
  view = grub_malloc (sizeof (*view));
 
57
  if (! view)
 
58
    return 0;
 
59
 
 
60
  view->screen.x = 0;
 
61
  view->screen.y = 0;
 
62
  view->screen.width = width;
 
63
  view->screen.height = height;
 
64
 
 
65
  default_font = grub_font_get ("Unknown Regular 16");
 
66
  default_fg_color = grub_gui_color_rgb (0, 0, 0);
 
67
  default_bg_color = grub_gui_color_rgb (255, 255, 255);
 
68
 
 
69
  view->canvas = 0;
 
70
 
 
71
  view->title_font = default_font;
 
72
  view->message_font = default_font;
 
73
  view->terminal_font_name = grub_strdup ("Fixed 10");
 
74
  view->title_color = default_fg_color;
 
75
  view->message_color = default_bg_color;
 
76
  view->message_bg_color = default_fg_color;
 
77
  view->desktop_image = 0;
 
78
  view->desktop_color = default_bg_color;
 
79
  view->terminal_box = grub_gfxmenu_create_box (0, 0);
 
80
  view->title_text = grub_strdup ("GRUB Boot Menu");
 
81
  view->progress_message_text = 0;
 
82
  view->theme_path = 0;
 
83
 
 
84
  /* Set the timeout bar's frame.  */
 
85
  view->progress_message_frame.width = view->screen.width * 4 / 5;
 
86
  view->progress_message_frame.height = 50;
 
87
  view->progress_message_frame.x = view->screen.x
 
88
    + (view->screen.width - view->progress_message_frame.width) / 2;
 
89
  view->progress_message_frame.y = view->screen.y
 
90
    + view->screen.height - 90 - 20 - view->progress_message_frame.height;
 
91
 
 
92
  if (grub_gfxmenu_view_load_theme (view, theme_path) != 0)
 
93
    {
 
94
      grub_gfxmenu_view_destroy (view);
 
95
      return 0;
 
96
    }
 
97
 
 
98
  return view;
 
99
}
 
100
 
 
101
/* Destroy the view object.  All used memory is freed.  */
 
102
void
 
103
grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view)
 
104
{
 
105
  if (!view)
 
106
    return;
 
107
  grub_video_bitmap_destroy (view->desktop_image);
 
108
  if (view->terminal_box)
 
109
    view->terminal_box->destroy (view->terminal_box);
 
110
  grub_free (view->terminal_font_name);
 
111
  grub_free (view->title_text);
 
112
  grub_free (view->progress_message_text);
 
113
  grub_free (view->theme_path);
 
114
  if (view->canvas)
 
115
    view->canvas->component.ops->destroy (view->canvas);
 
116
  grub_free (view);
 
117
}
 
118
 
 
119
static void
 
120
redraw_background (grub_gfxmenu_view_t view,
 
121
                   const grub_video_rect_t *bounds)
 
122
{
 
123
  if (view->desktop_image)
 
124
    {
 
125
      struct grub_video_bitmap *img = view->desktop_image;
 
126
      grub_video_blit_bitmap (img, GRUB_VIDEO_BLIT_REPLACE,
 
127
                              bounds->x, bounds->y,
 
128
                              bounds->x - view->screen.x,
 
129
                              bounds->y - view->screen.y,
 
130
                              bounds->width, bounds->height);
 
131
    }
 
132
  else
 
133
    {
 
134
      grub_video_fill_rect (grub_gui_map_color (view->desktop_color),
 
135
                            bounds->x, bounds->y,
 
136
                            bounds->width, bounds->height);
 
137
    }
 
138
}
 
139
 
 
140
static void
 
141
draw_title (grub_gfxmenu_view_t view)
 
142
{
 
143
  if (! view->title_text)
 
144
    return;
 
145
 
 
146
  /* Center the title. */
 
147
  int title_width = grub_font_get_string_width (view->title_font,
 
148
                                                view->title_text);
 
149
  int x = (view->screen.width - title_width) / 2;
 
150
  int y = 40 + grub_font_get_ascent (view->title_font);
 
151
  grub_font_draw_string (view->title_text,
 
152
                         view->title_font,
 
153
                         grub_gui_map_color (view->title_color),
 
154
                         x, y);
 
155
}
 
156
 
 
157
struct progress_value_data
 
158
{
 
159
  int visible;
 
160
  int start;
 
161
  int end;
 
162
  int value;
 
163
};
 
164
 
 
165
struct grub_gfxmenu_timeout_notify *grub_gfxmenu_timeout_notifications;
 
166
 
 
167
static void
 
168
update_timeouts (int visible, int start, int value, int end)
 
169
{
 
170
  struct grub_gfxmenu_timeout_notify *cur;
 
171
 
 
172
  for (cur = grub_gfxmenu_timeout_notifications; cur; cur = cur->next)
 
173
    cur->set_state (cur->self, visible, start, value, end);
 
174
}
 
175
 
 
176
static void
 
177
redraw_timeouts (struct grub_gfxmenu_view *view)
 
178
{
 
179
  struct grub_gfxmenu_timeout_notify *cur;
 
180
 
 
181
  for (cur = grub_gfxmenu_timeout_notifications; cur; cur = cur->next)
 
182
    {
 
183
      grub_video_rect_t bounds;
 
184
      cur->self->ops->get_bounds (cur->self, &bounds);
 
185
      grub_gfxmenu_view_redraw (view, &bounds);
 
186
    }
 
187
}
 
188
 
 
189
void 
 
190
grub_gfxmenu_print_timeout (int timeout, void *data)
 
191
{
 
192
  struct grub_gfxmenu_view *view = data;
 
193
 
 
194
  if (view->first_timeout == -1)
 
195
    view->first_timeout = timeout;
 
196
 
 
197
  update_timeouts (1, -(view->first_timeout + 1), -timeout, 0);
 
198
  redraw_timeouts (view);
 
199
  grub_video_swap_buffers ();
 
200
  if (view->double_repaint)
 
201
    redraw_timeouts (view);
 
202
}
 
203
 
 
204
void 
 
205
grub_gfxmenu_clear_timeout (void *data)
 
206
{
 
207
  struct grub_gfxmenu_view *view = data;
 
208
 
 
209
  update_timeouts (0, 1, 0, 0);
 
210
  redraw_timeouts (view);
 
211
  grub_video_swap_buffers ();
 
212
  if (view->double_repaint)
 
213
    redraw_timeouts (view);
 
214
}
 
215
 
 
216
static void
 
217
update_menu_visit (grub_gui_component_t component,
 
218
                   void *userdata)
 
219
{
 
220
  grub_gfxmenu_view_t view;
 
221
  view = userdata;
 
222
  if (component->ops->is_instance (component, "list"))
 
223
    {
 
224
      grub_gui_list_t list = (grub_gui_list_t) component;
 
225
      list->ops->set_view_info (list, view);
 
226
    }
 
227
}
 
228
 
 
229
/* Update any boot menu components with the current menu model and
 
230
   theme path.  */
 
231
static void
 
232
update_menu_components (grub_gfxmenu_view_t view)
 
233
{
 
234
  grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas,
 
235
                                update_menu_visit, view);
 
236
}
 
237
 
 
238
static void
 
239
draw_message (grub_gfxmenu_view_t view)
 
240
{
 
241
  char *text = view->progress_message_text;
 
242
  grub_video_rect_t f = view->progress_message_frame;
 
243
  if (! text)
 
244
    return;
 
245
 
 
246
  grub_font_t font = view->message_font;
 
247
  grub_video_color_t color = grub_gui_map_color (view->message_color);
 
248
 
 
249
  /* Border.  */
 
250
  grub_video_fill_rect (color,
 
251
                        f.x-1, f.y-1, f.width+2, f.height+2);
 
252
  /* Fill.  */
 
253
  grub_video_fill_rect (grub_gui_map_color (view->message_bg_color),
 
254
                        f.x, f.y, f.width, f.height);
 
255
 
 
256
  /* Center the text. */
 
257
  int text_width = grub_font_get_string_width (font, text);
 
258
  int x = f.x + (f.width - text_width) / 2;
 
259
  int y = (f.y + (f.height - grub_font_get_descent (font)) / 2
 
260
           + grub_font_get_ascent (font) / 2);
 
261
  grub_font_draw_string (text, font, color, x, y);
 
262
}
 
263
 
 
264
void
 
265
grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view,
 
266
                          const grub_video_rect_t *region)
 
267
{
 
268
  if (grub_video_have_common_points (&term_rect, region))
 
269
    grub_gfxterm_schedule_repaint ();
 
270
 
 
271
  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
 
272
 
 
273
  redraw_background (view, region);
 
274
  if (view->canvas)
 
275
    view->canvas->component.ops->paint (view->canvas, region);
 
276
  draw_title (view);
 
277
  if (grub_video_have_common_points (&view->progress_message_frame, region))
 
278
    draw_message (view);
 
279
}
 
280
 
 
281
void
 
282
grub_gfxmenu_view_draw (grub_gfxmenu_view_t view)
 
283
{
 
284
  init_terminal (view);
 
285
 
 
286
  /* Clear the screen; there may be garbage left over in video memory. */
 
287
  grub_video_fill_rect (grub_video_map_rgb (0, 0, 0),
 
288
                        view->screen.x, view->screen.y,
 
289
                        view->screen.width, view->screen.height);
 
290
  grub_video_swap_buffers ();
 
291
  if (view->double_repaint)
 
292
    grub_video_fill_rect (grub_video_map_rgb (0, 0, 0),
 
293
                          view->screen.x, view->screen.y,
 
294
                          view->screen.width, view->screen.height);
 
295
 
 
296
  update_menu_components (view);
 
297
 
 
298
  grub_gfxmenu_view_redraw (view, &view->screen);
 
299
  grub_video_swap_buffers ();
 
300
  if (view->double_repaint)
 
301
    grub_gfxmenu_view_redraw (view, &view->screen);
 
302
}
 
303
 
 
304
static void
 
305
redraw_menu_visit (grub_gui_component_t component,
 
306
                   void *userdata)
 
307
{
 
308
  grub_gfxmenu_view_t view;
 
309
  view = userdata;
 
310
  if (component->ops->is_instance (component, "list"))
 
311
    {
 
312
      grub_video_rect_t bounds;
 
313
 
 
314
      component->ops->get_bounds (component, &bounds);
 
315
      grub_gfxmenu_view_redraw (view, &bounds);
 
316
    }
 
317
}
 
318
 
 
319
void
 
320
grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view)
 
321
{
 
322
  update_menu_components (view);
 
323
 
 
324
  grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas,
 
325
                                redraw_menu_visit, view);
 
326
  grub_video_swap_buffers ();
 
327
  if (view->double_repaint)
 
328
    {
 
329
      grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas,
 
330
                                    redraw_menu_visit, view);
 
331
    }
 
332
}
 
333
 
 
334
void 
 
335
grub_gfxmenu_set_chosen_entry (int entry, void *data)
 
336
{
 
337
  grub_gfxmenu_view_t view = data;
 
338
 
 
339
  view->selected = entry;
 
340
  grub_gfxmenu_redraw_menu (view);
 
341
}
 
342
 
 
343
static void
 
344
grub_gfxmenu_draw_terminal_box (void)
 
345
{
 
346
  grub_gfxmenu_box_t term_box;
 
347
 
 
348
  term_box = term_view->terminal_box;
 
349
  if (!term_box)
 
350
    return;
 
351
  
 
352
  term_box->set_content_size (term_box, term_rect.width,
 
353
                              term_rect.height);
 
354
  
 
355
  term_box->draw (term_box,
 
356
                  term_rect.x - term_box->get_left_pad (term_box),
 
357
                  term_rect.y - term_box->get_top_pad (term_box));
 
358
}
 
359
 
 
360
static void
 
361
init_terminal (grub_gfxmenu_view_t view)
 
362
{
 
363
  term_rect.width = view->screen.width * 7 / 10;
 
364
  term_rect.height = view->screen.height * 7 / 10;
 
365
 
 
366
  term_rect.x = view->screen.x + view->screen.width * (10 - 7) / 10 / 2;
 
367
  term_rect.y = view->screen.y + view->screen.height * (10 - 7) / 10 / 2;
 
368
 
 
369
  term_view = view;
 
370
 
 
371
  /* Note: currently there is no API for changing the gfxterm font
 
372
     on the fly, so whatever font the initially loaded theme specifies
 
373
     will be permanent.  */
 
374
  grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, term_rect.x,
 
375
                           term_rect.y,
 
376
                           term_rect.width, term_rect.height,
 
377
                           view->double_repaint, view->terminal_font_name, 3);
 
378
  grub_gfxterm_decorator_hook = grub_gfxmenu_draw_terminal_box;
 
379
}
 
380
 
 
381
/* FIXME: previously notifications were displayed in special case.
 
382
   Is it necessary?
 
383
 */
 
384
#if 0
 
385
/* Sets MESSAGE as the progress message for the view.
 
386
   MESSAGE can be 0, in which case no message is displayed.  */
 
387
static void
 
388
set_progress_message (grub_gfxmenu_view_t view, const char *message)
 
389
{
 
390
  grub_free (view->progress_message_text);
 
391
  if (message)
 
392
    view->progress_message_text = grub_strdup (message);
 
393
  else
 
394
    view->progress_message_text = 0;
 
395
}
 
396
 
 
397
static void
 
398
notify_booting (grub_menu_entry_t entry, void *userdata)
 
399
{
 
400
  grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata;
 
401
 
 
402
  char *s = grub_malloc (100 + grub_strlen (entry->title));
 
403
  if (!s)
 
404
    return;
 
405
 
 
406
  grub_sprintf (s, "Booting '%s'", entry->title);
 
407
  set_progress_message (view, s);
 
408
  grub_free (s);
 
409
  grub_gfxmenu_view_redraw (view, &view->progress_message_frame);
 
410
  grub_video_swap_buffers ();
 
411
  if (view->double_repaint)
 
412
    grub_gfxmenu_view_redraw (view, &view->progress_message_frame);
 
413
}
 
414
 
 
415
static void
 
416
notify_fallback (grub_menu_entry_t entry, void *userdata)
 
417
{
 
418
  grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata;
 
419
 
 
420
  char *s = grub_malloc (100 + grub_strlen (entry->title));
 
421
  if (!s)
 
422
    return;
 
423
 
 
424
  grub_sprintf (s, "Falling back to '%s'", entry->title);
 
425
  set_progress_message (view, s);
 
426
  grub_free (s);
 
427
  grub_gfxmenu_view_redraw (view, &view->progress_message_frame);
 
428
  grub_video_swap_buffers ();
 
429
  if (view->double_repaint)
 
430
    grub_gfxmenu_view_redraw (view, &view->progress_message_frame);
 
431
}
 
432
 
 
433
static void
 
434
notify_execution_failure (void *userdata __attribute__ ((unused)))
 
435
{
 
436
}
 
437
 
 
438
 
 
439
static struct grub_menu_execute_callback execute_callback =
 
440
{
 
441
  .notify_booting = notify_booting,
 
442
  .notify_fallback = notify_fallback,
 
443
  .notify_failure = notify_execution_failure
 
444
};
 
445
 
 
446
#endif