2009-11-21 Samuel Thibault <samuel.thibault@ens-lyon.org>
[grub2.git] / term / gfxterm.c
blobf161499e6f9137d9ac42919113427383cb0f6759
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
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.
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.
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/>.
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/bitmap.h>
28 #include <grub/command.h>
30 #define DEFAULT_VIDEO_MODE "1024x768,800x600,640x480"
31 #define DEFAULT_BORDER_WIDTH 10
33 #define DEFAULT_STANDARD_COLOR 0x07
34 #define DEFAULT_NORMAL_COLOR 0x07
35 #define DEFAULT_HIGHLIGHT_COLOR 0x70
37 struct grub_dirty_region
39 int top_left_x;
40 int top_left_y;
41 int bottom_right_x;
42 int bottom_right_y;
45 struct grub_colored_char
47 /* An Unicode codepoint. */
48 grub_uint32_t code;
50 /* Color values. */
51 grub_video_color_t fg_color;
52 grub_video_color_t bg_color;
54 /* The width of this character minus one. */
55 unsigned char width;
57 /* The column index of this character. */
58 unsigned char index;
61 struct grub_virtual_screen
63 /* Dimensions of the virtual screen in pixels. */
64 unsigned int width;
65 unsigned int height;
67 /* Offset in the display in pixels. */
68 unsigned int offset_x;
69 unsigned int offset_y;
71 /* TTY Character sizes in pixes. */
72 unsigned int normal_char_width;
73 unsigned int normal_char_height;
75 /* Virtual screen TTY size in characters. */
76 unsigned int columns;
77 unsigned int rows;
79 /* Current cursor location in characters. */
80 unsigned int cursor_x;
81 unsigned int cursor_y;
83 /* Current cursor state. */
84 int cursor_state;
86 /* Font settings. */
87 grub_font_t font;
89 /* Terminal color settings. */
90 grub_uint8_t standard_color_setting;
91 grub_uint8_t normal_color_setting;
92 grub_uint8_t highlight_color_setting;
93 grub_uint8_t term_color;
95 /* Color settings. */
96 grub_video_color_t fg_color;
97 grub_video_color_t bg_color;
99 /* Text buffer for virtual screen. Contains (columns * rows) number
100 of entries. */
101 struct grub_colored_char *text_buffer;
104 static struct grub_virtual_screen virtual_screen;
106 static struct grub_video_mode_info mode_info;
108 static struct grub_video_render_target *text_layer;
110 static unsigned int bitmap_width;
111 static unsigned int bitmap_height;
112 static struct grub_video_bitmap *bitmap;
114 static struct grub_dirty_region dirty_region;
116 static void dirty_region_reset (void);
118 static int dirty_region_is_empty (void);
120 static void dirty_region_add (int x, int y,
121 unsigned int width, unsigned int height);
123 static unsigned int calculate_normal_character_width (grub_font_t font);
125 static unsigned char calculate_character_width (struct grub_font_glyph *glyph);
127 static void
128 set_term_color (grub_uint8_t term_color)
130 struct grub_video_render_target *old_target;
132 /* Save previous target and switch to text layer. */
133 grub_video_get_active_render_target (&old_target);
134 grub_video_set_active_render_target (text_layer);
136 /* Map terminal color to text layer compatible video colors. */
137 virtual_screen.fg_color = grub_video_map_color(term_color & 0x0f);
139 /* Special case: use black as transparent color. */
140 if (((term_color >> 4) & 0x0f) == 0)
142 virtual_screen.bg_color = grub_video_map_rgba(0, 0, 0, 0);
144 else
146 virtual_screen.bg_color = grub_video_map_color((term_color >> 4) & 0x0f);
149 /* Restore previous target. */
150 grub_video_set_active_render_target (old_target);
153 static void
154 clear_char (struct grub_colored_char *c)
156 c->code = ' ';
157 c->fg_color = virtual_screen.fg_color;
158 c->bg_color = virtual_screen.bg_color;
159 c->width = 0;
160 c->index = 0;
163 static void
164 grub_virtual_screen_free (void)
166 /* If virtual screen has been allocated, free it. */
167 if (virtual_screen.text_buffer != 0)
168 grub_free (virtual_screen.text_buffer);
170 /* Reset virtual screen data. */
171 grub_memset (&virtual_screen, 0, sizeof (virtual_screen));
173 /* Free render targets. */
174 grub_video_delete_render_target (text_layer);
175 text_layer = 0;
178 static grub_err_t
179 grub_virtual_screen_setup (unsigned int x, unsigned int y,
180 unsigned int width, unsigned int height,
181 const char *font_name)
183 unsigned int i;
185 /* Free old virtual screen. */
186 grub_virtual_screen_free ();
188 /* Initialize with default data. */
189 virtual_screen.font = grub_font_get (font_name);
190 if (!virtual_screen.font)
191 return grub_error (GRUB_ERR_BAD_FONT,
192 "No font loaded.");
193 virtual_screen.width = width;
194 virtual_screen.height = height;
195 virtual_screen.offset_x = x;
196 virtual_screen.offset_y = y;
197 virtual_screen.normal_char_width =
198 calculate_normal_character_width (virtual_screen.font);
199 virtual_screen.normal_char_height =
200 grub_font_get_max_char_height (virtual_screen.font);
201 virtual_screen.cursor_x = 0;
202 virtual_screen.cursor_y = 0;
203 virtual_screen.cursor_state = 1;
205 /* Calculate size of text buffer. */
206 virtual_screen.columns = virtual_screen.width / virtual_screen.normal_char_width;
207 virtual_screen.rows = virtual_screen.height / virtual_screen.normal_char_height;
209 /* Allocate memory for text buffer. */
210 virtual_screen.text_buffer =
211 (struct grub_colored_char *) grub_malloc (virtual_screen.columns
212 * virtual_screen.rows
213 * sizeof (*virtual_screen.text_buffer));
214 if (grub_errno != GRUB_ERR_NONE)
215 return grub_errno;
217 /* Create new render target for text layer. */
218 grub_video_create_render_target (&text_layer,
219 virtual_screen.width,
220 virtual_screen.height,
221 GRUB_VIDEO_MODE_TYPE_RGB
222 | GRUB_VIDEO_MODE_TYPE_ALPHA);
223 if (grub_errno != GRUB_ERR_NONE)
224 return grub_errno;
226 /* As we want to have colors compatible with rendering target,
227 we can only have those after mode is initialized. */
228 grub_video_set_active_render_target (text_layer);
230 virtual_screen.standard_color_setting = DEFAULT_STANDARD_COLOR;
231 virtual_screen.normal_color_setting = DEFAULT_NORMAL_COLOR;
232 virtual_screen.highlight_color_setting = DEFAULT_HIGHLIGHT_COLOR;
234 virtual_screen.term_color = virtual_screen.normal_color_setting;
236 set_term_color (virtual_screen.term_color);
238 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
240 /* Clear out text buffer. */
241 for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
242 clear_char (&(virtual_screen.text_buffer[i]));
244 return grub_errno;
247 static int NESTED_FUNC_ATTR video_hook (grub_video_adapter_t p __attribute__ ((unused)),
248 struct grub_video_mode_info *info)
250 return ! (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT);
253 static grub_err_t
254 grub_gfxterm_init (void)
256 char *font_name;
257 char *modevar;
258 char *tmp;
259 grub_video_color_t color;
260 int width;
261 int height;
262 grub_err_t err;
264 /* Select the font to use. */
265 font_name = grub_env_get ("gfxterm_font");
266 if (! font_name)
267 font_name = ""; /* Allow fallback to any font. */
269 /* Parse gfxmode environment variable if set. */
270 modevar = grub_env_get ("gfxmode");
271 if (! modevar || *modevar == 0)
272 err = grub_video_set_mode (DEFAULT_VIDEO_MODE, video_hook);
273 else
275 tmp = grub_malloc (grub_strlen (modevar)
276 + sizeof (DEFAULT_VIDEO_MODE) + 1);
277 grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
278 err = grub_video_set_mode (tmp, video_hook);
279 grub_free (tmp);
282 if (err)
283 return err;
285 err = grub_video_get_info (&mode_info);
286 /* Figure out what mode we ended up. */
287 if (err)
288 return err;
290 /* Make sure screen is black. */
291 color = grub_video_map_rgb (0, 0, 0);
292 grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
293 bitmap = 0;
295 /* Leave borders for virtual screen. */
296 width = mode_info.width - (2 * DEFAULT_BORDER_WIDTH);
297 height = mode_info.height - (2 * DEFAULT_BORDER_WIDTH);
299 /* Create virtual screen. */
300 if (grub_virtual_screen_setup (DEFAULT_BORDER_WIDTH, DEFAULT_BORDER_WIDTH,
301 width, height, font_name) != GRUB_ERR_NONE)
303 grub_video_restore ();
304 return grub_errno;
307 /* Mark whole screen as dirty. */
308 dirty_region_reset ();
309 dirty_region_add (0, 0, mode_info.width, mode_info.height);
311 return (grub_errno = GRUB_ERR_NONE);
314 static grub_err_t
315 grub_gfxterm_fini (void)
317 if (bitmap)
319 grub_video_bitmap_destroy (bitmap);
320 bitmap = 0;
323 grub_virtual_screen_free ();
325 grub_video_restore ();
327 return GRUB_ERR_NONE;
330 static void
331 redraw_screen_rect (unsigned int x, unsigned int y,
332 unsigned int width, unsigned int height)
334 grub_video_color_t color;
336 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
339 if (bitmap)
341 /* Render bitmap as background. */
342 grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_REPLACE, x, y,
343 x, y,
344 width, height);
346 /* If bitmap is smaller than requested blit area, use background
347 color. */
348 color = virtual_screen.bg_color;
350 /* Fill right side of the bitmap if needed. */
351 if ((x + width >= bitmap_width) && (y < bitmap_height))
353 int w = (x + width) - bitmap_width;
354 int h = height;
355 unsigned int tx = x;
357 if (y + height >= bitmap_height)
359 h = bitmap_height - y;
362 if (bitmap_width > tx)
364 tx = bitmap_width;
367 /* Render background layer. */
368 grub_video_fill_rect (color, tx, y, w, h);
371 /* Fill bottom side of the bitmap if needed. */
372 if (y + height >= bitmap_height)
374 int h = (y + height) - bitmap_height;
375 unsigned int ty = y;
377 if (bitmap_height > ty)
379 ty = bitmap_height;
382 /* Render background layer. */
383 grub_video_fill_rect (color, x, ty, width, h);
386 /* Render text layer as blended. */
387 grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, x, y,
388 x - virtual_screen.offset_x,
389 y - virtual_screen.offset_y,
390 width, height);
392 else
394 /* Render background layer. */
395 color = virtual_screen.bg_color;
396 grub_video_fill_rect (color, x, y, width, height);
398 /* Render text layer as replaced (to get texts background color). */
399 grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_REPLACE, x, y,
400 x - virtual_screen.offset_x,
401 y - virtual_screen.offset_y,
402 width, height);
406 static void
407 dirty_region_reset (void)
409 dirty_region.top_left_x = -1;
410 dirty_region.top_left_y = -1;
411 dirty_region.bottom_right_x = -1;
412 dirty_region.bottom_right_y = -1;
415 static int
416 dirty_region_is_empty (void)
418 if ((dirty_region.top_left_x == -1)
419 || (dirty_region.top_left_y == -1)
420 || (dirty_region.bottom_right_x == -1)
421 || (dirty_region.bottom_right_y == -1))
422 return 1;
423 return 0;
426 static void
427 dirty_region_add (int x, int y, unsigned int width, unsigned int height)
429 if ((width == 0) || (height == 0))
430 return;
432 if (dirty_region_is_empty ())
434 dirty_region.top_left_x = x;
435 dirty_region.top_left_y = y;
436 dirty_region.bottom_right_x = x + width - 1;
437 dirty_region.bottom_right_y = y + height - 1;
439 else
441 if (x < dirty_region.top_left_x)
442 dirty_region.top_left_x = x;
443 if (y < dirty_region.top_left_y)
444 dirty_region.top_left_y = y;
445 if ((x + (int)width - 1) > dirty_region.bottom_right_x)
446 dirty_region.bottom_right_x = x + width - 1;
447 if ((y + (int)height - 1) > dirty_region.bottom_right_y)
448 dirty_region.bottom_right_y = y + height - 1;
452 static void
453 dirty_region_add_virtualscreen (void)
455 /* Mark virtual screen as dirty. */
456 dirty_region_add (virtual_screen.offset_x, virtual_screen.offset_y,
457 virtual_screen.width, virtual_screen.height);
461 static void
462 dirty_region_redraw (void)
464 int x;
465 int y;
466 int width;
467 int height;
469 if (dirty_region_is_empty ())
470 return;
472 x = dirty_region.top_left_x;
473 y = dirty_region.top_left_y;
475 width = dirty_region.bottom_right_x - x + 1;
476 height = dirty_region.bottom_right_y - y + 1;
478 redraw_screen_rect (x, y, width, height);
480 dirty_region_reset ();
483 static void
484 write_char (void)
486 struct grub_colored_char *p;
487 struct grub_font_glyph *glyph;
488 grub_video_color_t color;
489 grub_video_color_t bgcolor;
490 unsigned int x;
491 unsigned int y;
492 int ascent;
493 unsigned int height;
494 unsigned int width;
496 /* Find out active character. */
497 p = (virtual_screen.text_buffer
498 + virtual_screen.cursor_x
499 + (virtual_screen.cursor_y * virtual_screen.columns));
501 p -= p->index;
503 /* Get glyph for character. */
504 glyph = grub_font_get_glyph (virtual_screen.font, p->code);
505 ascent = grub_font_get_ascent (virtual_screen.font);
507 width = virtual_screen.normal_char_width * calculate_character_width(glyph);
508 height = virtual_screen.normal_char_height;
510 color = p->fg_color;
511 bgcolor = p->bg_color;
513 x = virtual_screen.cursor_x * virtual_screen.normal_char_width;
514 y = virtual_screen.cursor_y * virtual_screen.normal_char_height;
516 /* Render glyph to text layer. */
517 grub_video_set_active_render_target (text_layer);
518 grub_video_fill_rect (bgcolor, x, y, width, height);
519 grub_font_draw_glyph (glyph, color, x, y + ascent);
520 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
522 /* Mark character to be drawn. */
523 dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
524 width, height);
527 static void
528 draw_cursor (int show)
530 write_char ();
532 if (show)
534 unsigned int x;
535 unsigned int y;
536 unsigned int width;
537 unsigned int height;
538 grub_video_color_t color;
540 /* Determine cursor properties and position on text layer. */
541 x = virtual_screen.cursor_x * virtual_screen.normal_char_width;
542 width = virtual_screen.normal_char_width;
543 color = virtual_screen.fg_color;
544 y = (virtual_screen.cursor_y * virtual_screen.normal_char_height
545 + grub_font_get_ascent (virtual_screen.font));
546 height = 2;
548 /* Render cursor to text layer. */
549 grub_video_set_active_render_target (text_layer);
550 grub_video_fill_rect (color, x, y, width, height);
551 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
553 /* Mark cursor to be redrawn. */
554 dirty_region_add (virtual_screen.offset_x + x,
555 virtual_screen.offset_y + y,
556 width, height);
560 static void
561 scroll_up (void)
563 unsigned int i;
564 grub_video_color_t color;
566 /* If we don't have background bitmap, remove cursor. */
567 if (!bitmap)
569 /* Remove cursor. */
570 draw_cursor (0);
572 /* Redraw only changed regions. */
573 dirty_region_redraw ();
576 /* Scroll text buffer with one line to up. */
577 grub_memmove (virtual_screen.text_buffer,
578 virtual_screen.text_buffer + virtual_screen.columns,
579 sizeof (*virtual_screen.text_buffer)
580 * virtual_screen.columns
581 * (virtual_screen.rows - 1));
583 /* Clear last line in text buffer. */
584 for (i = virtual_screen.columns * (virtual_screen.rows - 1);
585 i < virtual_screen.columns * virtual_screen.rows;
586 i++)
587 clear_char (&(virtual_screen.text_buffer[i]));
589 /* Scroll physical screen. */
590 grub_video_set_active_render_target (text_layer);
591 color = virtual_screen.bg_color;
592 grub_video_scroll (color, 0, -virtual_screen.normal_char_height);
593 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
595 /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */
596 if (bitmap)
598 /* Mark virtual screen to be redrawn. */
599 dirty_region_add_virtualscreen ();
601 else
603 /* Clear new border area. */
604 grub_video_fill_rect (color,
605 virtual_screen.offset_x, virtual_screen.offset_y,
606 virtual_screen.width, virtual_screen.normal_char_height);
608 /* Scroll physical screen. */
609 grub_video_scroll (color, 0, -virtual_screen.normal_char_height);
611 /* Draw cursor if visible. */
612 if (virtual_screen.cursor_state)
613 draw_cursor (1);
617 static void
618 grub_gfxterm_putchar (grub_uint32_t c)
620 if (c == '\a')
621 /* FIXME */
622 return;
624 /* Erase current cursor, if any. */
625 if (virtual_screen.cursor_state)
626 draw_cursor (0);
628 if (c == '\b' || c == '\n' || c == '\r')
630 switch (c)
632 case '\b':
633 if (virtual_screen.cursor_x > 0)
634 virtual_screen.cursor_x--;
635 break;
637 case '\n':
638 if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
639 scroll_up ();
640 else
641 virtual_screen.cursor_y++;
642 break;
644 case '\r':
645 virtual_screen.cursor_x = 0;
646 break;
649 else
651 struct grub_font_glyph *glyph;
652 struct grub_colored_char *p;
653 unsigned char char_width;
655 /* Get properties of the character. */
656 glyph = grub_font_get_glyph (virtual_screen.font, c);
658 /* Calculate actual character width for glyph. This is number of
659 times of normal_font_width. */
660 char_width = calculate_character_width(glyph);
662 /* If we are about to exceed line length, wrap to next line. */
663 if (virtual_screen.cursor_x + char_width > virtual_screen.columns)
664 grub_putchar ('\n');
666 /* Find position on virtual screen, and fill information. */
667 p = (virtual_screen.text_buffer +
668 virtual_screen.cursor_x +
669 virtual_screen.cursor_y * virtual_screen.columns);
670 p->code = c;
671 p->fg_color = virtual_screen.fg_color;
672 p->bg_color = virtual_screen.bg_color;
673 p->width = char_width - 1;
674 p->index = 0;
676 /* If we have large glyph, add fixup info. */
677 if (char_width > 1)
679 unsigned i;
681 for (i = 1; i < char_width; i++)
683 p[i].code = ' ';
684 p[i].width = char_width - 1;
685 p[i].index = i;
689 /* Draw glyph. */
690 write_char ();
692 /* Make sure we scroll screen when needed and wrap line correctly. */
693 virtual_screen.cursor_x += char_width;
694 if (virtual_screen.cursor_x >= virtual_screen.columns)
696 virtual_screen.cursor_x = 0;
698 if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
699 scroll_up ();
700 else
701 virtual_screen.cursor_y++;
705 /* Redraw cursor if it should be visible. */
706 /* Note: This will redraw the character as well, which means that the
707 above call to write_char is redundant when the cursor is showing. */
708 if (virtual_screen.cursor_state)
709 draw_cursor (1);
712 /* Use ASCII characters to determine normal character width. */
713 static unsigned int
714 calculate_normal_character_width (grub_font_t font)
716 struct grub_font_glyph *glyph;
717 unsigned int width = 0;
718 unsigned int i;
720 /* Get properties of every printable ASCII character. */
721 for (i = 32; i < 127; i++)
723 glyph = grub_font_get_glyph (font, i);
725 /* Skip unknown characters. Should never happen on normal conditions. */
726 if (! glyph)
727 continue;
729 if (glyph->device_width > width)
730 width = glyph->device_width;
733 return width;
736 static unsigned char
737 calculate_character_width (struct grub_font_glyph *glyph)
739 if (! glyph || glyph->device_width == 0)
740 return 1;
742 return (glyph->device_width
743 + (virtual_screen.normal_char_width - 1))
744 / virtual_screen.normal_char_width;
747 static grub_ssize_t
748 grub_gfxterm_getcharwidth (grub_uint32_t c)
750 struct grub_font_glyph *glyph;
751 unsigned char char_width;
753 /* Get properties of the character. */
754 glyph = grub_font_get_glyph (virtual_screen.font, c);
756 /* Calculate actual character width for glyph. */
757 char_width = calculate_character_width (glyph);
759 return char_width;
762 static grub_uint16_t
763 grub_virtual_screen_getwh (void)
765 return (virtual_screen.columns << 8) | virtual_screen.rows;
768 static grub_uint16_t
769 grub_virtual_screen_getxy (void)
771 return ((virtual_screen.cursor_x << 8) | virtual_screen.cursor_y);
774 static void
775 grub_gfxterm_gotoxy (grub_uint8_t x, grub_uint8_t y)
777 if (x >= virtual_screen.columns)
778 x = virtual_screen.columns - 1;
780 if (y >= virtual_screen.rows)
781 y = virtual_screen.rows - 1;
783 /* Erase current cursor, if any. */
784 if (virtual_screen.cursor_state)
785 draw_cursor (0);
787 virtual_screen.cursor_x = x;
788 virtual_screen.cursor_y = y;
790 /* Draw cursor if visible. */
791 if (virtual_screen.cursor_state)
792 draw_cursor (1);
795 static void
796 grub_virtual_screen_cls (void)
798 grub_uint32_t i;
800 for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
801 clear_char (&(virtual_screen.text_buffer[i]));
803 virtual_screen.cursor_x = virtual_screen.cursor_y = 0;
806 static void
807 grub_gfxterm_cls (void)
809 grub_video_color_t color;
811 /* Clear virtual screen. */
812 grub_virtual_screen_cls ();
814 /* Clear text layer. */
815 grub_video_set_active_render_target (text_layer);
816 color = virtual_screen.bg_color;
817 grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
818 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
820 /* Mark virtual screen to be redrawn. */
821 dirty_region_add_virtualscreen ();
824 static void
825 grub_virtual_screen_setcolorstate (grub_term_color_state state)
827 switch (state)
829 case GRUB_TERM_COLOR_STANDARD:
830 virtual_screen.term_color = virtual_screen.standard_color_setting;
831 break;
833 case GRUB_TERM_COLOR_NORMAL:
834 virtual_screen.term_color = virtual_screen.normal_color_setting;
835 break;
837 case GRUB_TERM_COLOR_HIGHLIGHT:
838 virtual_screen.term_color = virtual_screen.highlight_color_setting;
839 break;
841 default:
842 break;
845 /* Change color to virtual terminal. */
846 set_term_color (virtual_screen.term_color);
849 static void
850 grub_virtual_screen_setcolor (grub_uint8_t normal_color,
851 grub_uint8_t highlight_color)
853 virtual_screen.normal_color_setting = normal_color;
854 virtual_screen.highlight_color_setting = highlight_color;
857 static void
858 grub_virtual_screen_getcolor (grub_uint8_t *normal_color,
859 grub_uint8_t *highlight_color)
861 *normal_color = virtual_screen.normal_color_setting;
862 *highlight_color = virtual_screen.highlight_color_setting;
865 static void
866 grub_gfxterm_setcursor (int on)
868 if (virtual_screen.cursor_state != on)
870 if (virtual_screen.cursor_state)
871 draw_cursor (0);
872 else
873 draw_cursor (1);
875 virtual_screen.cursor_state = on;
879 static void
880 grub_gfxterm_refresh (void)
882 /* Redraw only changed regions. */
883 dirty_region_redraw ();
886 static grub_err_t
887 grub_gfxterm_background_image_cmd (grub_command_t cmd __attribute__ ((unused)),
888 int argc,
889 char **args)
891 /* Check that we have video adapter active. */
892 if (grub_video_get_info(NULL) != GRUB_ERR_NONE)
893 return grub_errno;
895 /* Destroy existing background bitmap if loaded. */
896 if (bitmap)
898 grub_video_bitmap_destroy (bitmap);
899 bitmap = 0;
901 /* Mark whole screen as dirty. */
902 dirty_region_reset ();
903 dirty_region_add (0, 0, mode_info.width, mode_info.height);
906 /* If filename was provided, try to load that. */
907 if (argc >= 1)
909 /* Try to load new one. */
910 grub_video_bitmap_load (&bitmap, args[0]);
911 if (grub_errno != GRUB_ERR_NONE)
912 return grub_errno;
914 /* If bitmap was loaded correctly, display it. */
915 if (bitmap)
917 /* Determine bitmap dimensions. */
918 bitmap_width = grub_video_bitmap_get_width (bitmap);
919 bitmap_height = grub_video_bitmap_get_width (bitmap);
921 /* Mark whole screen as dirty. */
922 dirty_region_reset ();
923 dirty_region_add (0, 0, mode_info.width, mode_info.height);
927 /* All was ok. */
928 grub_errno = GRUB_ERR_NONE;
929 return grub_errno;
932 static struct grub_term_output grub_video_term =
934 .name = "gfxterm",
935 .init = grub_gfxterm_init,
936 .fini = grub_gfxterm_fini,
937 .putchar = grub_gfxterm_putchar,
938 .getcharwidth = grub_gfxterm_getcharwidth,
939 .getwh = grub_virtual_screen_getwh,
940 .getxy = grub_virtual_screen_getxy,
941 .gotoxy = grub_gfxterm_gotoxy,
942 .cls = grub_gfxterm_cls,
943 .setcolorstate = grub_virtual_screen_setcolorstate,
944 .setcolor = grub_virtual_screen_setcolor,
945 .getcolor = grub_virtual_screen_getcolor,
946 .setcursor = grub_gfxterm_setcursor,
947 .refresh = grub_gfxterm_refresh,
948 .flags = 0,
949 .next = 0
952 static grub_command_t cmd;
954 GRUB_MOD_INIT(term_gfxterm)
956 grub_term_register_output ("gfxterm", &grub_video_term);
957 cmd = grub_register_command ("background_image",
958 grub_gfxterm_background_image_cmd,
959 0, "Load background image for active terminal");
962 GRUB_MOD_FINI(term_gfxterm)
964 grub_unregister_command (cmd);
965 grub_term_unregister_output (&grub_video_term);