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

« back to all changes in this revision

Viewing changes to term/gfxterm.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2011-02-08 11:39:26 UTC
  • mfrom: (17.6.26 experimental)
  • mto: (17.6.27 experimental)
  • mto: This revision was merged to the branch mainline in revision 104.
  • Revision ID: james.westby@ubuntu.com-20110208113926-clfs90haboyk9zip
Tags: 1.99~rc1-2
* Merge 1.98+20100804-13 and 1.98+20100804-14, updating translations:
  - Kazakh (Baurzhan Muftakhidinov / Timur Birsh).
* mkconfig_skip_dmcrypt.patch: Refer to GRUB_PRELOAD_MODULES rather than
  suggesting people write a /etc/grub.d/01_modules script (thanks, Jordan
  Uggla).
* Handle empty dir passed to grub_find_root_device_from_mountinfo; fixes
  grub-mkrelpath on btrfs subvolumes (LP: #712029).
* Add rootflags=subvol=<name> if / is on a btrfs subvolume (LP: #712029).
* Upload to unstable.

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
 
  destroy_window ();
409
 
  grub_video_restore ();
410
 
 
411
 
  /* Clear error state.  */
412
 
  grub_errno = GRUB_ERR_NONE;
413
 
  return GRUB_ERR_NONE;
414
 
}
415
 
 
416
 
static void
417
 
redraw_screen_rect (unsigned int x, unsigned int y,
418
 
                    unsigned int width, unsigned int height)
419
 
{
420
 
  grub_video_color_t color;
421
 
  grub_video_rect_t saved_view;
422
 
 
423
 
  grub_video_set_active_render_target (render_target);
424
 
  /* Save viewport and set it to our window.  */
425
 
  grub_video_get_viewport ((unsigned *) &saved_view.x, 
426
 
                           (unsigned *) &saved_view.y, 
427
 
                           (unsigned *) &saved_view.width, 
428
 
                           (unsigned *) &saved_view.height);
429
 
  grub_video_set_viewport (window.x, window.y, window.width, window.height);
430
 
 
431
 
  if (bitmap)
432
 
    {
433
 
      /* Render bitmap as background.  */
434
 
      grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_REPLACE, x, y,
435
 
                              x, y,
436
 
                              width, height);
437
 
 
438
 
      /* If bitmap is smaller than requested blit area, use background
439
 
         color.  */
440
 
      color = virtual_screen.bg_color_display;
441
 
 
442
 
      /* Fill right side of the bitmap if needed.  */
443
 
      if ((x + width >= bitmap_width) && (y < bitmap_height))
444
 
        {
445
 
          int w = (x + width) - bitmap_width;
446
 
          int h = height;
447
 
          unsigned int tx = x;
448
 
 
449
 
          if (y + height >= bitmap_height)
450
 
            {
451
 
              h = bitmap_height - y;
452
 
            }
453
 
 
454
 
          if (bitmap_width > tx)
455
 
            {
456
 
              tx = bitmap_width;
457
 
            }
458
 
 
459
 
          /* Render background layer.  */
460
 
          grub_video_fill_rect (color, tx, y, w, h);
461
 
        }
462
 
 
463
 
      /* Fill bottom side of the bitmap if needed.  */
464
 
      if (y + height >= bitmap_height)
465
 
        {
466
 
          int h = (y + height) - bitmap_height;
467
 
          unsigned int ty = y;
468
 
 
469
 
          if (bitmap_height > ty)
470
 
            {
471
 
              ty = bitmap_height;
472
 
            }
473
 
 
474
 
          /* Render background layer.  */
475
 
          grub_video_fill_rect (color, x, ty, width, h);
476
 
        }
477
 
 
478
 
      /* Render text layer as blended.  */
479
 
      grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, x, y,
480
 
                                     x - virtual_screen.offset_x,
481
 
                                     y - virtual_screen.offset_y,
482
 
                                     width, height);
483
 
    }
484
 
  else
