~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/term/gfxterm.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 2006,2007,2008,2009  Free Software Foundation, Inc.
 
4
 *
 
5
 *  GRUB is free software: you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation, either version 3 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  GRUB is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#include <grub/term.h>
 
20
#include <grub/types.h>
 
21
#include <grub/dl.h>
 
22
#include <grub/misc.h>
 
23
#include <grub/font.h>
 
24
#include <grub/mm.h>
 
25
#include <grub/env.h>
 
26
#include <grub/video.h>
 
27
#include <grub/gfxterm.h>
 
28
#include <grub/bitmap.h>
 
29
#include <grub/command.h>
 
30
#include <grub/extcmd.h>
 
31
#include <grub/bitmap_scale.h>
 
32
#include <grub/i18n.h>
 
33
 
 
34
#define DEFAULT_VIDEO_MODE      "auto"
 
35
#define DEFAULT_BORDER_WIDTH    10
 
36
 
 
37
#define DEFAULT_STANDARD_COLOR  0x07
 
38
 
 
39
struct grub_dirty_region
 
40
{
 
41
  int top_left_x;
 
42
  int top_left_y;
 
43
  int bottom_right_x;
 
44
  int bottom_right_y;
 
45
};
 
46
 
 
47
struct grub_colored_char
 
48
{
 
49
  /* An Unicode codepoint.  */
 
50
  struct grub_unicode_glyph *code;
 
51
 
 
52
  /* Color values.  */
 
53
  grub_video_color_t fg_color;
 
54
  grub_video_color_t bg_color;
 
55
 
 
56
  /* The width of this character minus one.  */
 
57
  unsigned char width;
 
58
 
 
59
  /* The column index of this character.  */
 
60
  unsigned char index;
 
61
};
 
62
 
 
63
struct grub_virtual_screen
 
64
{
 
65
  /* Dimensions of the virtual screen in pixels.  */
 
66
  unsigned int width;
 
67
  unsigned int height;
 
68
 
 
69
  /* Offset in the display in pixels.  */
 
70
  unsigned int offset_x;
 
71
  unsigned int offset_y;
 
72
 
 
73
  /* TTY Character sizes in pixes.  */
 
74
  unsigned int normal_char_width;
 
75
  unsigned int normal_char_height;
 
76
 
 
77
  /* Virtual screen TTY size in characters.  */
 
78
  unsigned int columns;
 
79
  unsigned int rows;
 
80
 
 
81
  /* Current cursor location in characters.  */
 
82
  unsigned int cursor_x;
 
83
  unsigned int cursor_y;
 
84
 
 
85
  /* Current cursor state. */
 
86
  int cursor_state;
 
87
 
 
88
  /* Font settings. */
 
89
  grub_font_t font;
 
90
 
 
91
  /* Terminal color settings.  */
 
92
  grub_uint8_t standard_color_setting;
 
93
  grub_uint8_t term_color;
 
94
 
 
95
  /* Color settings.  */
 
96
  grub_video_color_t fg_color;
 
97
  grub_video_color_t bg_color;
 
98
  grub_video_color_t bg_color_display;
 
99
 
 
100
  /* Text buffer for virtual screen.  Contains (columns * rows) number
 
101
     of entries.  */
 
102
  struct grub_colored_char *text_buffer;
 
103
 
 
104
  int total_scroll;
 
105
};
 
106
 
 
107
struct grub_gfxterm_window
 
108
{
 
109
  unsigned x;
 
110
  unsigned y;
 
111
  unsigned width;
 
112
  unsigned height;
 
113
  int double_repaint;
 
114
};
 
115
 
 
116
static struct grub_video_render_target *render_target;
 
117
void (*grub_gfxterm_decorator_hook) (void) = NULL;
 
118
static struct grub_gfxterm_window window;
 
119
static struct grub_virtual_screen virtual_screen;
 
120
static grub_gfxterm_repaint_callback_t repaint_callback;
 
121
static int repaint_scheduled = 0;
 
122
static int repaint_was_scheduled = 0;
 
123
 
 
124
static void destroy_window (void);
 
125
 
 
126
static struct grub_video_render_target *text_layer;
 
127
 
 
128
static unsigned int bitmap_width;
 
129
static unsigned int bitmap_height;
 
130
static struct grub_video_bitmap *bitmap;
 
131
 
 
132
static struct grub_dirty_region dirty_region;
 
133
 
 
134
static void dirty_region_reset (void);
 
135
 
 
136
static int dirty_region_is_empty (void);
 
137
 
 
138
static void dirty_region_add (int x, int y,
 
139
                              unsigned int width, unsigned int height);
 
140
 
 
141
static unsigned int calculate_normal_character_width (grub_font_t font);
 
142
 
 
143
static unsigned char calculate_character_width (struct grub_font_glyph *glyph);
 
144
 
 
145
static void grub_gfxterm_refresh (struct grub_term_output *term __attribute__ ((unused)));
 
146
 
 
147
static grub_ssize_t
 
148
grub_gfxterm_getcharwidth (struct grub_term_output *term __attribute__ ((unused)),
 
149
                           const struct grub_unicode_glyph *c);
 
150
 
 
151
static void
 
152
set_term_color (grub_uint8_t term_color)
 
153
{
 
154
  struct grub_video_render_target *old_target;
 
155
 
 
156
  /* Save previous target and switch to text layer.  */
 
157
  grub_video_get_active_render_target (&old_target);
 
158
  grub_video_set_active_render_target (text_layer);
 
159
 
 
160
  /* Map terminal color to text layer compatible video colors.  */
 
161
  virtual_screen.fg_color = grub_video_map_color(term_color & 0x0f);
 
162
 
 
163
  /* Special case: use black as transparent color.  */
 
164
  if (((term_color >> 4) & 0x0f) == 0)
 
165
    {
 
166
      virtual_screen.bg_color = grub_video_map_rgba(0, 0, 0, 0);
 
167
    }
 
168
  else
 
169
    {
 
170
      virtual_screen.bg_color = grub_video_map_color((term_color >> 4) & 0x0f);
 
171
    }
 
172
 
 
173
  /* Restore previous target.  */
 
174
  grub_video_set_active_render_target (old_target);
 
175
}
 
