2009-07-01 Pavel Roskin <proski@gnu.org>
[grub2/bean.git] / term / gfxterm.c
blobef93bb70fcdaeb0fea0c6f58b1c4ff6e9e5180ba
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 grub_virtual_screen_free (void)
156 /* If virtual screen has been allocated, free it. */
157 if (virtual_screen.text_buffer != 0)
158 grub_free (virtual_screen.text_buffer);
160 /* Reset virtual screen data. */
161 grub_memset (&virtual_screen, 0, sizeof (virtual_screen));
163 /* Free render targets. */
164 grub_video_delete_render_target (text_layer);
165 text_layer = 0;
168 static grub_err_t
169 grub_virtual_screen_setup (unsigned int x, unsigned int y,
170 unsigned int width, unsigned int height,
171 const char *font_name)
173 /* Free old virtual screen. */
174 grub_virtual_screen_free ();
176 /* Initialize with default data. */
177 virtual_screen.font = grub_font_get (font_name);
178 if (!virtual_screen.font)
179 return grub_error (GRUB_ERR_BAD_FONT,
180 "No font loaded.");
181 virtual_screen.width = width;
182 virtual_screen.height = height;
183 virtual_screen.offset_x = x;
184 virtual_screen.offset_y = y;
185 virtual_screen.normal_char_width =
186 calculate_normal_character_width (virtual_screen.font);
187 virtual_screen.normal_char_height =
188 grub_font_get_max_char_height (virtual_screen.font);
189 virtual_screen.cursor_x = 0;
190 virtual_screen.cursor_y = 0;
191 virtual_screen.cursor_state = 1;
193 /* Calculate size of text buffer. */
194 virtual_screen.columns = virtual_screen.width / virtual_screen.normal_char_width;
195 virtual_screen.rows = virtual_screen.height / virtual_screen.normal_char_height;
197 /* Allocate memory for text buffer. */
198 virtual_screen.text_buffer =
199 (struct grub_colored_char *) grub_malloc (virtual_screen.columns
200 * virtual_screen.rows
201 * sizeof (*virtual_screen.text_buffer));
202 if (grub_errno != GRUB_ERR_NONE)
203 return grub_errno;
205 /* Create new render target for text layer. */
206 grub_video_create_render_target (&text_layer,
207 virtual_screen.width,
208 virtual_screen.height,
209 GRUB_VIDEO_MODE_TYPE_RGB
210 | GRUB_VIDEO_MODE_TYPE_ALPHA);
211 if (grub_errno != GRUB_ERR_NONE)
212 return grub_errno;
214 /* As we want to have colors compatible with rendering target,
215 we can only have those after mode is initialized. */
216 grub_video_set_active_render_target (text_layer);
218 virtual_screen.standard_color_setting = DEFAULT_STANDARD_COLOR;
219 virtual_screen.normal_color_setting = DEFAULT_NORMAL_COLOR;
220 virtual_screen.highlight_color_setting = DEFAULT_HIGHLIGHT_COLOR;
222 virtual_screen.term_color = virtual_screen.normal_color_setting;
224 set_term_color (virtual_screen.term_color);
226 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
228 return grub_errno;
231 static int NESTED_FUNC_ATTR video_hook (grub_video_adapter_t p __attribute__ ((unused)),
232 struct grub_video_mode_info *info)
234 return ! (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT);
237 static grub_err_t
238 grub_gfxterm_init (void)
240 char *font_name;
241 char *modevar;
242 char *tmp;
243 grub_video_color_t color;
244 int width;
245 int height;
246 grub_err_t err;
248 /* Select the font to use. */
249 font_name = grub_env_get ("gfxterm_font");
250 if (! font_name)
251 font_name = ""; /* Allow fallback to any font. */
253 /* Parse gfxmode environment variable if set. */
254 modevar = grub_env_get ("gfxmode");
255 if (! modevar || *modevar == 0)
256 err = grub_video_set_mode (DEFAULT_VIDEO_MODE, video_hook);
257 else
259 tmp = grub_malloc (grub_strlen (modevar)
260 + sizeof (DEFAULT_VIDEO_MODE) + 1);
261 grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
262 err = grub_video_set_mode (tmp, video_hook);
263 grub_free (tmp);
266 if (err)
267 return err;
269 err = grub_video_get_info (&mode_info);
270 /* Figure out what mode we ended up. */
271 if (err)
272 return err;
274 /* Make sure screen is black. */
275 color = grub_video_map_rgb (0, 0, 0);
276 grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
277 bitmap = 0;
279 /* Leave borders for virtual screen. */
280 width = mode_info.width - (2 * DEFAULT_BORDER_WIDTH);
281 height = mode_info.height - (2 * DEFAULT_BORDER_WIDTH);
283 /* Create virtual screen. */
284 if (grub_virtual_screen_setup (DEFAULT_BORDER_WIDTH, DEFAULT_BORDER_WIDTH,
285 width, height, font_name) != GRUB_ERR_NONE)
287 grub_video_restore ();
288 return grub_errno;
291 /* Mark whole screen as dirty. */
292 dirty_region_reset ();
293 dirty_region_add (0, 0, mode_info.width, mode_info.height);
295 return (grub_errno = GRUB_ERR_NONE);
298 static grub_err_t
299 grub_gfxterm_fini (void)
301 if (bitmap)
303 grub_video_bitmap_destroy (bitmap);
304 bitmap = 0;
307 grub_virtual_screen_free ();
309 grub_video_restore ();
311 return GRUB_ERR_NONE;
314 static void
315 redraw_screen_rect (unsigned int x, unsigned int y,
316 unsigned int width, unsigned int height)
318 grub_video_color_t color;
320 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
323 if (bitmap)
325 /* Render bitmap as background. */
326 grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_REPLACE, x, y,
327 x, y,
328 width, height);
330 /* If bitmap is smaller than requested blit area, use background
331 color. */
332 color = virtual_screen.bg_color;
334 /* Fill right side of the bitmap if needed. */
335 if ((x + width >= bitmap_width) && (y < bitmap_height))
337 int w = (x + width) - bitmap_width;
338 int h = height;
339 unsigned int tx = x;
341 if (y + height >= bitmap_height)
343 h = bitmap_height - y;
346 if (bitmap_width > tx)
348 tx = bitmap_width;
351 /* Render background layer. */
352 grub_video_fill_rect (color, tx, y, w, h);
355 /* Fill bottom side of the bitmap if needed. */
356 if (y + height >= bitmap_height)
358 int h = (y + height) - bitmap_height;
359 unsigned int ty = y;
361 if (bitmap_height > ty)
363 ty = bitmap_height;
366 /* Render background layer. */
367 grub_video_fill_rect (color, x, ty, width, h);
370 /* Render text layer as blended. */
371 grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, x, y,
372 x - virtual_screen.offset_x,
373 y - virtual_screen.offset_y,
374 width, height);
376 else
378 /* Render background layer. */
379 color = virtual_screen.bg_color;
380 grub_video_fill_rect (color, x, y, width, height);
382 /* Render text layer as replaced (to get texts background color). */
383 grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_REPLACE, x, y,
384 x - virtual_screen.offset_x,
385 y - virtual_screen.offset_y,
386 width, height);
390 static void
391 dirty_region_reset (void)
393 dirty_region.top_left_x = -1;
394 dirty_region.top_left_y = -1;
395 dirty_region.bottom_right_x = -1;
396 dirty_region.bottom_right_y = -1;
399 static int
400 dirty_region_is_empty (void)
402 if ((dirty_region.top_left_x == -1)
403 || (dirty_region.top_left_y == -1)
404 || (dirty_region.bottom_right_x == -1)
405 || (dirty_region.bottom_right_y == -1))
406 return 1;
407 return 0;
410 static void
411 dirty_region_add (int x, int y, unsigned int width, unsigned int height)
413 if ((width == 0) || (height == 0))
414 return;
416 if (dirty_region_is_empty ())
418 dirty_region.top_left_x = x;
419 dirty_region.top_left_y = y;
420 dirty_region.bottom_right_x = x + width - 1;
421 dirty_region.bottom_right_y = y + height - 1;
423 else
425 if (x < dirty_region.top_left_x)
426 dirty_region.top_left_x = x;
427 if (y < dirty_region.top_left_y)
428 dirty_region.top_left_y = y;
429 if ((x + (int)width - 1) > dirty_region.bottom_right_x)
430 dirty_region.bottom_right_x = x + width - 1;
431 if ((y + (int)height - 1) > dirty_region.bottom_right_y)
432 dirty_region.bottom_right_y = y + height - 1;
436 static void
437 dirty_region_add_virtualscreen (void)
439 /* Mark virtual screen as dirty. */
440 dirty_region_add (virtual_screen.offset_x, virtual_screen.offset_y,
441 virtual_screen.width, virtual_screen.height);
445 static void
446 dirty_region_redraw (void)
448 int x;
449 int y;
450 int width;
451 int height;
453 if (dirty_region_is_empty ())
454 return;
456 x = dirty_region.top_left_x;
457 y = dirty_region.top_left_y;
459 width = dirty_region.bottom_right_x - x + 1;
460 height = dirty_region.bottom_right_y - y + 1;
462 redraw_screen_rect (x, y, width, height);
464 dirty_region_reset ();
467 static void
468 write_char (void)
470 struct grub_colored_char *p;
471 struct grub_font_glyph *glyph;
472 grub_video_color_t color;
473 grub_video_color_t bgcolor;
474 unsigned int x;
475 unsigned int y;
476 int ascent;
477 unsigned int height;
478 unsigned int width;
480 /* Find out active character. */
481 p = (virtual_screen.text_buffer
482 + virtual_screen.cursor_x
483 + (virtual_screen.cursor_y * virtual_screen.columns));
485 p -= p->index;
487 /* Get glyph for character. */
488 glyph = grub_font_get_glyph (virtual_screen.font, p->code);
489 ascent = grub_font_get_ascent (virtual_screen.font);
491 width = virtual_screen.normal_char_width * calculate_character_width(glyph);
492 height = virtual_screen.normal_char_height;
494 color = p->fg_color;
495 bgcolor = p->bg_color;
497 x = virtual_screen.cursor_x * virtual_screen.normal_char_width;
498 y = virtual_screen.cursor_y * virtual_screen.normal_char_height;
500 /* Render glyph to text layer. */
501 grub_video_set_active_render_target (text_layer);
502 grub_video_fill_rect (bgcolor, x, y, width, height);
503 grub_font_draw_glyph (glyph, color, x, y + ascent);
504 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
506 /* Mark character to be drawn. */
507 dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
508 width, height);
511 static void
512 draw_cursor (int show)
514 write_char ();
516 if (show)
518 unsigned int x;
519 unsigned int y;
520 unsigned int width;
521 unsigned int height;
522 grub_video_color_t color;
524 /* Determine cursor properties and position on text layer. */
525 x = virtual_screen.cursor_x * virtual_screen.normal_char_width;
526 width = virtual_screen.normal_char_width;
527 color = virtual_screen.fg_color;
528 y = (virtual_screen.cursor_y * virtual_screen.normal_char_height
529 + grub_font_get_ascent (virtual_screen.font));
530 height = 2;
532 /* Render cursor to text layer. */
533 grub_video_set_active_render_target (text_layer);
534 grub_video_fill_rect (color, x, y, width, height);
535 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
537 /* Mark cursor to be redrawn. */
538 dirty_region_add (virtual_screen.offset_x + x,
539 virtual_screen.offset_y + y,
540 width, height);
544 static void
545 scroll_up (void)
547 unsigned int i;
548 grub_video_color_t color;
550 /* If we don't have background bitmap, remove cursor. */
551 if (!bitmap)
553 /* Remove cursor. */
554 draw_cursor (0);
556 /* Redraw only changed regions. */
557 dirty_region_redraw ();
560 /* Scroll text buffer with one line to up. */
561 grub_memmove (virtual_screen.text_buffer,
562 virtual_screen.text_buffer + virtual_screen.columns,
563 sizeof (*virtual_screen.text_buffer)
564 * virtual_screen.columns
565 * (virtual_screen.rows - 1));
567 /* Clear last line in text buffer. */
568 for (i = virtual_screen.columns * (virtual_screen.rows - 1);
569 i < virtual_screen.columns * virtual_screen.rows;
570 i++)
572 virtual_screen.text_buffer[i].code = ' ';
573 virtual_screen.text_buffer[i].fg_color = virtual_screen.fg_color;
574 virtual_screen.text_buffer[i].bg_color = virtual_screen.bg_color;
575 virtual_screen.text_buffer[i].width = 0;
576 virtual_screen.text_buffer[i].index = 0;
579 /* Scroll physical screen. */
580 grub_video_set_active_render_target (text_layer);
581 color = virtual_screen.bg_color;
582 grub_video_scroll (color, 0, -virtual_screen.normal_char_height);
583 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
585 /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */
586 if (bitmap)
588 /* Mark virtual screen to be redrawn. */
589 dirty_region_add_virtualscreen ();
591 else
593 /* Clear new border area. */
594 grub_video_fill_rect (color,
595 virtual_screen.offset_x, virtual_screen.offset_y,
596 virtual_screen.width, virtual_screen.normal_char_height);
598 /* Scroll physical screen. */
599 grub_video_scroll (color, 0, -virtual_screen.normal_char_height);
601 /* Draw cursor if visible. */
602 if (virtual_screen.cursor_state)
603 draw_cursor (1);
607 static void
608 grub_gfxterm_putchar (grub_uint32_t c)
610 if (c == '\a')
611 /* FIXME */
612 return;
614 /* Erase current cursor, if any. */
615 if (virtual_screen.cursor_state)
616 draw_cursor (0);
618 if (c == '\b' || c == '\n' || c == '\r')
620 switch (c)
622 case '\b':
623 if (virtual_screen.cursor_x > 0)
624 virtual_screen.cursor_x--;
625 break;
627 case '\n':
628 if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
629 scroll_up ();
630 else
631 virtual_screen.cursor_y++;
632 break;
634 case '\r':
635 virtual_screen.cursor_x = 0;
636 break;
639 else
641 struct grub_font_glyph *glyph;
642 struct grub_colored_char *p;
643 unsigned char char_width;
645 /* Get properties of the character. */
646 glyph = grub_font_get_glyph (virtual_screen.font, c);
648 /* Calculate actual character width for glyph. This is number of
649 times of normal_font_width. */
650 char_width = calculate_character_width(glyph);
652 /* If we are about to exceed line length, wrap to next line. */
653 if (virtual_screen.cursor_x + char_width > virtual_screen.columns)
654 grub_putchar ('\n');
656 /* Find position on virtual screen, and fill information. */
657 p = (virtual_screen.text_buffer +
658 virtual_screen.cursor_x +
659 virtual_screen.cursor_y * virtual_screen.columns);
660 p->code = c;
661 p->fg_color = virtual_screen.fg_color;
662 p->bg_color = virtual_screen.bg_color;
663 p->width = char_width - 1;
664 p->index = 0;
666 /* If we have large glyph, add fixup info. */
667 if (char_width > 1)
669 unsigned i;
671 for (i = 1; i < char_width; i++)
673 p[i].code = ' ';
674 p[i].width = char_width - 1;
675 p[i].index = i;
679 /* Draw glyph. */
680 write_char ();
682 /* Make sure we scroll screen when needed and wrap line correctly. */
683 virtual_screen.cursor_x += char_width;
684 if (virtual_screen.cursor_x >= virtual_screen.columns)
686 virtual_screen.cursor_x = 0;
688 if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
689 scroll_up ();
690 else
691 virtual_screen.cursor_y++;
695 /* Redraw cursor if it should be visible. */
696 /* Note: This will redraw the character as well, which means that the
697 above call to write_char is redundant when the cursor is showing. */
698 if (virtual_screen.cursor_state)
699 draw_cursor (1);
702 /* Use ASCII characters to determine normal character width. */
703 static unsigned int
704 calculate_normal_character_width (grub_font_t font)
706 struct grub_font_glyph *glyph;
707 unsigned int width = 0;
708 unsigned int i;
710 /* Get properties of every printable ASCII character. */
711 for (i = 32; i < 127; i++)
713 glyph = grub_font_get_glyph (font, i);
715 /* Skip unknown characters. Should never happen on normal conditions. */
716 if (! glyph)
717 continue;
719 if (glyph->device_width > width)
720 width = glyph->device_width;
723 return width;
726 static unsigned char
727 calculate_character_width (struct grub_font_glyph *glyph)
729 if (! glyph || glyph->device_width == 0)
730 return 1;
732 return (glyph->device_width
733 + (virtual_screen.normal_char_width - 1))
734 / virtual_screen.normal_char_width;
737 static grub_ssize_t
738 grub_gfxterm_getcharwidth (grub_uint32_t c)
740 struct grub_font_glyph *glyph;
741 unsigned char char_width;
743 /* Get properties of the character. */
744 glyph = grub_font_get_glyph (virtual_screen.font, c);
746 /* Calculate actual character width for glyph. */
747 char_width = calculate_character_width (glyph);
749 return char_width;
752 static grub_uint16_t
753 grub_virtual_screen_getwh (void)
755 return (virtual_screen.columns << 8) | virtual_screen.rows;
758 static grub_uint16_t
759 grub_virtual_screen_getxy (void)
761 return ((virtual_screen.cursor_x << 8) | virtual_screen.cursor_y);
764 static void
765 grub_gfxterm_gotoxy (grub_uint8_t x, grub_uint8_t y)
767 if (x >= virtual_screen.columns)
768 x = virtual_screen.columns - 1;
770 if (y >= virtual_screen.rows)
771 y = virtual_screen.rows - 1;
773 /* Erase current cursor, if any. */
774 if (virtual_screen.cursor_state)
775 draw_cursor (0);
777 virtual_screen.cursor_x = x;
778 virtual_screen.cursor_y = y;
780 /* Draw cursor if visible. */
781 if (virtual_screen.cursor_state)
782 draw_cursor (1);
785 static void
786 grub_virtual_screen_cls (void)
788 grub_uint32_t i;
790 for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
792 virtual_screen.text_buffer[i].code = ' ';
793 virtual_screen.text_buffer[i].fg_color = virtual_screen.fg_color;
794 virtual_screen.text_buffer[i].bg_color = virtual_screen.bg_color;
795 virtual_screen.text_buffer[i].width = 0;
796 virtual_screen.text_buffer[i].index = 0;
799 virtual_screen.cursor_x = virtual_screen.cursor_y = 0;
802 static void
803 grub_gfxterm_cls (void)
805 grub_video_color_t color;
807 /* Clear virtual screen. */
808 grub_virtual_screen_cls ();
810 /* Clear text layer. */
811 grub_video_set_active_render_target (text_layer);
812 color = virtual_screen.bg_color;
813 grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
814 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
816 /* Mark virtual screen to be redrawn. */
817 dirty_region_add_virtualscreen ();
820 static void
821 grub_virtual_screen_setcolorstate (grub_term_color_state state)
823 switch (state)
825 case GRUB_TERM_COLOR_STANDARD:
826 virtual_screen.term_color = virtual_screen.standard_color_setting;
827 break;
829 case GRUB_TERM_COLOR_NORMAL:
830 virtual_screen.term_color = virtual_screen.normal_color_setting;
831 break;
833 case GRUB_TERM_COLOR_HIGHLIGHT:
834 virtual_screen.term_color = virtual_screen.highlight_color_setting;
835 break;
837 default:
838 break;
841 /* Change color to virtual terminal. */
842 set_term_color (virtual_screen.term_color);
845 static void
846 grub_virtual_screen_setcolor (grub_uint8_t normal_color,
847 grub_uint8_t highlight_color)
849 virtual_screen.normal_color_setting = normal_color;
850 virtual_screen.highlight_color_setting = highlight_color;
853 static void
854 grub_virtual_screen_getcolor (grub_uint8_t *normal_color,
855 grub_uint8_t *highlight_color)
857 *normal_color = virtual_screen.normal_color_setting;
858 *highlight_color = virtual_screen.highlight_color_setting;
861 static void
862 grub_gfxterm_setcursor (int on)
864 if (virtual_screen.cursor_state != on)
866 if (virtual_screen.cursor_state)
867 draw_cursor (0);
868 else
869 draw_cursor (1);
871 virtual_screen.cursor_state = on;
875 static void
876 grub_gfxterm_refresh (void)
878 /* Redraw only changed regions. */
879 dirty_region_redraw ();
882 static grub_err_t
883 grub_gfxterm_background_image_cmd (grub_command_t cmd __attribute__ ((unused)),
884 int argc,
885 char **args)
887 /* Check that we have video adapter active. */
888 if (grub_video_get_info(NULL) != GRUB_ERR_NONE)
889 return grub_errno;
891 /* Destroy existing background bitmap if loaded. */
892 if (bitmap)
894 grub_video_bitmap_destroy (bitmap);
895 bitmap = 0;
897 /* Mark whole screen as dirty. */
898 dirty_region_reset ();
899 dirty_region_add (0, 0, mode_info.width, mode_info.height);
902 /* If filename was provided, try to load that. */
903 if (argc >= 1)
905 /* Try to load new one. */
906 grub_video_bitmap_load (&bitmap, args[0]);
907 if (grub_errno != GRUB_ERR_NONE)
908 return grub_errno;
910 /* If bitmap was loaded correctly, display it. */
911 if (bitmap)
913 /* Determine bitmap dimensions. */
914 bitmap_width = grub_video_bitmap_get_width (bitmap);
915 bitmap_height = grub_video_bitmap_get_width (bitmap);
917 /* Mark whole screen as dirty. */
918 dirty_region_reset ();
919 dirty_region_add (0, 0, mode_info.width, mode_info.height);
923 /* All was ok. */
924 grub_errno = GRUB_ERR_NONE;
925 return grub_errno;
928 static struct grub_term_output grub_video_term =
930 .name = "gfxterm",
931 .init = grub_gfxterm_init,
932 .fini = grub_gfxterm_fini,
933 .putchar = grub_gfxterm_putchar,
934 .getcharwidth = grub_gfxterm_getcharwidth,
935 .getwh = grub_virtual_screen_getwh,
936 .getxy = grub_virtual_screen_getxy,
937 .gotoxy = grub_gfxterm_gotoxy,
938 .cls = grub_gfxterm_cls,
939 .setcolorstate = grub_virtual_screen_setcolorstate,
940 .setcolor = grub_virtual_screen_setcolor,
941 .getcolor = grub_virtual_screen_getcolor,
942 .setcursor = grub_gfxterm_setcursor,
943 .refresh = grub_gfxterm_refresh,
944 .flags = 0,
945 .next = 0
948 static grub_command_t cmd;
950 GRUB_MOD_INIT(term_gfxterm)
952 grub_term_register_output ("gfxterm", &grub_video_term);
953 cmd = grub_register_command ("background_image",
954 grub_gfxterm_background_image_cmd,
955 0, "Load background image for active terminal");
958 GRUB_MOD_FINI(term_gfxterm)
960 grub_unregister_command (cmd);
961 grub_term_unregister_output (&grub_video_term);