485
 
    {
486
 
      /* Render background layer.  */
487
 
      color = virtual_screen.bg_color_display;
488
 
      grub_video_fill_rect (color, x, y, width, height);
489
 
 
490
 
      /* Render text layer as replaced (to get texts background color).  */
491
 
      grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_REPLACE, x, y,
492
 
                                     x - virtual_screen.offset_x,
493
 
                                     y - virtual_screen.offset_y,
494
 
                                     width, height);
495
 
    }
496
 
 
497
 
  /* Restore saved viewport.  */
498
 
  grub_video_set_viewport (saved_view.x, saved_view.y,
499
 
                           saved_view.width, saved_view.height);
500
 
  grub_video_set_active_render_target (render_target);
501
 
  
502
 
  if (repaint_callback)
503
 
    repaint_callback (x, y, width, height);
504
 
}
505
 
 
506
 
static void
507
 
dirty_region_reset (void)
508
 
{
509
 
  dirty_region.top_left_x = -1;
510
 
  dirty_region.top_left_y = -1;
511
 
  dirty_region.bottom_right_x = -1;
512
 
  dirty_region.bottom_right_y = -1;
513
 
  repaint_was_scheduled = 0;
514
 
}
515
 
 
516
 
static int
517
 
dirty_region_is_empty (void)
518
 
{
519
 
  if ((dirty_region.top_left_x == -1)
520
 
      || (dirty_region.top_left_y == -1)
521
 
      || (dirty_region.bottom_right_x == -1)
522
 
      || (dirty_region.bottom_right_y == -1))
523
 
    return 1;
524
 
  return 0;
525
 
}
526
 
 
527
 
static void
528
 
dirty_region_add (int x, int y, unsigned int width, unsigned int height)
529
 
{
530
 
  if ((width == 0) || (height == 0))
531
 
    return;
532
 
 
533
 
  if (repaint_scheduled)
534
 
    {
535
 
      x = virtual_screen.offset_x;
536
 
      y = virtual_screen.offset_y;
537
 
      width = virtual_screen.width;
538
 
      height = virtual_screen.height;
539
 
      repaint_scheduled = 0;
540
 
      repaint_was_scheduled = 1;
541
 
    }
542
 
 
543
 
  if (dirty_region_is_empty ())
544
 
    {
545
 
      dirty_region.top_left_x = x;
546
 
      dirty_region.top_left_y = y;
547
 
      dirty_region.bottom_right_x = x + width - 1;
548
 
      dirty_region.bottom_right_y = y + height - 1;
549
 
    }
550
 
  else
551
 
    {
552
 
      if (x < dirty_region.top_left_x)
553
 
        dirty_region.top_left_x = x;
554
 
      if (y < dirty_region.top_left_y)
555
 
        dirty_region.top_left_y = y;
556
 
      if ((x + (int)width - 1) > dirty_region.bottom_right_x)
557
 
        dirty_region.bottom_right_x = x + width - 1;
558
 
      if ((y + (int)height - 1) > dirty_region.bottom_right_y)
559
 
        dirty_region.bottom_right_y = y + height - 1;
560
 
    }
561
 
}
562
 
 
563
 
static void
564
 
dirty_region_add_virtualscreen (void)
565
 
{
566
 
  /* Mark virtual screen as dirty.  */
567
 
  dirty_region_add (virtual_screen.offset_x, virtual_screen.offset_y,
568
 
                    virtual_screen.width, virtual_screen.height);
569
 
}
570
 
 
571
 
 
572
 
static void
573
 
dirty_region_redraw (void)
574
 
{
575
 
  int x;
576
 
  int y;
577
 
  int width;
578
 
  int height;
579
 
 
580
 
  if (dirty_region_is_empty ())
581
 
    return;
582
 
 
583
 
  x = dirty_region.top_left_x;
584
 
  y = dirty_region.top_left_y;
585
 
 
586
 
  width = dirty_region.bottom_right_x - x + 1;
587
 
  height = dirty_region.bottom_right_y - y + 1;
588
 
 
589
 
  if (repaint_was_scheduled && grub_gfxterm_decorator_hook)
590
 
    grub_gfxterm_decorator_hook ();
591
 
 
592
 
  redraw_screen_rect (x, y, width, height);
593
 
}
594
 
 
595
 
static inline void
596
 
paint_char (unsigned cx, unsigned cy)
597
 