176
 
 
177
static void
 
178
clear_char (struct grub_colored_char *c)
 
179
{
 
180
  grub_free (c->code);
 
181
  c->code = grub_unicode_glyph_from_code (' ');
 
182
  if (!c->code)
 
183
    grub_errno = GRUB_ERR_NONE;
 
184
  c->fg_color = virtual_screen.fg_color;
 
185
  c->bg_color = virtual_screen.bg_color;
 
186
  c->width = 0;
 
187
  c->index = 0;
 
188
}
 
189
 
 
190
static void
 
191
grub_virtual_screen_free (void)
 
192
{
 
193
  /* If virtual screen has been allocated, free it.  */
 
194
  if (virtual_screen.text_buffer != 0)
 
195
    grub_free (virtual_screen.text_buffer);
 
196
 
 
197
  /* Reset virtual screen data.  */
 
198
  grub_memset (&virtual_screen, 0, sizeof (virtual_screen));
 
199
 
 
200
  /* Free render targets.  */
 
201
  grub_video_delete_render_target (text_layer);
 
202
  text_layer = 0;
 
203
}
 
204
 
 
205
static grub_err_t
 
206
grub_virtual_screen_setup (unsigned int x, unsigned int y,
 
207
                           unsigned int width, unsigned int height,
 
208
                           const char *font_name)
 
209
{
 
210
  unsigned int i;
 
211
 
 
212
  /* Free old virtual screen.  */
 
213
  grub_virtual_screen_free ();
 
214
 
 
215
  /* Initialize with default data.  */
 
216
  virtual_screen.font = grub_font_get (font_name);
 
217
  if (!virtual_screen.font)
 
218
    return grub_error (GRUB_ERR_BAD_FONT,
 
219
                       "no font loaded");
 
220
  virtual_screen.width = width;
 
221
  virtual_screen.height = height;
 
222
  virtual_screen.offset_x = x;
 
223
  virtual_screen.offset_y = y;
 
224
  virtual_screen.normal_char_width =
 
225
    calculate_normal_character_width (virtual_screen.font);
 
226
  virtual_screen.normal_char_height =
 
227
    grub_font_get_max_char_height (virtual_screen.font);
 
228
  virtual_screen.cursor_x = 0;
 
229
  virtual_screen.cursor_y = 0;
 
230
  virtual_screen.cursor_state = 1;
 
231
  virtual_screen.total_scroll = 0;
 
232
 
 
233
  /* Calculate size of text buffer.  */
 
234
  virtual_screen.columns = virtual_screen.width / virtual_screen.normal_char_width;
 
235
  virtual_screen.rows = virtual_screen.height / virtual_screen.normal_char_height;
 
236
 
 
237
  /* Allocate memory for text buffer.  */
 
238
  virtual_screen.text_buffer =
 
239
    (struct grub_colored_char *) grub_malloc (virtual_screen.columns
 
240
                                              * virtual_screen.rows
 
241
                                              * sizeof (*virtual_screen.text_buffer));
 
242
  if (grub_errno != GRUB_ERR_NONE)
 
243
    return grub_errno;
 
244
 
 
245
  /* Create new render target for text layer.  */
 
246
  grub_video_create_render_target (&text_layer,
 
247
                                   virtual_screen.width,
 
248
                                   virtual_screen.height,
 
249
                                   GRUB_VIDEO_MODE_TYPE_RGB
 
250
                                   | GRUB_VIDEO_MODE_TYPE_ALPHA);
 
251
  if (grub_errno != GRUB_ERR_NONE)
 
252
    return grub_errno;
 
253
 
 
254
  /* As we want to have colors compatible with rendering target,
 
255
     we can only have those after mode is initialized.  */
 
256
  grub_video_set_active_render_target (text_layer);
 
257
 
 
258
  virtual_screen.standard_color_setting = DEFAULT_STANDARD_COLOR;
 
259
 
 
260
  virtual_screen.term_color = GRUB_TERM_DEFAULT_NORMAL_COLOR;
 
261
 
 
262
  set_term_color (virtual_screen.term_color);
 
263
 
 
264
  grub_video_set_active_render_target (render_target);
 
265
 
 
266
  virtual_screen.bg_color_display = grub_video_map_rgba(0, 0, 0, 0);
 
267
 
 
268
  /* Clear out text buffer. */
 
269
  for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
 
270
    {
 
271
      virtual_screen.text_buffer[i].code = 0;
 
272
      clear_char (&(virtual_screen.text_buffer[i]));
 
273
    }
 
274
 
 
275
  return grub_errno;
 
276
}
 
277
 
 
278
void
 
279
grub_gfxterm_schedule_repaint (void)
 
280
{
 
281
  repaint_scheduled = 1;
 
282
}
 
283
 
 
284
grub_err_t
 
285
grub_gfxterm_set_window (struct grub_video_render_target *target,
 
286
                         int x, int y, int width, int height,
 
287
                         int double_repaint,
 
288
                         const char *font_name, int border_width)
 
289
{
 
290
  /* Clean up any prior instance.  */
 
291
  destroy_window ();
 
292
 
 
293
  /* Set the render target.  */
 
294
  render_target = target;
 
295
 
 
296
  /* Create virtual screen.  */
 
297
  if (grub_virtual_screen_setup (border_width, border_width, 
 
298
                                 width - 2 * border_width, 
 
299
                                 height - 2 * border_width, 
 
300
                                 font_name) 
 
301
      != GRUB_ERR_NONE)
 
302
    {
 
303
      return grub_errno;
 
304
    }
 
305
 
 
306
  /* Set window bounds.  */
 
307
  window.x = x;
 
308
  window.y = y;
 
309
  window.width = width;
 
310
  window.height = height;
 
311
  window.double_repaint = double_repaint;
 
312
 
 
313
  dirty_region_reset ();
 
314
  grub_gfxterm_schedule_repaint ();
 
315
 
 
316
  return grub_errno;
 
317
}
 
