2008-04-04 Pavel Roskin <proski@gnu.org>
[grub2/bean.git] / term / gfxterm.c
blobeb5136518b6ba0e0a2490c866bed4eb53b7b6074
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2006,2007,2008 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/machine/memory.h>
20 #include <grub/machine/console.h>
21 #include <grub/term.h>
22 #include <grub/types.h>
23 #include <grub/dl.h>
24 #include <grub/misc.h>
25 #include <grub/normal.h>
26 #include <grub/font.h>
27 #include <grub/arg.h>
28 #include <grub/mm.h>
29 #include <grub/env.h>
30 #include <grub/video.h>
31 #include <grub/bitmap.h>
33 #define DEFAULT_VIDEO_WIDTH 640
34 #define DEFAULT_VIDEO_HEIGHT 480
35 #define DEFAULT_VIDEO_FLAGS 0
37 #define DEFAULT_CHAR_WIDTH 8
38 #define DEFAULT_CHAR_HEIGHT 16
40 #define DEFAULT_BORDER_WIDTH 10
42 #define DEFAULT_STANDARD_COLOR 0x07
43 #define DEFAULT_NORMAL_COLOR 0x07
44 #define DEFAULT_HIGHLIGHT_COLOR 0x70
45 #define DEFAULT_CURSOR_COLOR 0x07
47 struct grub_dirty_region
49 int top_left_x;
50 int top_left_y;
51 int bottom_right_x;
52 int bottom_right_y;
55 struct grub_colored_char
57 /* An Unicode codepoint. */
58 grub_uint32_t code;
60 /* Color values. */
61 grub_video_color_t fg_color;
62 grub_video_color_t bg_color;
64 /* The width of this character minus one. */
65 unsigned char width;
67 /* The column index of this character. */
68 unsigned char index;
71 struct grub_virtual_screen
73 /* Dimensions of the virtual screen. */
74 unsigned int width;
75 unsigned int height;
77 /* Offset in the display. */
78 unsigned int offset_x;
79 unsigned int offset_y;
81 /* TTY Character sizes. */
82 unsigned int char_width;
83 unsigned int char_height;
85 /* Virtual screen TTY size. */
86 unsigned int columns;
87 unsigned int rows;
89 /* Current cursor details. */
90 unsigned int cursor_x;
91 unsigned int cursor_y;
92 int cursor_state;
94 /* Terminal color settings. */
95 grub_uint8_t standard_color_setting;
96 grub_uint8_t normal_color_setting;
97 grub_uint8_t highlight_color_setting;
98 grub_uint8_t term_color;
100 /* Color settings. */
101 grub_video_color_t fg_color;
102 grub_video_color_t bg_color;
103 grub_video_color_t cursor_color;
105 /* Text buffer for virtual screen. Contains (columns * rows) number
106 of entries. */
107 struct grub_colored_char *text_buffer;
110 static struct grub_virtual_screen virtual_screen;
112 static grub_dl_t my_mod;
113 static struct grub_video_mode_info mode_info;
115 static struct grub_video_render_target *text_layer;
117 static unsigned int bitmap_width;
118 static unsigned int bitmap_height;
119 static struct grub_video_bitmap *bitmap;
121 static struct grub_dirty_region dirty_region;
123 static void dirty_region_reset (void);
125 static int dirty_region_is_empty (void);
127 static void dirty_region_add (int x, int y,
128 unsigned int width, unsigned int height);
130 static void
131 set_term_color (grub_uint8_t term_color)
133 struct grub_video_render_target *old_target;
135 /* Save previous target and switch to text layer. */
136 grub_video_get_active_render_target (&old_target);
137 grub_video_set_active_render_target (text_layer);
139 /* Map terminal color to text layer compatible video colors. */
140 virtual_screen.fg_color = grub_video_map_color(term_color & 0x0f);
142 /* Special case: use black as transparent color. */
143 if (((term_color >> 4) & 0x0f) == 0)
145 virtual_screen.bg_color = grub_video_map_rgba(0, 0, 0, 0);
147 else
149 virtual_screen.bg_color = grub_video_map_color((term_color >> 4) & 0x0f);
152 /* Restore previous target. */
153 grub_video_set_active_render_target (old_target);
156 static void
157 grub_virtual_screen_free (void)
159 /* If virtual screen has been allocated, free it. */
160 if (virtual_screen.text_buffer != 0)
161 grub_free (virtual_screen.text_buffer);
163 /* Reset virtual screen data. */
164 grub_memset (&virtual_screen, 0, sizeof (virtual_screen));
166 /* Free render targets. */
167 grub_video_delete_render_target (text_layer);
168 text_layer = 0;
171 static grub_err_t
172 grub_virtual_screen_setup (unsigned int x, unsigned int y,
173 unsigned int width, unsigned int height)
175 /* Free old virtual screen. */
176 grub_virtual_screen_free ();
178 /* Initialize with default data. */
179 virtual_screen.width = width;
180 virtual_screen.height = height;
181 virtual_screen.offset_x = x;
182 virtual_screen.offset_y = y;
183 virtual_screen.char_width = DEFAULT_CHAR_WIDTH;
184 virtual_screen.char_height = DEFAULT_CHAR_HEIGHT;
185 virtual_screen.cursor_x = 0;
186 virtual_screen.cursor_y = 0;
187 virtual_screen.cursor_state = 1;
189 /* Calculate size of text buffer. */
190 virtual_screen.columns = virtual_screen.width / virtual_screen.char_width;
191 virtual_screen.rows = virtual_screen.height / virtual_screen.char_height;
193 /* Allocate memory for text buffer. */
194 virtual_screen.text_buffer =
195 (struct grub_colored_char *) grub_malloc (virtual_screen.columns
196 * virtual_screen.rows
197 * sizeof (*virtual_screen.text_buffer));
198 if (grub_errno != GRUB_ERR_NONE)
199 return grub_errno;
201 /* Create new render target for text layer. */
202 grub_video_create_render_target (&text_layer,
203 virtual_screen.width,
204 virtual_screen.height,
205 GRUB_VIDEO_MODE_TYPE_RGB
206 | GRUB_VIDEO_MODE_TYPE_ALPHA);
207 if (grub_errno != GRUB_ERR_NONE)
208 return grub_errno;
210 /* As we want to have colors compatible with rendering target,
211 we can only have those after mode is initialized. */
212 grub_video_set_active_render_target (text_layer);
214 virtual_screen.standard_color_setting = DEFAULT_STANDARD_COLOR;
215 virtual_screen.normal_color_setting = DEFAULT_NORMAL_COLOR;
216 virtual_screen.highlight_color_setting = DEFAULT_HIGHLIGHT_COLOR;
218 virtual_screen.term_color = virtual_screen.normal_color_setting;
220 set_term_color (virtual_screen.term_color);
222 virtual_screen.cursor_color = grub_video_map_color (DEFAULT_CURSOR_COLOR);
224 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
226 return grub_errno;
229 static grub_err_t
230 grub_gfxterm_init (void)
232 char *modevar;
233 int width = DEFAULT_VIDEO_WIDTH;
234 int height = DEFAULT_VIDEO_HEIGHT;
235 int depth = -1;
236 int flags = DEFAULT_VIDEO_FLAGS;
237 grub_video_color_t color;
239 /* Parse gfxmode environment variable if set. */
240 modevar = grub_env_get ("gfxmode");
241 if (modevar)
243 char *tmp;
244 char *next_mode;
245 char *current_mode;
246 char *param;
247 char *value;
248 int mode_found = 0;
250 /* Take copy of env.var. as we don't want to modify that. */
251 tmp = grub_strdup (modevar);
252 modevar = tmp;
254 if (grub_errno != GRUB_ERR_NONE)
255 return grub_errno;
257 /* Initialize next mode. */
258 next_mode = modevar;
260 /* Loop until all modes has been tested out. */
261 while (next_mode != NULL)
263 /* Use last next_mode as current mode. */
264 tmp = next_mode;
266 /* Reset video mode settings. */
267 width = DEFAULT_VIDEO_WIDTH;
268 height = DEFAULT_VIDEO_HEIGHT;
269 depth = -1;
270 flags = DEFAULT_VIDEO_FLAGS;
272 /* Save position of next mode and separate modes. */
273 next_mode = grub_strchr(next_mode, ';');
274 if (next_mode)
276 *next_mode = 0;
277 next_mode++;
280 /* Skip whitespace. */
281 while (grub_isspace (*tmp))
282 tmp++;
284 /* Initialize token holders. */
285 current_mode = tmp;
286 param = tmp;
287 value = NULL;
289 /* Parse <width>x<height>[x<depth>]*/
291 /* Find width value. */
292 value = param;
293 param = grub_strchr(param, 'x');
294 if (param == NULL)
296 grub_err_t rc;
298 /* First setup error message. */
299 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
300 "Invalid mode: %s\n",
301 current_mode);
303 /* Free memory before returning. */
304 grub_free (modevar);
306 return rc;
309 *param = 0;
310 param++;
312 width = grub_strtoul (value, 0, 0);
313 if (grub_errno != GRUB_ERR_NONE)
315 grub_err_t rc;
317 /* First setup error message. */
318 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
319 "Invalid mode: %s\n",
320 current_mode);
322 /* Free memory before returning. */
323 grub_free (modevar);
325 return rc;
328 /* Find height value. */
329 value = param;
330 param = grub_strchr(param, 'x');
331 if (param == NULL)
333 height = grub_strtoul (value, 0, 0);
334 if (grub_errno != GRUB_ERR_NONE)
336 grub_err_t rc;
338 /* First setup error message. */
339 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
340 "Invalid mode: %s\n",
341 current_mode);
343 /* Free memory before returning. */
344 grub_free (modevar);
346 return rc;
349 else
351 /* We have optional color depth value. */
352 *param = 0;
353 param++;
355 height = grub_strtoul (value, 0, 0);
356 if (grub_errno != GRUB_ERR_NONE)
358 grub_err_t rc;
360 /* First setup error message. */
361 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
362 "Invalid mode: %s\n",
363 current_mode);
365 /* Free memory before returning. */
366 grub_free (modevar);
368 return rc;
371 /* Convert color depth value. */
372 value = param;
373 depth = grub_strtoul (value, 0, 0);
374 if (grub_errno != GRUB_ERR_NONE)
376 grub_err_t rc;
378 /* First setup error message. */
379 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
380 "Invalid mode: %s\n",
381 current_mode);
383 /* Free memory before returning. */
384 grub_free (modevar);
386 return rc;
390 /* Try out video mode. */
392 /* If we have 8 or less bits, then assume that it is indexed color mode. */
393 if ((depth <= 8) && (depth != -1))
394 flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
396 /* We have more than 8 bits, then assume that it is RGB color mode. */
397 if (depth > 8)
398 flags |= GRUB_VIDEO_MODE_TYPE_RGB;
400 /* If user requested specific depth, forward that information to driver. */
401 if (depth != -1)
402 flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
403 & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
405 /* Try to initialize requested mode. Ignore any errors. */
406 grub_error_push ();
407 if (grub_video_setup (width, height, flags) != GRUB_ERR_NONE)
409 grub_error_pop ();
410 continue;
413 /* Figure out what mode we ended up. */
414 if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
416 /* Couldn't get video mode info, restore old mode and continue to next one. */
417 grub_error_pop ();
419 grub_video_restore ();
420 continue;
423 /* Restore state of error stack. */
424 grub_error_pop ();
426 /* Mode found! Exit loop. */
427 mode_found = 1;
428 break;
431 /* Free memory. */
432 grub_free (modevar);
434 if (!mode_found)
435 return grub_error (GRUB_ERR_BAD_ARGUMENT,
436 "No suitable mode found.");
438 else
440 /* No gfxmode variable set, use defaults. */
442 /* If we have 8 or less bits, then assume that it is indexed color mode. */
443 if ((depth <= 8) && (depth != -1))
444 flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
446 /* We have more than 8 bits, then assume that it is RGB color mode. */
447 if (depth > 8)
448 flags |= GRUB_VIDEO_MODE_TYPE_RGB;
450 /* If user requested specific depth, forward that information to driver. */
451 if (depth != -1)
452 flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
453 & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
455 /* Initialize user requested mode. */
456 if (grub_video_setup (width, height, flags) != GRUB_ERR_NONE)
457 return grub_errno;
459 /* Figure out what mode we ended up. */
460 if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
462 grub_video_restore ();
463 return grub_errno;
467 /* Make sure screen is black. */
468 color = grub_video_map_rgb (0, 0, 0);
469 grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
470 bitmap = 0;
472 /* Leave borders for virtual screen. */
473 width = mode_info.width - (2 * DEFAULT_BORDER_WIDTH);
474 height = mode_info.height - (2 * DEFAULT_BORDER_WIDTH);
476 /* Create virtual screen. */
477 if (grub_virtual_screen_setup (DEFAULT_BORDER_WIDTH, DEFAULT_BORDER_WIDTH,
478 width, height) != GRUB_ERR_NONE)
480 grub_video_restore ();
481 return grub_errno;
484 /* Mark whole screen as dirty. */
485 dirty_region_reset ();
486 dirty_region_add (0, 0, mode_info.width, mode_info.height);
488 return (grub_errno = GRUB_ERR_NONE);
491 static grub_err_t
492 grub_gfxterm_fini (void)
494 if (bitmap)
496 grub_video_bitmap_destroy (bitmap);
497 bitmap = 0;
500 grub_virtual_screen_free ();
502 grub_video_restore ();
504 return GRUB_ERR_NONE;
507 static void
508 redraw_screen_rect (unsigned int x, unsigned int y,
509 unsigned int width, unsigned int height)
511 grub_video_color_t color;
513 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
516 if (bitmap)
518 /* Render bitmap as background. */
519 grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_REPLACE, x, y,
520 x, y,
521 width, height);
523 /* If bitmap is smaller than requested blit area, use background
524 color. */
525 color = virtual_screen.bg_color;
527 /* Fill right side of the bitmap if needed. */
528 if ((x + width >= bitmap_width) && (y < bitmap_height))
530 int w = (x + width) - bitmap_width;
531 int h = height;
532 unsigned int tx = x;
534 if (y + height >= bitmap_height)
536 h = bitmap_height - y;
539 if (bitmap_width > tx)
541 tx = bitmap_width;
544 /* Render background layer. */
545 grub_video_fill_rect (color, tx, y, w, h);
548 /* Fill bottom side of the bitmap if needed. */
549 if (y + height >= bitmap_height)
551 int h = (y + height) - bitmap_height;
552 unsigned int ty = y;
554 if (bitmap_height > ty)
556 ty = bitmap_height;
559 /* Render background layer. */
560 grub_video_fill_rect (color, x, ty, width, h);
563 /* Render text layer as blended. */
564 grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, x, y,
565 x - virtual_screen.offset_x,
566 y - virtual_screen.offset_y,
567 width, height);
569 else
571 /* Render background layer. */
572 color = virtual_screen.bg_color;
573 grub_video_fill_rect (color, x, y, width, height);
575 /* Render text layer as replaced (to get texts background color). */
576 grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_REPLACE, x, y,
577 x - virtual_screen.offset_x,
578 y - virtual_screen.offset_y,
579 width, height);
583 static void
584 dirty_region_reset (void)
586 dirty_region.top_left_x = -1;
587 dirty_region.top_left_y = -1;
588 dirty_region.bottom_right_x = -1;
589 dirty_region.bottom_right_y = -1;
592 static int
593 dirty_region_is_empty (void)
595 if ((dirty_region.top_left_x == -1)
596 || (dirty_region.top_left_y == -1)
597 || (dirty_region.bottom_right_x == -1)
598 || (dirty_region.bottom_right_y == -1))
599 return 1;
600 return 0;
603 static void
604 dirty_region_add (int x, int y, unsigned int width, unsigned int height)
606 if ((width == 0) || (height == 0))
607 return;
609 if (dirty_region_is_empty ())
611 dirty_region.top_left_x = x;
612 dirty_region.top_left_y = y;
613 dirty_region.bottom_right_x = x + width - 1;
614 dirty_region.bottom_right_y = y + height - 1;
616 else
618 if (x < dirty_region.top_left_x)
619 dirty_region.top_left_x = x;
620 if (y < dirty_region.top_left_y)
621 dirty_region.top_left_y = y;
622 if ((x + (int)width - 1) > dirty_region.bottom_right_x)
623 dirty_region.bottom_right_x = x + width - 1;
624 if ((y + (int)height - 1) > dirty_region.bottom_right_y)
625 dirty_region.bottom_right_y = y + height - 1;
629 static void
630 dirty_region_add_virtualscreen (void)
632 /* Mark virtual screen as dirty. */
633 dirty_region_add (virtual_screen.offset_x, virtual_screen.offset_y,
634 virtual_screen.width, virtual_screen.height);
638 static void
639 dirty_region_redraw (void)
641 int x;
642 int y;
643 int width;
644 int height;
646 if (dirty_region_is_empty ())
647 return;
649 x = dirty_region.top_left_x;
650 y = dirty_region.top_left_y;
652 width = dirty_region.bottom_right_x - x + 1;
653 height = dirty_region.bottom_right_y - y + 1;
655 redraw_screen_rect (x, y, width, height);
657 dirty_region_reset ();
660 static void
661 write_char (void)
663 struct grub_colored_char *p;
664 struct grub_font_glyph glyph;
665 grub_video_color_t color;
666 grub_video_color_t bgcolor;
667 unsigned int x;
668 unsigned int y;
670 /* Find out active character. */
671 p = (virtual_screen.text_buffer
672 + virtual_screen.cursor_x
673 + (virtual_screen.cursor_y * virtual_screen.columns));
675 p -= p->index;
677 /* Get glyph for character. */
678 grub_font_get_glyph (p->code, &glyph);
680 color = p->fg_color;
681 bgcolor = p->bg_color;
683 x = virtual_screen.cursor_x * virtual_screen.char_width;
684 y = virtual_screen.cursor_y * virtual_screen.char_height;
686 /* Render glyph to text layer. */
687 grub_video_set_active_render_target (text_layer);
688 grub_video_fill_rect (bgcolor, x, y, glyph.width, glyph.height);
689 grub_video_blit_glyph (&glyph, color, x, y);
690 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
692 /* Mark character to be drawn. */
693 dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
694 glyph.width, glyph.height);
697 static void
698 write_cursor (void)
700 unsigned int x;
701 unsigned int y;
702 unsigned int width;
703 unsigned int height;
704 grub_video_color_t color;
706 /* Determine cursor properties and position on text layer. */
707 x = virtual_screen.cursor_x * virtual_screen.char_width;
708 y = ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 3;
709 width = virtual_screen.char_width;
710 height = 2;
712 color = virtual_screen.cursor_color;
714 /* Render cursor to text layer. */
715 grub_video_set_active_render_target (text_layer);
716 grub_video_fill_rect (color, x, y, width, height);
717 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
719 /* Mark cursor to be redrawn. */
720 dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
721 width, height);
724 static void
725 scroll_up (void)
727 unsigned int i;
728 grub_video_color_t color;
730 /* If we don't have background bitmap, remove cursor. */
731 if (!bitmap)
733 /* Remove cursor. */
734 write_char ();
736 /* Redraw only changed regions. */
737 dirty_region_redraw ();
740 /* Scroll text buffer with one line to up. */
741 grub_memmove (virtual_screen.text_buffer,
742 virtual_screen.text_buffer + virtual_screen.columns,
743 sizeof (*virtual_screen.text_buffer)
744 * virtual_screen.columns
745 * (virtual_screen.rows - 1));
747 /* Clear last line in text buffer. */
748 for (i = virtual_screen.columns * (virtual_screen.rows - 1);
749 i < virtual_screen.columns * virtual_screen.rows;
750 i++)
752 virtual_screen.text_buffer[i].code = ' ';
753 virtual_screen.text_buffer[i].fg_color = virtual_screen.fg_color;
754 virtual_screen.text_buffer[i].bg_color = virtual_screen.bg_color;
755 virtual_screen.text_buffer[i].width = 0;
756 virtual_screen.text_buffer[i].index = 0;
759 /* Scroll physical screen. */
760 grub_video_set_active_render_target (text_layer);
761 color = virtual_screen.bg_color;
762 grub_video_scroll (color, 0, -virtual_screen.char_height);
763 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
765 /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */
766 if (bitmap)
768 /* Mark virtual screen to be redrawn. */
769 dirty_region_add_virtualscreen ();
771 else
773 /* Clear new border area. */
774 grub_video_fill_rect (color,
775 virtual_screen.offset_x, virtual_screen.offset_y,
776 virtual_screen.width, virtual_screen.char_height);
778 /* Scroll physical screen. */
779 grub_video_scroll (color, 0, -virtual_screen.char_height);
781 /* Draw cursor if visible. */
782 if (virtual_screen.cursor_state)
783 write_cursor ();
787 static void
788 grub_gfxterm_putchar (grub_uint32_t c)
790 if (c == '\a')
791 /* FIXME */
792 return;
794 if (c == '\b' || c == '\n' || c == '\r')
796 /* Erase current cursor, if any. */
797 if (virtual_screen.cursor_state)
798 write_char ();
800 switch (c)
802 case '\b':
803 if (virtual_screen.cursor_x > 0)
804 virtual_screen.cursor_x--;
805 break;
807 case '\n':
808 if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
809 scroll_up ();
810 else
811 virtual_screen.cursor_y++;
812 break;
814 case '\r':
815 virtual_screen.cursor_x = 0;
816 break;
819 /* Redraw cursor if visible. */
820 if (virtual_screen.cursor_state)
821 write_cursor ();
823 else
825 struct grub_font_glyph glyph;
826 struct grub_colored_char *p;
828 /* Get properties of the character. */
829 grub_font_get_glyph (c, &glyph);
831 /* If we are about to exceed line length, wrap to next line. */
832 if (virtual_screen.cursor_x + glyph.char_width > virtual_screen.columns)
833 grub_putchar ('\n');
835 /* Find position on virtual screen, and fill information. */
836 p = (virtual_screen.text_buffer +
837 virtual_screen.cursor_x +
838 virtual_screen.cursor_y * virtual_screen.columns);
839 p->code = c;
840 p->fg_color = virtual_screen.fg_color;
841 p->bg_color = virtual_screen.bg_color;
842 p->width = glyph.char_width - 1;
843 p->index = 0;
845 /* If we have large glyph, add fixup info. */
846 if (glyph.char_width > 1)
848 unsigned i;
850 for (i = 1; i < glyph.char_width; i++)
852 p[i].code = ' ';
853 p[i].width = glyph.char_width - 1;
854 p[i].index = i;
858 /* Draw glyph. */
859 write_char ();
861 /* Make sure we scroll screen when needed and wrap line correctly. */
862 virtual_screen.cursor_x += glyph.char_width;
863 if (virtual_screen.cursor_x >= virtual_screen.columns)
865 virtual_screen.cursor_x = 0;
867 if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
868 scroll_up ();
869 else
870 virtual_screen.cursor_y++;
873 /* Draw cursor if visible. */
874 if (virtual_screen.cursor_state)
875 write_cursor ();
879 static grub_ssize_t
880 grub_gfxterm_getcharwidth (grub_uint32_t c)
882 struct grub_font_glyph glyph;
884 grub_font_get_glyph (c, &glyph);
886 return glyph.char_width;
889 static grub_uint16_t
890 grub_virtual_screen_getwh (void)
892 return (virtual_screen.columns << 8) | virtual_screen.rows;
895 static grub_uint16_t
896 grub_virtual_screen_getxy (void)
898 return ((virtual_screen.cursor_x << 8) | virtual_screen.cursor_y);
901 static void
902 grub_gfxterm_gotoxy (grub_uint8_t x, grub_uint8_t y)
904 if (x >= virtual_screen.columns)
905 x = virtual_screen.columns - 1;
907 if (y >= virtual_screen.rows)
908 y = virtual_screen.rows - 1;
910 if (virtual_screen.cursor_state)
911 write_char ();
913 virtual_screen.cursor_x = x;
914 virtual_screen.cursor_y = y;
916 if (virtual_screen.cursor_state)
917 write_cursor ();
920 static void
921 grub_virtual_screen_cls (void)
923 grub_uint32_t i;
925 for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
927 virtual_screen.text_buffer[i].code = ' ';
928 virtual_screen.text_buffer[i].fg_color = virtual_screen.fg_color;
929 virtual_screen.text_buffer[i].bg_color = virtual_screen.bg_color;
930 virtual_screen.text_buffer[i].width = 0;
931 virtual_screen.text_buffer[i].index = 0;
934 virtual_screen.cursor_x = virtual_screen.cursor_y = 0;
937 static void
938 grub_gfxterm_cls (void)
940 grub_video_color_t color;
942 /* Clear virtual screen. */
943 grub_virtual_screen_cls ();
945 /* Clear text layer. */
946 grub_video_set_active_render_target (text_layer);
947 color = virtual_screen.bg_color;
948 grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
949 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
951 /* Mark virtual screen to be redrawn. */
952 dirty_region_add_virtualscreen ();
955 static void
956 grub_virtual_screen_setcolorstate (grub_term_color_state state)
958 switch (state)
960 case GRUB_TERM_COLOR_STANDARD:
961 virtual_screen.term_color = virtual_screen.standard_color_setting;
962 break;
964 case GRUB_TERM_COLOR_NORMAL:
965 virtual_screen.term_color = virtual_screen.normal_color_setting;
966 break;
968 case GRUB_TERM_COLOR_HIGHLIGHT:
969 virtual_screen.term_color = virtual_screen.highlight_color_setting;
970 break;
972 default:
973 break;
976 /* Change color to virtual terminal. */
977 set_term_color (virtual_screen.term_color);
980 static void
981 grub_virtual_screen_setcolor (grub_uint8_t normal_color,
982 grub_uint8_t highlight_color)
984 virtual_screen.normal_color_setting = normal_color;
985 virtual_screen.highlight_color_setting = highlight_color;
988 static void
989 grub_virtual_screen_getcolor (grub_uint8_t *normal_color,
990 grub_uint8_t *highlight_color)
992 *normal_color = virtual_screen.normal_color_setting;
993 *highlight_color = virtual_screen.highlight_color_setting;
996 static void
997 grub_gfxterm_setcursor (int on)
999 if (virtual_screen.cursor_state != on)
1001 if (virtual_screen.cursor_state)
1002 write_char ();
1003 else
1004 write_cursor ();
1006 virtual_screen.cursor_state = on;
1010 static void
1011 grub_gfxterm_refresh (void)
1013 /* Redraw only changed regions. */
1014 dirty_region_redraw ();
1017 static grub_err_t
1018 grub_gfxterm_background_image_cmd (struct grub_arg_list *state __attribute__ ((unused)),
1019 int argc,
1020 char **args)
1022 /* Check that we have video adapter active. */
1023 if (grub_video_get_info(NULL) != GRUB_ERR_NONE)
1024 return grub_errno;
1026 /* Destroy existing background bitmap if loaded. */
1027 if (bitmap)
1029 grub_video_bitmap_destroy (bitmap);
1030 bitmap = 0;
1032 /* Mark whole screen as dirty. */
1033 dirty_region_reset ();
1034 dirty_region_add (0, 0, mode_info.width, mode_info.height);
1037 /* If filename was provided, try to load that. */
1038 if (argc >= 1)
1040 /* Try to load new one. */
1041 grub_video_bitmap_load (&bitmap, args[0]);
1042 if (grub_errno != GRUB_ERR_NONE)
1043 return grub_errno;
1045 /* If bitmap was loaded correctly, display it. */
1046 if (bitmap)
1048 /* Determine bitmap dimensions. */
1049 bitmap_width = grub_video_bitmap_get_width (bitmap);
1050 bitmap_height = grub_video_bitmap_get_width (bitmap);
1052 /* Mark whole screen as dirty. */
1053 dirty_region_reset ();
1054 dirty_region_add (0, 0, mode_info.width, mode_info.height);
1058 /* All was ok. */
1059 grub_errno = GRUB_ERR_NONE;
1060 return grub_errno;
1063 static struct grub_term grub_video_term =
1065 .name = "gfxterm",
1066 .init = grub_gfxterm_init,
1067 .fini = grub_gfxterm_fini,
1068 .putchar = grub_gfxterm_putchar,
1069 .getcharwidth = grub_gfxterm_getcharwidth,
1070 .checkkey = grub_console_checkkey,
1071 .getkey = grub_console_getkey,
1072 .getwh = grub_virtual_screen_getwh,
1073 .getxy = grub_virtual_screen_getxy,
1074 .gotoxy = grub_gfxterm_gotoxy,
1075 .cls = grub_gfxterm_cls,
1076 .setcolorstate = grub_virtual_screen_setcolorstate,
1077 .setcolor = grub_virtual_screen_setcolor,
1078 .getcolor = grub_virtual_screen_getcolor,
1079 .setcursor = grub_gfxterm_setcursor,
1080 .refresh = grub_gfxterm_refresh,
1081 .flags = 0,
1082 .next = 0
1085 GRUB_MOD_INIT(term_gfxterm)
1087 my_mod = mod;
1088 grub_term_register (&grub_video_term);
1090 grub_register_command ("background_image",
1091 grub_gfxterm_background_image_cmd,
1092 GRUB_COMMAND_FLAG_BOTH,
1093 "background_image",
1094 "Load background image for active terminal",
1098 GRUB_MOD_FINI(term_gfxterm)
1100 grub_unregister_command ("bgimage");
1101 grub_term_unregister (&grub_video_term);