{
598
 
  struct grub_colored_char *p;
599
 
  struct grub_font_glyph *glyph;
600
 
  grub_video_color_t color;
601
 
  grub_video_color_t bgcolor;
602
 
  unsigned int x;
603
 
  unsigned int y;
604
 
  int ascent;
605
 
  unsigned int height;
606
 
  unsigned int width;
607
 
 
608
 
  if (cy + virtual_screen.total_scroll >= virtual_screen.rows)
609
 
    return;
610
 
 
611
 
  /* Find out active character.  */
612
 
  p = (virtual_screen.text_buffer
613
 
       + cx + (cy * virtual_screen.columns));
614
 
 
615
 
  p -= p->index;
616
 
 
617
 
  /* Get glyph for character.  */
618
 
  glyph = grub_font_construct_glyph (virtual_screen.font, p->code);
619
 
  if (!glyph)
620
 
    {
621
 
      grub_errno = GRUB_ERR_NONE;
622
 
      return;
623
 
    }
624
 
  ascent = grub_font_get_ascent (virtual_screen.font);
625
 
 
626
 
  width = virtual_screen.normal_char_width * calculate_character_width(glyph);
627
 
  height = virtual_screen.normal_char_height;
628
 
 
629
 
  color = p->fg_color;
630
 
  bgcolor = p->bg_color;
631
 
 
632
 
  x = cx * virtual_screen.normal_char_width;
633
 
  y = (cy + virtual_screen.total_scroll) * virtual_screen.normal_char_height;
634
 
 
635
 
  /* Render glyph to text layer.  */
636
 
  grub_video_set_active_render_target (text_layer);
637
 
  grub_video_fill_rect (bgcolor, x, y, width, height);
638
 
  grub_font_draw_glyph (glyph, color, x, y + ascent);
639
 
  grub_video_set_active_render_target (render_target);
640
 
 
641
 
  /* Mark character to be drawn.  */
642
 
  dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
643
 
                    width, height);
644
 
  grub_free (glyph);
645
 
}
646
 
 
647
 
static inline void
648
 
write_char (void)
649
 
{
650
 
  paint_char (virtual_screen.cursor_x, virtual_screen.cursor_y);
651
 
}
652
 
 
653
 
static inline void
654
 
draw_cursor (int show)
655
 
{
656
 
  unsigned int x;
657
 
  unsigned int y;
658
 
  unsigned int width;
659
 
  unsigned int height;
660
 
  grub_video_color_t color;
661
 
  
662
 
  write_char ();
663
 
 
664
 
  if (!show)
665
 
    return;
666
 
 
667
 
  if (virtual_screen.cursor_y + virtual_screen.total_scroll
668
 
      >= virtual_screen.rows)
669
 
    return;
670
 
 
671
 
  /* Determine cursor properties and position on text layer. */
672
 
  x = virtual_screen.cursor_x * virtual_screen.normal_char_width;
673
 
  width = virtual_screen.normal_char_width;
674
 
  color = virtual_screen.fg_color;
675
 
  y = ((virtual_screen.cursor_y + virtual_screen.total_scroll)
676
 
       * virtual_screen.normal_char_height
677
 
       + grub_font_get_ascent (virtual_screen.font));
678
 
  height = 2;
679
 
  
680
 
  /* Render cursor to text layer.  */
681
 
  grub_video_set_active_render_target (text_layer);
682
 
  grub_video_fill_rect (color, x, y, width, height);
683
 
  grub_video_set_active_render_target (render_target);
684
 
  
685
 
  /* Mark cursor to be redrawn.  */
686
 
  dirty_region_add (virtual_screen.offset_x + x,
687
 
                    virtual_screen.offset_y + y,
688
 
                    width, height);
689
 
}
690
 
 
691
 
static void
692
 
real_scroll (void)
693
 