318
 
 
319
grub_err_t
 
320
grub_gfxterm_fullscreen (void)
 
321
{
 
322
  const char *font_name;
 
323
  struct grub_video_mode_info mode_info;
 
324
  grub_video_color_t color;
 
325
  grub_err_t err;
 
326
  int double_redraw;
 
327
 
 
328
  err = grub_video_get_info (&mode_info);
 
329
  /* Figure out what mode we ended up.  */
 
330
  if (err)
 
331
    return err;
 
332
 
 
333
  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
 
334
 
 
335
  double_redraw = mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
 
336
    && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
 
337
 
 
338
  /* Make sure screen is black.  */
 
339
  color = grub_video_map_rgb (0, 0, 0);
 
340
  grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
 
341
  if (double_redraw)
 
342
    {
 
343
      grub_video_swap_buffers ();
 
344
      grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
 
345
    }
 
346
  bitmap = 0;
 
347
 
 
348
  /* Select the font to use.  */
 
349
  font_name = grub_env_get ("gfxterm_font");
 
350
  if (! font_name)
 
351
    font_name = "";   /* Allow fallback to any font.  */
 
352
 
 
353
  grub_gfxterm_decorator_hook = NULL;
 
354
 
 
355
  return grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY,
 
356
                                  0, 0, mode_info.width, mode_info.height,
 
357
                                  double_redraw,
 
358
                                  font_name, DEFAULT_BORDER_WIDTH);
 
359
}
 
360
 
 
361
static grub_err_t
 
362
grub_gfxterm_term_init (struct grub_term_output *term __attribute__ ((unused)))
 
363
{
 
364
  char *tmp;
 
365
  grub_err_t err;
 
366
  const char *modevar;
 
367
 
 
368
  /* Parse gfxmode environment variable if set.  */
 
369
  modevar = grub_env_get ("gfxmode");
 
370
  if (! modevar || *modevar == 0)
 
371
    err = grub_video_set_mode (DEFAULT_VIDEO_MODE,
 
372
                               GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
 
373
  else
 
374
    {
 
375
      tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
 
376
      if (!tmp)
 
377
        return grub_errno;
 
378
      err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
 
379
      grub_free (tmp);
 
380
    }
 
381
 
 
382
  if (err)
 
383
    return err;
 
384
 
 
385
  err = grub_gfxterm_fullscreen ();
 
386
  if (err)
 
387
    grub_video_restore ();
 
388
 
 
389
  return err;
 
390
}
 
391
 
 
392
static void
 
393
destroy_window (void)
 
394
{
 
395
  if (bitmap)
 
396
    {
 
397
      grub_video_bitmap_destroy (bitmap);
 
398
      bitmap = 0;
 
399
    }
 
400
 
 
401
  repaint_callback = 0;
 
402
  grub_virtual_screen_free ();
 
403
}
 
404
 
 
405
static grub_err_t
 
406
grub_gfxterm_term_fini (struct grub_term_output *term __attribute__ ((unused)))
 
407
{
 
408
  unsigned i;
 
409
  destroy_window ();
 
410
  grub_video_restore ();
 
411
 
 
412
  for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
 
413
    {
 
414
      grub_free (virtual_screen.text_buffer[i].code);
 
415
      virtual_screen.text_buffer[i].code = 0;
 
416
    }
 
417
 
 
418
  /* Clear error state.  */
 
419
  grub_errno = GRUB_ERR_NONE;
 
420
  return GRUB_ERR_NONE;
 
421
}
 
422
 
 
423
static void
 
424
redraw_screen_rect (unsigned int x, unsigned int y,
 
425
                    unsigned int width, unsigned int height)
 
426
{
 
427
  grub_video_color_t color;
 
428
  grub_video_rect_t saved_view;
 
429
 
 
430
  grub_video_set_active_render_target (render_target);
 
431
  /* Save viewport and set it to our window.  */
 
432
  grub_video_get_viewport ((unsigned *) &saved_view.x, 
 
433
                           (unsigned *) &saved_view.y, 
 
434
                           (unsigned *) &saved_view.width, 
 
435
                           (unsigned *) &saved_view.height);
 
436
  grub_video_set_viewport (window.x, window.y, window.width, window.height);
 
437
 
 
438
  if (bitmap)
 
439
    {
 
440
      /* Render bitmap as background.  */
 
441
      grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_REPLACE, x, y,
 
442
                              x, y,
 
443
                              width, height);
 
444
 
 
445
      /* If bitmap is smaller than requested blit area, use background
 
446
         color.  */
 
447
      color = virtual_screen.bg_color_display;
 
448
 
 
449
      /* Fill right side of the bitmap if needed.  */
 
450
      if ((x + width >= bitmap_width) && (y < bitmap_height))
 
451
        {
 
452
          int w = (x + width) - bitmap_width;
 
453
          int h = height;
 
454
          unsigned int tx = x;
 
455
 
 
456
          if (y + height >= bitmap_height)
 
457
            {
 
458
              h = bitmap_height - y;
 
459
            }
 
460
 
 
461
          if (bitmap_width > tx)
 
462
            {
 
463
              tx = bitmap_width;
 
464
            }
 
465
 
 
466
          /* Render background layer.  */
 
467
          grub_video_fill_rect (color, tx, y, w, h);
 
468
        }
 
469
 
 
470
      /* Fill bottom side of the bitmap if needed.  */
 
471
      if (y + height >= bitmap_height)
 
472
        {
 
473
          int h = (y + height) - bitmap_height;
 
474
          unsigned int ty = y;
 
475
 
 
476
          if (bitmap_height > ty)
 
477
            {
 
478
              ty = bitmap_height;
 
479
            }
 
480
 
 
481
          /* Render background layer.  */
 
482
          grub_video_fill_rect (color, x, ty, width, h);
 
483
        }
 
484
 
 
485
      /* Render text layer as blended.  */
 
486
      grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, x, y,
 
487
                                     x - virtual_screen.offset_x,
 
488
                                     y - virtual_screen.offset_y,
 
489
                                     width, height);
 
490
    }
 