{
694
 
  unsigned int i, j, was_scroll;
695
 
  grub_video_color_t color;
696
 
 
697
 
  if (!virtual_screen.total_scroll)
698
 
    return;
699
 
 
700
 
  /* If we have bitmap, re-draw screen, otherwise scroll physical screen too.  */
701
 
  if (bitmap)
702
 
    {
703
 
      /* Scroll physical screen.  */
704
 
      grub_video_set_active_render_target (text_layer);
705
 
      color = virtual_screen.bg_color;
706
 
      grub_video_scroll (color, 0, -virtual_screen.normal_char_height
707
 
                         * virtual_screen.total_scroll);
708
 
 
709
 
      /* Mark virtual screen to be redrawn.  */
710
 
      dirty_region_add_virtualscreen ();
711
 
    }
712
 
  else
713
 
    {
714
 
      grub_video_rect_t saved_view;
715
 
 
716
 
      /* Remove cursor.  */
717
 
      draw_cursor (0);
718
 
 
719
 
      grub_video_set_active_render_target (render_target);
720
 
 
721
 
      i = window.double_repaint ? 2 : 1;
722
 
 
723
 
      color = virtual_screen.bg_color;
724
 
 
725
 
      while (i--)
726
 
        {
727
 
          /* Save viewport and set it to our window.  */
728
 
          grub_video_get_viewport ((unsigned *) &saved_view.x, 
729
 
                                   (unsigned *) &saved_view.y, 
730
 
                                   (unsigned *) &saved_view.width, 
731
 
                                   (unsigned *) &saved_view.height);
732
 
 
733
 
          grub_video_set_viewport (window.x, window.y, window.width,
734
 
                                   window.height);
735
 
 
736
 
          /* Clear new border area.  */
737
 
          grub_video_fill_rect (color,
738
 
                                virtual_screen.offset_x,
739
 
                                virtual_screen.offset_y,
740
 
                                virtual_screen.width,
741
 
                                virtual_screen.normal_char_height
742
 
                                * virtual_screen.total_scroll);
743
 
 
744
 
          grub_video_set_active_render_target (render_target);
745
 
          dirty_region_redraw ();
746
 
 
747
 
          /* Scroll physical screen.  */
748
 
          grub_video_scroll (color, 0, -virtual_screen.normal_char_height
749
 
                             * virtual_screen.total_scroll);
750
 
 
751
 
          /* Restore saved viewport.  */
752
 
          grub_video_set_viewport (saved_view.x, saved_view.y,
753
 
                                   saved_view.width, saved_view.height);
754
 
 
755
 
          if (i)
756
 
            grub_video_swap_buffers ();
757
 
        }
758
 
      dirty_region_reset ();
759
 
 
760
 
      /* Scroll physical screen.  */
761
 
      grub_video_set_active_render_target (text_layer);
762
 
      color = virtual_screen.bg_color;
763
 
      grub_video_scroll (color, 0, -virtual_screen.normal_char_height
764
 
                         * virtual_screen.total_scroll);
765
 
 
766
 
      grub_video_set_active_render_target (render_target);
767
 
 
768
 
    }
769
 
 
770
 
  was_scroll = virtual_screen.total_scroll;
771
 
  virtual_screen.total_scroll = 0;
772
 
 
773
 
  if (was_scroll > virtual_screen.rows)
774
 
    was_scroll = virtual_screen.rows;
775
 
 
776
 
  /* Draw shadow part.  */
777
 
  for (i = virtual_screen.rows - was_scroll;
778
 
       i < virtual_screen.rows; i++)
779
 
    for (j = 0; j < virtual_screen.columns; j++)
780
 
      paint_char (j, i);
781
 
 
782
 
  /* Draw cursor if visible.  */
783
 
  if (virtual_screen.cursor_state)
784
 
    draw_cursor (1);
785
 
 
786
 
  if (repaint_callback)
787
 
    repaint_callback (window.x, window.y, window.width, window.height);
788
 
}
789
 
 
790
 
static void
791
 
scroll_up (void)
792
 