491
  else
 
492
    {
 
493
      /* Render background layer.  */
 
494
      color = virtual_screen.bg_color_display;
 
495
      grub_video_fill_rect (color, x, y, width, height);
 
496
 
 
497
      /* Render text layer as replaced (to get texts background color).  */
 
498
      grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_REPLACE, x, y,
 
499
                                     x - virtual_screen.offset_x,
 
500
                                     y - virtual_screen.offset_y,
 
501
                                     width, height);
 
502
    }
 
503
 
 
504
  /* Restore saved viewport.  */
 
505
  grub_video_set_viewport (saved_view.x, saved_view.y,
 
506
                           saved_view.width, saved_view.height);
 
507
  grub_video_set_active_render_target (render_target);
 
508
  
 
509
  if (repaint_callback)
 
510
    repaint_callback (x, y, width, height);
 
511
}
 
512
 
 
513
static void
 
514
dirty_region_reset (void)
 
515
{
 
516
  dirty_region.top_left_x = -1;
 
517
  dirty_region.top_left_y = -1;
 
518
  dirty_region.bottom_right_x = -1;
 
519
  dirty_region.bottom_right_y = -1;
 
520
  repaint_was_scheduled = 0;
 
521
}
 
522
 
 
523
static int
 
524
dirty_region_is_empty (void)
 
525
{
 
526
  if ((dirty_region.top_left_x == -1)
 
527
      || (dirty_region.top_left_y == -1)
 
528
      || (dirty_region.bottom_right_x == -1)
 
529
      || (dirty_region.bottom_right_y == -1))
 
530
    return 1;
 
531
  return 0;
 
532
}
 
533
 
 
534
static void
 
535
dirty_region_add (int x, int y, unsigned int width, unsigned int height)
 
536
{
 
537
  if ((width == 0) || (height == 0))
 
538
    return;
 
539
 
 
540
  if (repaint_scheduled)
 
541
    {
 
542
      x = virtual_screen.offset_x;
 
543
      y = virtual_screen.offset_y;
 
544
      width = virtual_screen.width;
 
545
      height = virtual_screen.height;
 
546
      repaint_scheduled = 0;
 
547
      repaint_was_scheduled = 1;
 
548
    }
 
549
 
 
550
  if (dirty_region_is_empty ())
 
551
    {
 
552
      dirty_region.top_left_x = x;
 
553
      dirty_region.top_left_y = y;
 
554
      dirty_region.bottom_right_x = x + width - 1;
 
555
      dirty_region.bottom_right_y = y + height - 1;
 
556
    }
 
557
  else
 
558
    {
 
559
      if (x < dirty_region.top_left_x)
 
560
        dirty_region.top_left_x = x;
 
561
      if (y < dirty_region.top_left_y)
 
562
        dirty_region.top_left_y = y;
 
563
      if ((x + (int)width - 1) > dirty_region.bottom_right_x)
 
564
        dirty_region.bottom_right_x = x + width - 1;
 
565
      if ((y + (int)height - 1) > dirty_region.bottom_right_y)
 
566
        dirty_region.bottom_right_y = y + height - 1;
 
567
    }
 
568
}
 
569
 
 
570
static void
 
571
dirty_region_add_virtualscreen (void)
 
572
{
 
573
  /* Mark virtual screen as dirty.  */
 
574
  dirty_region_add (virtual_screen.offset_x, virtual_screen.offset_y,
 
575
                    virtual_screen.width, virtual_screen.height);
 
576
}
 
577
 
 
578
 
 
579
static void
 
580
dirty_region_redraw (void)
 
581
{
 
582
  int x;
 
583
  int y;
 
584
  int width;
 
585
  int height;
 
586
 
 
587
  if (dirty_region_is_empty ())
 
588
    return;
 
589
 
 
590
  x = dirty_region.top_left_x;
 
591
  y = dirty_region.top_left_y;
 
592
 
 
593
  width = dirty_region.bottom_right_x - x + 1;
 
594
  height = dirty_region.bottom_right_y - y + 1;
 
595
 
 
596
  if (repaint_was_scheduled && grub_gfxterm_decorator_hook)
 
597
    grub_gfxterm_decorator_hook ();
 
598
 
 
599
  redraw_screen_rect (x, y, width, height);
 
600
}
 
601
 
 
602
static inline void
 
603
paint_char (unsigned cx, unsigned cy)
 
604
{
 
605
  struct grub_colored_char *p;
 
606
  struct grub_font_glyph *glyph;
 
607
  grub_video_color_t color;
 
608
  grub_video_color_t bgcolor;
 
609
  unsigned int x;
 
610
  unsigned int y;
 
611
  int ascent;
 
612
  unsigned int height;
 
613
  unsigned int width;
 
614
 
 
615
  if (cy + virtual_screen.total_scroll >= virtual_screen.rows)
 
616
    return;
 
617
 
 
618
  /* Find out active character.  */
 
619
  p = (virtual_screen.text_buffer
 
620
       + cx + (cy * virtual_screen.columns));
 
621
 
 
622
  p -= p->index;
 
623
 
 
624
  /* Get glyph for character.  */
 
625
  glyph = grub_font_construct_glyph (virtual_screen.font, p->code);
 
626
  if (!glyph)
 
627
    {
 
628
      grub_errno = GRUB_ERR_NONE;
 
629
      return;
 
630
    }
 
631
  ascent = grub_font_get_ascent (virtual_screen.font);
 
632
 
 
633
  width = virtual_screen.normal_char_width * calculate_character_width(glyph);
 
634
  height = virtual_screen.normal_char_height;
 
635
 
 
636
  color = p->fg_color;
 
637
  bgcolor = p->bg_color;
 
638
 
 
639
  x = cx * virtual_screen.normal_char_width;
 
640
  y = (cy + virtual_screen.total_scroll) * virtual_screen.normal_char_height;
 
641
 
 
642
  /* Render glyph to text layer.  */
 
643
  grub_video_set_active_render_target (text_layer);
 
644
  grub_video_fill_rect (bgcolor, x, y, width, height);
 
645
  grub_font_draw_glyph (glyph, color, x, y + ascent);
 
646
  grub_video_set_active_render_target (render_target);
 
647
 
 
648
  /* Mark character to be drawn.  */
 
649
  dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
 
650
                    width, height);
 
651
  grub_free (glyph);
 
652
}
 
653
 
 
654
static inline void
 
655
write_char (void)
 
656
{
 
657
  paint_char (virtual_screen.cursor_x, virtual_screen.cursor_y);
 
658
}
 
659
 
 
660
static inline void
 
661
draw_cursor (int show)
 
662
{
 
663
  unsigned int x;
 
664
  unsigned int y;
 
665
  unsigned int width;
 
666
  unsigned int height;
 
667
  grub_video_color_t color;
 
668
  
 
669
  write_char ();
 
670
 
 
671
  if (!show)
 
672
    return;
 
673
 
 
674
  if (virtual_screen.cursor_y + virtual_screen.total_scroll
 
675
      >= virtual_screen.rows)
 
676
    return;
 
677
 
 
678
  /* Determine cursor properties and position on text layer. */
 
679
  x = virtual_screen.cursor_x * virtual_screen.normal_char_width;
 
680
  width = virtual_screen.normal_char_width;
 
681
  color = virtual_screen.fg_color;
 
682
  y = ((virtual_screen.cursor_y + virtual_screen.total_scroll)
 
683
       * virtual_screen.normal_char_height
 
684
       + grub_font_get_ascent (virtual_screen.font));
 
685
  height = 2;
 
686
  
 
687
  /* Render cursor to text layer.  */
 
688
  grub_video_set_active_render_target (text_layer);
 
689
  grub_video_fill_rect (color, x, y, width, height);
 
690
  grub_video_set_active_render_target (render_target);
 
691
  
 
692
  /* Mark cursor to be redrawn.  */
 
693
  dirty_region_add (virtual_screen.offset_x + x,
 
694
                    virtual_screen.offset_y + y,
 
695
                    width, height);
 
696
}
 
697
 
 
698
static void
 
699
real_scroll (void)
 
700
{
 
701
  unsigned int i, j, was_scroll;
 
702
  grub_video_color_t color;
 
703
 
 
704
  if (!virtual_screen.total_scroll)
 
705
    return;
 
706
 
 
707
  /* If we have bitmap, re-draw screen, otherwise scroll physical screen too.  */
 
708
  if (bitmap)
 
709
    {
 
710
      /* Scroll physical screen.  */
 
711
      grub_video_set_active_render_target (text_layer);
 
712
      color = virtual_screen.bg_color;
 
713
      grub_video_scroll (color, 0, -virtual_screen.normal_char_height
 
714
                         * virtual_screen.total_scroll);
 
715
 
 
716
      /* Mark virtual screen to be redrawn.  */
 
717
      dirty_region_add_virtualscreen ();
 
718
    }
 
719
  else
 
720
    {
 
721
      grub_video_rect_t saved_view;
 
722
 
 
723
      /* Remove cursor.  */
 
724
      draw_cursor (0);
 
725
 
 
726
      grub_video_set_active_render_target (render_target);
 
727
 
 
728
      i = window.double_repaint ? 2 : 1;
 
729
 
 
730
      color = virtual_screen.bg_color;
 
731
 
 
732
      while (i--)
 
733
        {
 
734
          /* Save viewport and set it to our window.  */
 
735
          grub_video_get_viewport ((unsigned *) &saved_view.x, 
 
736
                                   (unsigned *) &saved_view.y, 
 
737
                                   (unsigned *) &saved_view.width, 
 
738
                                   (unsigned *) &saved_view.height);
 
739
 
 
740
          grub_video_set_viewport (window.x, window.y, window.width,
 
741
                                   window.height);
 
742
 
 
743
          /* Clear new border area.  */
 
744
          grub_video_fill_rect (color,
 
745
                                virtual_screen.offset_x,
 
746
                                virtual_screen.offset_y,
 
747
                                virtual_screen.width,
 
748
                                virtual_screen.normal_char_height
 
749
                                * virtual_screen.total_scroll);
 
750
 
 
751
          grub_video_set_active_render_target (render_target);
 
752
          dirty_region_redraw ();
 
753
 
 
754
          /* Scroll physical screen.  */
 
755
          grub_video_scroll (color, 0, -virtual_screen.normal_char_height
 
756
                             * virtual_screen.total_scroll);
 
757
 
 
758
          /* Restore saved viewport.  */
 
759
          grub_video_set_viewport (saved_view.x, saved_view.y,
 
760
                                   saved_view.width, saved_view.height);
 
761
 
 
762
          if (i)
 
763
            grub_video_swap_buffers ();
 
764
        }
 
765
      dirty_region_reset ();
 
766
 
 
767
      /* Scroll physical screen.  */
 
768
      grub_video_set_active_render_target (text_layer);
 
769
      color = virtual_screen.bg_color;
 
770
      grub_video_scroll (color, 0, -virtual_screen.normal_char_height
 
771
                         * virtual_screen.total_scroll);
 
772
 
 
773
      grub_video_set_active_render_target (render_target);
 
774
 
 
775
    }
 
776
 
 
777
  was_scroll = virtual_screen.total_scroll;
 
778
  virtual_screen.total_scroll = 0;
 
779
 
 
780
  if (was_scroll > virtual_screen.rows)
 
781
    was_scroll = virtual_screen.rows;
 
782
 
 
783
  /* Draw shadow part.  */
 
784
  for (i = virtual_screen.rows - was_scroll;
 
785
       i < virtual_screen.rows; i++)
 
786
    for (j = 0; j < virtual_screen.columns; j++)
 
787
      paint_char (j, i);
 
788
 
 
789
  /* Draw cursor if visible.  */
 
790
  if (virtual_screen.cursor_state)
 
791
    draw_cursor (1);
 
792
 
 
793
  if (repaint_callback)
 
794
    repaint_callback (window.x, window.y, window.width, window.height);
 
795
}
 