{
793
 
  unsigned int i;
794
 
 
795
 
  /* Clear first line in text buffer.  */
796
 
  for (i = 0;
797
 
       i < virtual_screen.columns;
798
 
       i++)
799
 
    {
800
 
      virtual_screen.text_buffer[i].code = 0;
801
 
      clear_char (&(virtual_screen.text_buffer[i]));
802
 
    }
803
 
 
804
 
  /* Scroll text buffer with one line to up.  */
805
 
  grub_memmove (virtual_screen.text_buffer,
806
 
                virtual_screen.text_buffer + virtual_screen.columns,
807
 
                sizeof (*virtual_screen.text_buffer)
808
 
                * virtual_screen.columns
809
 
                * (virtual_screen.rows - 1));
810
 
 
811
 
  /* Clear last line in text buffer.  */
812
 
  for (i = virtual_screen.columns * (virtual_screen.rows - 1);
813
 
       i < virtual_screen.columns * virtual_screen.rows;
814
 
       i++)
815
 
    {
816
 
      virtual_screen.text_buffer[i].code = 0;
817
 
      clear_char (&(virtual_screen.text_buffer[i]));
818
 
    }
819
 
 
820
 
  virtual_screen.total_scroll++;
821
 
}
822
 
 
823
 
static void
824
 
grub_gfxterm_putchar (struct grub_term_output *term,
825
 
                      const struct grub_unicode_glyph *c)
826
 
{
827
 
  if (c->base == '\a')
828
 
    /* FIXME */
829
 
    return;
830
 
 
831
 
  /* Erase current cursor, if any.  */
832
 
  if (virtual_screen.cursor_state)
833
 
    draw_cursor (0);
834
 
 
835
 
  if (c->base == '\b' || c->base == '\n' || c->base == '\r')
836
 
    {
837
 
      switch (c->base)
838
 
        {
839
 
        case '\b':
840
 
          if (virtual_screen.cursor_x > 0)
841
 
            virtual_screen.cursor_x--;
842
 
          break;
843
 
 
844
 
        case '\n':
845
 
          if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
846
 
            scroll_up ();
847
 
          else
848
 
            virtual_screen.cursor_y++;
849
 
          break;
850
 
 
851
 
        case '\r':
852
 
          virtual_screen.cursor_x = 0;
853
 
          break;
854
 
        }
855
 
    }
856
 
  else
857
 
    {
858
 
      struct grub_colored_char *p;
859
 
      unsigned char char_width;
860
 
 
861
 
      /* Calculate actual character width for glyph. This is number of
862
 
         times of normal_font_width.  */
863
 
      char_width = grub_gfxterm_getcharwidth (term, c);
864
 
 
865
 
      /* If we are about to exceed line length, wrap to next line.  */
866
 
      if (virtual_screen.cursor_x + char_width > virtual_screen.columns)
867
 
        {
868
 
          if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
869
 
            scroll_up ();
870
 
          else
871
 
            virtual_screen.cursor_y++;
872
 
        }
873
 
 
874
 
      /* Find position on virtual screen, and fill information.  */
875
 
      p = (virtual_screen.text_buffer +
876
 
           virtual_screen.cursor_x +
877
 
           virtual_screen.cursor_y * virtual_screen.columns);
878
 
      grub_free (p->code);
879
 
      p->code = grub_unicode_glyph_dup (c);
880
 
      if (!p->code)
881
 
        grub_errno = GRUB_ERR_NONE;
882
 
      p->fg_color = virtual_screen.fg_color;
883
 
      p->bg_color = virtual_screen.bg_color;
884
 
      p->width = char_width - 1;
885
 
      p->index = 0;
886
 
 
887
 
      /* If we have large glyph, add fixup info.  */
888
 
      if (char_width > 1)
889
 
        {
890
 
          unsigned i;
891
 
 
892
 
          for (i = 1; i < char_width; i++)
893
 
            {
894
 
              grub_free (p[i].code);
895
 
              p[i].code = grub_unicode_glyph_from_code (' ');
896
 
              if (!p[i].code)
897
 
                grub_errno = GRUB_ERR_NONE;
898
 
              p[i].width = char_width - 1;
899
 
              p[i].index = i;
900
 
            }
901
 
        }
902
 
 
903
 
      /* Draw glyph.  */
904
 
      write_char ();
905
 
 
906
 
      /* Make sure we scroll screen when needed and wrap line correctly.  */
907
 
      virtual_screen.cursor_x += char_width;
908
 
      if (virtual_screen.cursor_x >= virtual_screen.columns)
909
 
        {
910
 
          virtual_screen.cursor_x = 0;
911
 
 
912
 
          if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
913
 
            scroll_up ();
914
 
          else
915
 
            virtual_screen.cursor_y++;
916
 
        }
917
 
    }
918
 
 
919
 
  /* Redraw cursor if it should be visible.  */
920
 
  /* Note: This will redraw the character as well, which means that the
921
 
     above call to write_char is redundant when the cursor is showing.  */
922
 
  if (virtual_screen.cursor_state)
923
 
    draw_cursor (1);
924
 
}
925
 
 
926
 