796
 
 
797
static void
 
798
scroll_up (void)
 
799
{
 
800
  unsigned int i;
 
801
 
 
802
  /* Clear first line in text buffer.  */
 
803
  for (i = 0; i < virtual_screen.columns; i++)
 
804
    grub_free (virtual_screen.text_buffer[i].code);
 
805
 
 
806
  /* Scroll text buffer with one line to up.  */
 
807
  grub_memmove (virtual_screen.text_buffer,
 
808
                virtual_screen.text_buffer + virtual_screen.columns,
 
809
                sizeof (*virtual_screen.text_buffer)
 
810
                * virtual_screen.columns
 
811
                * (virtual_screen.rows - 1));
 
812
 
 
813
  /* Clear last line in text buffer.  */
 
814
  for (i = virtual_screen.columns * (virtual_screen.rows - 1);
 
815
       i < virtual_screen.columns * virtual_screen.rows;
 
816
       i++)
 
817
    {
 
818
      virtual_screen.text_buffer[i].code = 0;
 
819
      clear_char (&(virtual_screen.text_buffer[i]));
 
820
    }
 
821
 
 
822
  virtual_screen.total_scroll++;
 
823
}
 
824
 
 
825
static void
 
826
grub_gfxterm_putchar (struct grub_term_output *term,
 
827
                      const struct grub_unicode_glyph *c)
 
828
{
 
829
  if (c->base == '\a')
 
830
    /* FIXME */
 
831
    return;
 
832
 
 
833
  /* Erase current cursor, if any.  */
 
834
  if (virtual_screen.cursor_state)
 
835
    draw_cursor (0);
 
836
 
 
837
  if (c->base == '\b' || c->base == '\n' || c->base == '\r')
 
838
    {
 
839
      switch (c->base)
 
840
        {
 
841
        case '\b':
 
842
          if (virtual_screen.cursor_x > 0)
 
843
            virtual_screen.cursor_x--;
 
844
          break;
 
845
 
 
846
        case '\n':
 
847
          if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
 
848
            scroll_up ();
 
849
          else
 
850
            virtual_screen.cursor_y++;
 
851
          break;
 
852
 
 
853
        case '\r':
 
854
          virtual_screen.cursor_x = 0;
 
855
          break;
 
856
        }
 
857
    }
 
858
  else
 
859
    {
 
860
      struct grub_colored_char *p;
 
861
      unsigned char char_width;
 
862
 
 
863
      /* Calculate actual character width for glyph. This is number of
 
864
         times of normal_font_width.  */
 
865
      char_width = grub_gfxterm_getcharwidth (term, c);
 
866
 
 
867
      /* If we are about to exceed line length, wrap to next line.  */
 
868
      if (virtual_screen.cursor_x + char_width > virtual_screen.columns)
 
869
        {
 
870
          if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
 
871
            scroll_up ();
 
872
          else
 
873
            virtual_screen.cursor_y++;
 
874
        }
 
875
 
 
876
      /* Find position on virtual screen, and fill information.  */
 
877
      p = (virtual_screen.text_buffer +
 
878
           virtual_screen.cursor_x +
 
879
           virtual_screen.cursor_y * virtual_screen.columns);
 
880
      grub_free (p->code);
 
881
      p->code = grub_unicode_glyph_dup (c);
 
882
      if (!p->code)
 
883
        grub_errno = GRUB_ERR_NONE;
 
884
      p->fg_color = virtual_screen.fg_color;
 
885
      p->bg_color = virtual_screen.bg_color;
 
886
      p->width = char_width - 1;
 
887
      p->index = 0;
 
888
 
 
889
      /* If we have large glyph, add fixup info.  */
 
890
      if (char_width > 1)
 
891
        {
 
892
          unsigned i;
 
893
 
 
894
          for (i = 1; i < char_width; i++)
 
895
            {
 
896
              grub_free (p[i].code);
 
897
              p[i].code = grub_unicode_glyph_from_code (' ');
 
898
              if (!p[i].code)
 
899
                grub_errno = GRUB_ERR_NONE;
 
900
              p[i].width = char_width - 1;
 
901
              p[i].index = i;
 
902
            }
 
903
        }
 
904
 
 
905
      /* Draw glyph.  */
 
906
      write_char ();
 
907
 
 
908
      /* Make sure we scroll screen when needed and wrap line correctly.  */
 
909
      virtual_screen.cursor_x += char_width;
 
910
      if (virtual_screen.cursor_x >= virtual_screen.columns)
 
911
        {
 
912
          virtual_screen.cursor_x = 0;
 
913
 
 
914
          if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
 
915
            scroll_up ();
 
916
          else
 
917
            virtual_screen.cursor_y++;
 
918
        }
 
919
    }
 
920
 
 
921
  /* Redraw cursor if it should be visible.  */
 
922
  /* Note: This will redraw the character as well, which means that the
 
923
     above call to write_char is redundant when the cursor is showing.  */
 
924
  if (virtual_screen.cursor_state)
 
925
    draw_cursor (1);
 
926
}
 
927
 
 
928
/* Use ASCII characters to determine normal character width.  */
 
929
static unsigned int
 
930
calculate_normal_character_width (grub_font_t font)
 
931
{
 
932
  struct grub_font_glyph *glyph;
 
933
  unsigned int width = 0;
 
934
  unsigned int i;
 
935
 
 
936
  /* Get properties of every printable ASCII character.  */
 
937
  for (i = 32; i < 127; i++)
 
938
    {
 
939
      glyph = grub_font_get_glyph (font, i);
 
940
 
 
941
      /* Skip unknown characters.  Should never happen on normal conditions.  */
 
942
      if (! glyph)
 
943
        continue;
 
944
 
 
945
      if (glyph->device_width > width)
 
946
        width = glyph->device_width;
 
947
    }
 
948
 
 
949
  return width;
 
950
}
 
951
 
 
952
static unsigned char
 
953
calculate_character_width (struct grub_font_glyph *glyph)
 
954
{
 
955
  if (! glyph || glyph->device_width == 0)
 
956
    return 1;
 
957
 
 
958
  return (glyph->device_width
 
959
          + (virtual_screen.normal_char_width - 1))
 
960
         / virtual_screen.normal_char_width;
 
961
}
 
962
 
 
963
static grub_ssize_t
 
964
grub_gfxterm_getcharwidth (struct grub_term_output *term __attribute__ ((unused)),
 
965
                           const struct grub_unicode_glyph *c)
 
966
{
 
967
  int dev_width;
 
968
  dev_width = grub_font_get_constructed_device_width (virtual_screen.font, c);
 
969
 
 
970
  if (dev_width == 0)
 
971
    return 1;
 
972
 
 
973
  return (dev_width + (virtual_screen.normal_char_width - 1))
 
974
    / virtual_screen.normal_char_width;
 
975
}
 
976
 
 
977
static grub_uint16_t
 
978
grub_virtual_screen_getwh (struct grub_term_output *term __attribute__ ((unused)))
 
979
{
 
980
  return (virtual_screen.columns << 8) | virtual_screen.rows;
 
981
}
 
982
 
 
983
static grub_uint16_t
 
984
grub_virtual_screen_getxy (struct grub_term_output *term __attribute__ ((unused)))
 
985
{
 
986
  return ((virtual_screen.cursor_x << 8) | virtual_screen.cursor_y);
 
987
}
 
988
 
 
989
static void
 
990
grub_gfxterm_gotoxy (struct grub_term_output *term __attribute__ ((unused)),
 
991
                     grub_uint8_t x, grub_uint8_t y)
 
992
{
 
993
  if (x >= virtual_screen.columns)
 
994
    x = virtual_screen.columns - 1;
 
995
 
 
996
  if (y >= virtual_screen.rows)
 
997
    y = virtual_screen.rows - 1;
 
998
 
 
999
  /* Erase current cursor, if any.  */
 
1000
  if (virtual_screen.cursor_state)
 
1001
    draw_cursor (0);
 
1002
 
 
1003
  virtual_screen.cursor_x = x;
 
1004
  virtual_screen.cursor_y = y;
 
1005
 
 
1006
  /* Draw cursor if visible.  */
 
1007
  if (virtual_screen.cursor_state)
 
1008
    draw_cursor (1);
 
1009
}
 
1010
 
 
1011
static void
 
1012
grub_virtual_screen_cls (struct grub_term_output *term __attribute__ ((unused)))
 
1013
{
 
1014
  grub_uint32_t i;
 
1015
 
 
1016
  for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
 
1017
    clear_char (&(virtual_screen.text_buffer[i]));
 
1018
 
 
1019
  virtual_screen.cursor_x = virtual_screen.cursor_y = 0;
 
1020
}
 
1021
 
 
1022
static void
 
1023
grub_gfxterm_cls (struct grub_term_output *term)
 
1024
{
 
1025
  grub_video_color_t color;
 
1026
 
 
1027
  /* Clear virtual screen.  */
 
1028
  grub_virtual_screen_cls (term);
 
1029
 
 
1030
  /* Clear text layer.  */
 
1031
  grub_video_set_active_render_target (text_layer);
 
1032
  color = virtual_screen.bg_color;
 
1033
  grub_video_fill_rect (color, 0, 0,
 
1034
                        virtual_screen.width, virtual_screen.height);
 
1035
  grub_video_set_active_render_target (render_target);
 
1036
 
 
1037
  /* Mark virtual screen to be redrawn.  */
 
1038
  dirty_region_add_virtualscreen ();
 
1039
 
 
1040
  grub_gfxterm_refresh (term);
 
1041
}
 
1042
 
 
1043
static void
 
1044
grub_virtual_screen_setcolorstate (struct grub_term_output *term,
 
1045
                                   grub_term_color_state state)
 
1046
{
 
1047
  switch (state)
 
1048
    {
 
1049
    case GRUB_TERM_COLOR_STANDARD:
 
1050
      virtual_screen.term_color = virtual_screen.standard_color_setting;
 
1051
      break;
 
1052
 
 
1053
    case GRUB_TERM_COLOR_NORMAL:
 
1054
      virtual_screen.term_color = term->normal_color;
 
1055
      break;
 
1056
 
 
1057
    case GRUB_TERM_COLOR_HIGHLIGHT:
 
1058
      virtual_screen.term_color = term->highlight_color;
 
1059
      break;
 
1060
 
 
1061
    default:
 
1062
      break;
 
1063
    }
 
1064
 
 
1065
  /* Change color to virtual terminal.  */
 
1066
  set_term_color (virtual_screen.term_color);
 
1067
}
 
1068
 
 
1069
static void
 
1070
grub_gfxterm_setcursor (struct grub_term_output *term __attribute__ ((unused)),
 
1071
                        int on)
 
1072
{
 
1073
  if (virtual_screen.cursor_state != on)
 
1074
    {
 
1075
      if (virtual_screen.cursor_state)
 
1076
        draw_cursor (0);
 
1077
      else
 
1078
        draw_cursor (1);
 
1079
 
 
1080
      virtual_screen.cursor_state = on;
 
1081
    }
 
1082
}
 
1083
 
 
1084
static void
 
1085
grub_gfxterm_refresh (struct grub_term_output *term __attribute__ ((unused)))
 