/* Use ASCII characters to determine normal character width.  */
927
 
static unsigned int
928
 
calculate_normal_character_width (grub_font_t font)
929
 
{
930
 
  struct grub_font_glyph *glyph;
931
 
  unsigned int width = 0;
932
 
  unsigned int i;
933
 
 
934
 
  /* Get properties of every printable ASCII character.  */
935
 
  for (i = 32; i < 127; i++)
936
 
    {
937
 
      glyph = grub_font_get_glyph (font, i);
938
 
 
939
 
      /* Skip unknown characters.  Should never happen on normal conditions.  */
940
 
      if (! glyph)
941
 
        continue;
942
 
 
943
 
      if (glyph->device_width > width)
944
 
        width = glyph->device_width;
945
 
    }
946
 
 
947
 
  return width;
948
 
}
949
 
 
950
 
static unsigned char
951
 
calculate_character_width (struct grub_font_glyph *glyph)
952
 
{
953
 
  if (! glyph || glyph->device_width == 0)
954
 
    return 1;
955
 
 
956
 
  return (glyph->device_width
957
 
          + (virtual_screen.normal_char_width - 1))
958
 
         / virtual_screen.normal_char_width;
959
 
}
960
 
 
961
 
static grub_ssize_t
962
 
grub_gfxterm_getcharwidth (struct grub_term_output *term __attribute__ ((unused)),
963
 
                           const struct grub_unicode_glyph *c)
964
 
{
965
 
  int dev_width;
966
 
  dev_width = grub_font_get_constructed_device_width (virtual_screen.font, c);
967
 
 
968
 
  if (dev_width == 0)
969
 
    return 1;
970
 
 
971
 
  return (dev_width + (virtual_screen.normal_char_width - 1))
972
 
    / virtual_screen.normal_char_width;
973
 
}
974
 
 
975
 
static grub_uint16_t
976
 
grub_virtual_screen_getwh (struct grub_term_output *term __attribute__ ((unused)))
977
 
{
978
 
  return (virtual_screen.columns << 8) | virtual_screen.rows;
979
 
}
980
 
 
981
 
static grub_uint16_t
982
 
grub_virtual_screen_getxy (struct grub_term_output *term __attribute__ ((unused)))
983
 
{
984
 
  return ((virtual_screen.cursor_x << 8) | virtual_screen.cursor_y);
985
 
}
986
 
 
987
 
static void
988
 
grub_gfxterm_gotoxy (struct grub_term_output *term __attribute__ ((unused)),
989
 
                     grub_uint8_t x, grub_uint8_t y)
990
 
{
991
 
  if (x >= virtual_screen.columns)
992
 
    x = virtual_screen.columns - 1;
993
 
 
994
 
  if (y >= virtual_screen.rows)
995
 
    y = virtual_screen.rows - 1;
996
 
 
997
 
  /* Erase current cursor, if any.  */
998
 
  if (virtual_screen.cursor_state)
999
 
    draw_cursor (0);
1000
 
 
1001
 
  virtual_screen.cursor_x = x;
1002
 
  virtual_screen.cursor_y = y;
1003
 
 
1004
 
  /* Draw cursor if visible.  */
1005
 
  if (virtual_screen.cursor_state)
1006
 
    draw_cursor (1);
1007
 
}
1008
 
 
1009
 
static void
1010
 
grub_virtual_screen_cls (struct grub_term_output *term __attribute__ ((unused)))
1011
 
{
1012
 
  grub_uint32_t i;
1013
 
 
1014
 
  for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
1015
 
    clear_char (&(virtual_screen.text_buffer[i]));
1016
 
 
1017
 
  virtual_screen.cursor_x = virtual_screen.cursor_y = 0;
1018
 
}
1019
 
 
1020
 