1086
{
 
1087
  real_scroll ();
 
1088
 
 
1089
  /* Redraw only changed regions.  */
 
1090
  dirty_region_redraw ();
 
1091
 
 
1092
  grub_video_swap_buffers ();
 
1093
 
 
1094
  if (window.double_repaint)
 
1095
    dirty_region_redraw ();
 
1096
  dirty_region_reset ();
 
1097
}
 
1098
 
 
1099
void 
 
1100
grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func)
 
1101
{
 
1102
  repaint_callback = func;
 
1103
}
 
1104
 
 
1105
/* Option array indices.  */
 
1106
#define BACKGROUND_CMD_ARGINDEX_MODE 0
 
1107
 
 
1108
static const struct grub_arg_option background_image_cmd_options[] =
 
1109
  {
 
1110
    {"mode", 'm', 0, "Background image mode.", "stretch|normal",
 
1111
     ARG_TYPE_STRING},
 
1112
    {0, 0, 0, 0, 0, 0}
 
1113
  };
 
1114
 
 
1115
static grub_err_t
 
1116
grub_gfxterm_background_image_cmd (grub_extcmd_context_t ctxt,
 
1117
                                   int argc, char **args)
 
1118
{
 
1119
  struct grub_arg_list *state = ctxt->state;
 
1120
 
 
1121
  /* Check that we have video adapter active.  */
 
1122
  if (grub_video_get_info(NULL) != GRUB_ERR_NONE)
 
1123
    return grub_errno;
 
1124
 
 
1125
  /* Destroy existing background bitmap if loaded.  */
 
1126
  if (bitmap)
 
1127
    {
 
1128
      grub_video_bitmap_destroy (bitmap);
 
1129
      bitmap = 0;
 
1130
 
 
1131
      /* Mark whole screen as dirty.  */
 
1132
      dirty_region_add (0, 0, window.width, window.height);
 
1133
    }
 
1134
 
 
1135
  /* If filename was provided, try to load that.  */
 
1136
  if (argc >= 1)
 
1137
    {
 
1138
      /* Try to load new one.  */
 
1139
      grub_video_bitmap_load (&bitmap, args[0]);
 
1140
      if (grub_errno != GRUB_ERR_NONE)
 
1141
        return grub_errno;
 
1142
 
 
1143
      /* Determine if the bitmap should be scaled to fit the screen.  */
 
1144
      if (!state[BACKGROUND_CMD_ARGINDEX_MODE].set
 
1145
          || grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_MODE].arg,
 
1146
                          "stretch") == 0)
 
1147
          {
 
1148
            if (window.width != grub_video_bitmap_get_width (bitmap)
 
1149
                || window.height != grub_video_bitmap_get_height (bitmap))
 
1150
              {
 
1151
                struct grub_video_bitmap *scaled_bitmap;
 
1152
                grub_video_bitmap_create_scaled (&scaled_bitmap,
 
1153
                                                 window.width, 
 
1154
                                                 window.height,
 
1155
                                                 bitmap,
 
1156
                                                 GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
 
1157
                if (grub_errno == GRUB_ERR_NONE)
 
1158
                  {
 
1159
                    /* Replace the original bitmap with the scaled one.  */
 
1160
                    grub_video_bitmap_destroy (bitmap);
 
1161
                    bitmap = scaled_bitmap;
 
1162
                  }
 
1163
              }
 
1164
          }
 
1165
 
 
1166
      /* If bitmap was loaded correctly, display it.  */
 
1167
      if (bitmap)
 
1168
        {
 
1169
          /* Determine bitmap dimensions.  */
 
1170
          bitmap_width = grub_video_bitmap_get_width (bitmap);
 
1171
          bitmap_height = grub_video_bitmap_get_height (bitmap);
 
1172
 
 
1173
          /* Mark whole screen as dirty.  */
 
1174
          dirty_region_add (0, 0, window.width, window.height);
 
1175
        }
 
1176
    }
 
1177
 
 
1178
  /* All was ok.  */
 
1179
  grub_errno = GRUB_ERR_NONE;
 
1180
  return grub_errno;
 
1181
}
 
1182
 
 
1183
static struct grub_term_output grub_video_term =
 
1184
  {
 
1185
    .name = "gfxterm",
 
1186
    .init = grub_gfxterm_term_init,
 
1187
    .fini = grub_gfxterm_term_fini,
 
1188
    .putchar = grub_gfxterm_putchar,
 
1189
    .getcharwidth = grub_gfxterm_getcharwidth,
 
1190
    .getwh = grub_virtual_screen_getwh,
 
1191
    .getxy = grub_virtual_screen_getxy,
 
1192
    .gotoxy = grub_gfxterm_gotoxy,
 
1193
    .cls = grub_gfxterm_cls,
 
1194
    .setcolorstate = grub_virtual_screen_setcolorstate,
 
1195
    .setcursor = grub_gfxterm_setcursor,
 
1196
    .refresh = grub_gfxterm_refresh,
 
1197
    .flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS,
 
1198
    .normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR,
 
1199
    .highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR,
 
1200
    .next = 0
 
1201
  };
 
1202
 
 
1203
static grub_extcmd_t background_image_cmd_handle;
 
1204
 
 
1205
GRUB_MOD_INIT(gfxterm)
 
1206
{
 
1207
  grub_term_register_output ("gfxterm", &grub_video_term);
 
1208
  background_image_cmd_handle =
 
1209
    grub_register_extcmd ("background_image",
 
1210
                          grub_gfxterm_background_image_cmd, 0,
 
1211
                          N_("[-m (stretch|normal)] FILE"),
 
1212
                          N_("Load background image for active terminal."),
 
1213
                          background_image_cmd_options);
 
1214
}
 
1215
 
 
1216
GRUB_MOD_FINI(gfxterm)
 
1217
{
 
1218
  grub_unregister_extcmd (background_image_cmd_handle);
 
1219
  grub_term_unregister_output (&grub_video_term);
 
1220
}