static void
1021
 
grub_gfxterm_cls (struct grub_term_output *term)
1022
 
{
1023
 
  grub_video_color_t color;
1024
 
 
1025
 
  /* Clear virtual screen.  */
1026
 
  grub_virtual_screen_cls (term);
1027
 
 
1028
 
  /* Clear text layer.  */
1029
 
  grub_video_set_active_render_target (text_layer);
1030
 
  color = virtual_screen.bg_color;
1031
 
  grub_video_fill_rect (color, 0, 0,
1032
 
                        virtual_screen.width, virtual_screen.height);
1033
 
  grub_video_set_active_render_target (render_target);
1034
 
 
1035
 
  /* Mark virtual screen to be redrawn.  */
1036
 
  dirty_region_add_virtualscreen ();
1037
 
 
1038
 
  grub_gfxterm_refresh (term);
1039
 
}
1040
 
 
1041
 
static void
1042
 
grub_virtual_screen_setcolorstate (struct grub_term_output *term,
1043
 
                                   grub_term_color_state state)
1044
 
{
1045
 
  switch (state)
1046
 
    {
1047
 
    case GRUB_TERM_COLOR_STANDARD:
1048
 
      virtual_screen.term_color = virtual_screen.standard_color_setting;
1049
 
      break;
1050
 
 
1051
 
    case GRUB_TERM_COLOR_NORMAL:
1052
 
      virtual_screen.term_color = term->normal_color;
1053
 
      break;
1054
 
 
1055
 
    case GRUB_TERM_COLOR_HIGHLIGHT:
1056
 
      virtual_screen.term_color = term->highlight_color;
1057
 
      break;
1058
 
 
1059
 
    default:
1060
 
      break;
1061
 
    }
1062
 
 
1063
 
  /* Change color to virtual terminal.  */
1064
 
  set_term_color (virtual_screen.term_color);
1065
 
}
1066
 
 
1067
 
static void
1068
 
grub_gfxterm_setcursor (struct grub_term_output *term __attribute__ ((unused)),
1069
 
                        int on)
1070
 
{
1071
 
  if (virtual_screen.cursor_state != on)
1072
 
    {
1073
 
      if (virtual_screen.cursor_state)
1074
 
        draw_cursor (0);
1075
 
      else
1076
 
        draw_cursor (1);
1077
 
 
1078
 
      virtual_screen.cursor_state = on;
1079
 
    }
1080
 
}
1081
 
 
1082
 
static void
1083
 
grub_gfxterm_refresh (struct grub_term_output *term __attribute__ ((unused)))
1084
 
{
1085
 
  real_scroll ();
1086
 
 
1087
 
  /* Redraw only changed regions.  */
1088
 
  dirty_region_redraw ();
1089
 
 
1090
 
  grub_video_swap_buffers ();
1091
 
 
1092
 
  if (window.double_repaint)
1093
 
    dirty_region_redraw ();
1094
 
  dirty_region_reset ();
1095
 
}
1096
 
 
1097
 
void 
1098
 
grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func)
1099
 
{
1100
 
  repaint_callback = func;
1101
 
}
1102
 
 
1103
 
/* Option array indices.  */
1104
 
#define BACKGROUND_CMD_ARGINDEX_MODE 0
1105
 
 
1106
 
static const struct grub_arg_option background_image_cmd_options[] =
1107
 
  {
1108
 
    {"mode", 'm', 0, "Background image mode.", "stretch|normal",
1109
 
     ARG_TYPE_STRING},
1110
 
    {0, 0, 0, 0, 0, 0}
1111
 
  };
1112
 
 
1113
 
static grub_err_t
1114
 
grub_gfxterm_background_image_cmd (grub_extcmd_t cmd __attribute__ ((unused)),
1115
 
                                   int argc,
1116
 
                                   char **args)
1117
 
{
1118
 
  struct grub_arg_list *state = cmd->state;
1119
 
 
1120
 
  /* Check that we have video adapter active.  */
1121
 
  if (grub_video_get_info(NULL) != GRUB_ERR_NONE)
1122
 
    return grub_errno;
1123
 
 
1124
 
  /* Destroy existing background bitmap if loaded.  */
1125
 
  if (bitmap)
1126
 
    {
1127
 
      grub_video_bitmap_destroy (bitmap);
1128
 
      bitmap = 0;
1129
 
 
1130
 
      /* Mark whole screen as dirty.  */
1131
 
      dirty_region_add (0, 0, window.width, window.height);
1132
 
    }
1133
 
 
1134
 
  /* If filename was provided, try to load that.  */
1135
 
  if (argc >= 1)
1136
 
    {
1137
 
      /* Try to load new one.  */
1138
 
      grub_video_bitmap_load (&bitmap, args[0]);
1139
 
      if (grub_errno != GRUB_ERR_NONE)
1140
 
        return grub_errno;
1141
 
 
1142
 
      /* Determine if the bitmap should be scaled to fit the screen.  */
1143
 
      if (!state[BACKGROUND_CMD_ARGINDEX_MODE].set
1144
 
          || grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_MODE].arg,
1145
 
                          "stretch") == 0)
1146
 
          {
1147
 
            if (window.width != grub_video_bitmap_get_width (bitmap)
1148
 
                || window.height != grub_video_bitmap_get_height (bitmap))
1149
 
              {
1150
 
                struct grub_video_bitmap *scaled_bitmap;
1151
 
                grub_video_bitmap_create_scaled (&scaled_bitmap,
1152
 
                                                 window.width, 
1153
 
                                                 window.height,
1154
 
                                                 bitmap,
1155
 
                                                 GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
1156
 
                if (grub_errno == GRUB_ERR_NONE)
1157
 
                  {
1158
 
                    /* Replace the original bitmap with the scaled one.  */
1159
 
                    grub_video_bitmap_destroy (bitmap);
1160
 
                    bitmap = scaled_bitmap;
1161
 
                  }
1162
 
              }
1163
 
          }
1164
 
 
1165
 
      /* If bitmap was loaded correctly, display it.  */
1166
 
      if (bitmap)
1167
 
        {
1168
 
          /* Determine bitmap dimensions.  */
1169
 
          bitmap_width = grub_video_bitmap_get_width (bitmap);
1170
 
          bitmap_height = grub_video_bitmap_get_height (bitmap);
1171
 
 
1172
 
          /* Mark whole screen as dirty.  */
1173
 
          dirty_region_add (0, 0, window.width, window.height);
1174
 
        }
1175
 
    }
1176
 
 
1177
 
  /* All was ok.  */
1178
 
  grub_errno = GRUB_ERR_NONE;
1179
 
  return grub_errno;
1180
 
}
1181
 
 
1182
 
static struct grub_term_output grub_video_term =
1183
 
  {
1184
 
    .name = "gfxterm",
1185
 
    .init = grub_gfxterm_term_init,
1186
 
    .fini = grub_gfxterm_term_fini,
1187
 
    .putchar = grub_gfxterm_putchar,
1188
 
    .getcharwidth = grub_gfxterm_getcharwidth,
1189
 
    .getwh = grub_virtual_screen_getwh,
1190
 
    .getxy = grub_virtual_screen_getxy,
1191
 
    .gotoxy = grub_gfxterm_gotoxy,
1192
 
    .cls = grub_gfxterm_cls,
1193
 
    .setcolorstate = grub_virtual_screen_setcolorstate,
1194
 
    .setcursor = grub_gfxterm_setcursor,
1195
 
    .refresh = grub_gfxterm_refresh,
1196
 
    .flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS,
1197
 
    .normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR,
1198
 
    .highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR,
1199
 
    .next = 0
1200
 
  };
1201
 
 
1202
 
static grub_extcmd_t background_image_cmd_handle;
1203
 
 
1204
 
GRUB_MOD_INIT(gfxterm)
1205
 
{
1206
 
  grub_term_register_output ("gfxterm", &grub_video_term);
1207
 
  background_image_cmd_handle =
1208
 
    grub_register_extcmd ("background_image",
1209
 
                          grub_gfxterm_background_image_cmd,
1210
 
                          GRUB_COMMAND_FLAG_BOTH,
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
 
}