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>
22 #include <grub/misc.h>
23 #include <grub/normal.h>
24 #include <grub/font.h>
28 #include <grub/video.h>
29 #include <grub/bitmap.h>
31 #define DEFAULT_VIDEO_WIDTH 640
32 #define DEFAULT_VIDEO_HEIGHT 480
33 #define DEFAULT_VIDEO_FLAGS 0
35 #define DEFAULT_BORDER_WIDTH 10
37 #define DEFAULT_STANDARD_COLOR 0x07
38 #define DEFAULT_NORMAL_COLOR 0x07
39 #define DEFAULT_HIGHLIGHT_COLOR 0x70
41 struct grub_dirty_region
49 struct grub_colored_char
51 /* An Unicode codepoint. */
55 grub_video_color_t fg_color
;
56 grub_video_color_t bg_color
;
58 /* The width of this character minus one. */
61 /* The column index of this character. */
65 struct grub_virtual_screen
67 /* Dimensions of the virtual screen in pixels. */
71 /* Offset in the display in pixels. */
72 unsigned int offset_x
;
73 unsigned int offset_y
;
75 /* TTY Character sizes in pixes. */
76 unsigned int normal_char_width
;
77 unsigned int normal_char_height
;
79 /* Virtual screen TTY size in characters. */
83 /* Current cursor location in characters. */
84 unsigned int cursor_x
;
85 unsigned int cursor_y
;
87 /* Current cursor state. */
93 /* Terminal color settings. */
94 grub_uint8_t standard_color_setting
;
95 grub_uint8_t normal_color_setting
;
96 grub_uint8_t highlight_color_setting
;
97 grub_uint8_t term_color
;
100 grub_video_color_t fg_color
;
101 grub_video_color_t bg_color
;
103 /* Text buffer for virtual screen. Contains (columns * rows) number
105 struct grub_colored_char
*text_buffer
;
108 static struct grub_virtual_screen virtual_screen
;
110 static grub_dl_t my_mod
;
111 static struct grub_video_mode_info mode_info
;
113 static struct grub_video_render_target
*text_layer
;
115 static unsigned int bitmap_width
;
116 static unsigned int bitmap_height
;
117 static struct grub_video_bitmap
*bitmap
;
119 static struct grub_dirty_region dirty_region
;
121 static void dirty_region_reset (void);
123 static int dirty_region_is_empty (void);
125 static void dirty_region_add (int x
, int y
,
126 unsigned int width
, unsigned int height
);
128 static unsigned int calculate_normal_character_width (grub_font_t font
);
130 static unsigned char calculate_character_width (struct grub_font_glyph
*glyph
);
133 set_term_color (grub_uint8_t term_color
)
135 struct grub_video_render_target
*old_target
;
137 /* Save previous target and switch to text layer. */
138 grub_video_get_active_render_target (&old_target
);
139 grub_video_set_active_render_target (text_layer
);
141 /* Map terminal color to text layer compatible video colors. */
142 virtual_screen
.fg_color
= grub_video_map_color(term_color
& 0x0f);
144 /* Special case: use black as transparent color. */
145 if (((term_color
>> 4) & 0x0f) == 0)
147 virtual_screen
.bg_color
= grub_video_map_rgba(0, 0, 0, 0);
151 virtual_screen
.bg_color
= grub_video_map_color((term_color
>> 4) & 0x0f);
154 /* Restore previous target. */
155 grub_video_set_active_render_target (old_target
);
159 grub_virtual_screen_free (void)
161 /* If virtual screen has been allocated, free it. */
162 if (virtual_screen
.text_buffer
!= 0)
163 grub_free (virtual_screen
.text_buffer
);
165 /* Reset virtual screen data. */
166 grub_memset (&virtual_screen
, 0, sizeof (virtual_screen
));
168 /* Free render targets. */
169 grub_video_delete_render_target (text_layer
);
174 grub_virtual_screen_setup (unsigned int x
, unsigned int y
,
175 unsigned int width
, unsigned int height
,
176 const char *font_name
)
178 /* Free old virtual screen. */
179 grub_virtual_screen_free ();
181 /* Initialize with default data. */
182 virtual_screen
.font
= grub_font_get (font_name
);
183 if (!virtual_screen
.font
)
184 return grub_error (GRUB_ERR_BAD_FONT
,
186 virtual_screen
.width
= width
;
187 virtual_screen
.height
= height
;
188 virtual_screen
.offset_x
= x
;
189 virtual_screen
.offset_y
= y
;
190 virtual_screen
.normal_char_width
=
191 calculate_normal_character_width (virtual_screen
.font
);
192 virtual_screen
.normal_char_height
=
193 grub_font_get_max_char_height (virtual_screen
.font
);
194 virtual_screen
.cursor_x
= 0;
195 virtual_screen
.cursor_y
= 0;
196 virtual_screen
.cursor_state
= 1;
198 /* Calculate size of text buffer. */
199 virtual_screen
.columns
= virtual_screen
.width
/ virtual_screen
.normal_char_width
;
200 virtual_screen
.rows
= virtual_screen
.height
/ virtual_screen
.normal_char_height
;
202 /* Allocate memory for text buffer. */
203 virtual_screen
.text_buffer
=
204 (struct grub_colored_char
*) grub_malloc (virtual_screen
.columns
205 * virtual_screen
.rows
206 * sizeof (*virtual_screen
.text_buffer
));
207 if (grub_errno
!= GRUB_ERR_NONE
)
210 /* Create new render target for text layer. */
211 grub_video_create_render_target (&text_layer
,
212 virtual_screen
.width
,
213 virtual_screen
.height
,
214 GRUB_VIDEO_MODE_TYPE_RGB
215 | GRUB_VIDEO_MODE_TYPE_ALPHA
);
216 if (grub_errno
!= GRUB_ERR_NONE
)
219 /* As we want to have colors compatible with rendering target,
220 we can only have those after mode is initialized. */
221 grub_video_set_active_render_target (text_layer
);
223 virtual_screen
.standard_color_setting
= DEFAULT_STANDARD_COLOR
;
224 virtual_screen
.normal_color_setting
= DEFAULT_NORMAL_COLOR
;
225 virtual_screen
.highlight_color_setting
= DEFAULT_HIGHLIGHT_COLOR
;
227 virtual_screen
.term_color
= virtual_screen
.normal_color_setting
;
229 set_term_color (virtual_screen
.term_color
);
231 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
237 grub_gfxterm_init (void)
241 int width
= DEFAULT_VIDEO_WIDTH
;
242 int height
= DEFAULT_VIDEO_HEIGHT
;
244 int flags
= DEFAULT_VIDEO_FLAGS
;
245 grub_video_color_t color
;
247 /* Select the font to use. */
248 font_name
= grub_env_get ("gfxterm_font");
250 font_name
= ""; /* Allow fallback to any font. */
252 /* Parse gfxmode environment variable if set. */
253 modevar
= grub_env_get ("gfxmode");
263 /* Take copy of env.var. as we don't want to modify that. */
264 tmp
= grub_strdup (modevar
);
267 if (grub_errno
!= GRUB_ERR_NONE
)
270 /* Initialize next mode. */
273 /* Loop until all modes has been tested out. */
274 while (next_mode
!= NULL
)
276 /* Use last next_mode as current mode. */
279 /* Reset video mode settings. */
280 width
= DEFAULT_VIDEO_WIDTH
;
281 height
= DEFAULT_VIDEO_HEIGHT
;
283 flags
= DEFAULT_VIDEO_FLAGS
;
285 /* Save position of next mode and separate modes. */
286 next_mode
= grub_strchr(next_mode
, ';');
293 /* Skip whitespace. */
294 while (grub_isspace (*tmp
))
297 /* Initialize token holders. */
302 /* Parse <width>x<height>[x<depth>]*/
304 /* Find width value. */
306 param
= grub_strchr(param
, 'x');
311 /* First setup error message. */
312 rc
= grub_error (GRUB_ERR_BAD_ARGUMENT
,
313 "Invalid mode: %s\n",
316 /* Free memory before returning. */
325 width
= grub_strtoul (value
, 0, 0);
326 if (grub_errno
!= GRUB_ERR_NONE
)
330 /* First setup error message. */
331 rc
= grub_error (GRUB_ERR_BAD_ARGUMENT
,
332 "Invalid mode: %s\n",
335 /* Free memory before returning. */
341 /* Find height value. */
343 param
= grub_strchr(param
, 'x');
346 height
= grub_strtoul (value
, 0, 0);
347 if (grub_errno
!= GRUB_ERR_NONE
)
351 /* First setup error message. */
352 rc
= grub_error (GRUB_ERR_BAD_ARGUMENT
,
353 "Invalid mode: %s\n",
356 /* Free memory before returning. */
364 /* We have optional color depth value. */
368 height
= grub_strtoul (value
, 0, 0);
369 if (grub_errno
!= GRUB_ERR_NONE
)
373 /* First setup error message. */
374 rc
= grub_error (GRUB_ERR_BAD_ARGUMENT
,
375 "Invalid mode: %s\n",
378 /* Free memory before returning. */
384 /* Convert color depth value. */
386 depth
= grub_strtoul (value
, 0, 0);
387 if (grub_errno
!= GRUB_ERR_NONE
)
391 /* First setup error message. */
392 rc
= grub_error (GRUB_ERR_BAD_ARGUMENT
,
393 "Invalid mode: %s\n",
396 /* Free memory before returning. */
403 /* Try out video mode. */
405 /* If we have 8 or less bits, then assume that it is indexed color mode. */
406 if ((depth
<= 8) && (depth
!= -1))
407 flags
|= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
;
409 /* We have more than 8 bits, then assume that it is RGB color mode. */
411 flags
|= GRUB_VIDEO_MODE_TYPE_RGB
;
413 /* If user requested specific depth, forward that information to driver. */
415 flags
|= (depth
<< GRUB_VIDEO_MODE_TYPE_DEPTH_POS
)
416 & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK
;
418 /* Try to initialize requested mode. Ignore any errors. */
420 if (grub_video_setup (width
, height
, flags
) != GRUB_ERR_NONE
)
426 /* Figure out what mode we ended up. */
427 if (grub_video_get_info (&mode_info
) != GRUB_ERR_NONE
)
429 /* Couldn't get video mode info, restore old mode and continue to next one. */
432 grub_video_restore ();
436 /* Restore state of error stack. */
439 /* Mode found! Exit loop. */
448 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
449 "No suitable mode found.");
453 /* No gfxmode variable set, use defaults. */
455 /* If we have 8 or less bits, then assume that it is indexed color mode. */
456 if ((depth
<= 8) && (depth
!= -1))
457 flags
|= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
;
459 /* We have more than 8 bits, then assume that it is RGB color mode. */
461 flags
|= GRUB_VIDEO_MODE_TYPE_RGB
;
463 /* If user requested specific depth, forward that information to driver. */
465 flags
|= (depth
<< GRUB_VIDEO_MODE_TYPE_DEPTH_POS
)
466 & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK
;
468 /* Initialize user requested mode. */
469 if (grub_video_setup (width
, height
, flags
) != GRUB_ERR_NONE
)
472 /* Figure out what mode we ended up. */
473 if (grub_video_get_info (&mode_info
) != GRUB_ERR_NONE
)
475 grub_video_restore ();
480 /* Make sure screen is black. */
481 color
= grub_video_map_rgb (0, 0, 0);
482 grub_video_fill_rect (color
, 0, 0, mode_info
.width
, mode_info
.height
);
485 /* Leave borders for virtual screen. */
486 width
= mode_info
.width
- (2 * DEFAULT_BORDER_WIDTH
);
487 height
= mode_info
.height
- (2 * DEFAULT_BORDER_WIDTH
);
489 /* Create virtual screen. */
490 if (grub_virtual_screen_setup (DEFAULT_BORDER_WIDTH
, DEFAULT_BORDER_WIDTH
,
491 width
, height
, font_name
) != GRUB_ERR_NONE
)
493 grub_video_restore ();
497 /* Mark whole screen as dirty. */
498 dirty_region_reset ();
499 dirty_region_add (0, 0, mode_info
.width
, mode_info
.height
);
501 return (grub_errno
= GRUB_ERR_NONE
);
505 grub_gfxterm_fini (void)
509 grub_video_bitmap_destroy (bitmap
);
513 grub_virtual_screen_free ();
515 grub_video_restore ();
517 return GRUB_ERR_NONE
;
521 redraw_screen_rect (unsigned int x
, unsigned int y
,
522 unsigned int width
, unsigned int height
)
524 grub_video_color_t color
;
526 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
531 /* Render bitmap as background. */
532 grub_video_blit_bitmap (bitmap
, GRUB_VIDEO_BLIT_REPLACE
, x
, y
,
536 /* If bitmap is smaller than requested blit area, use background
538 color
= virtual_screen
.bg_color
;
540 /* Fill right side of the bitmap if needed. */
541 if ((x
+ width
>= bitmap_width
) && (y
< bitmap_height
))
543 int w
= (x
+ width
) - bitmap_width
;
547 if (y
+ height
>= bitmap_height
)
549 h
= bitmap_height
- y
;
552 if (bitmap_width
> tx
)
557 /* Render background layer. */
558 grub_video_fill_rect (color
, tx
, y
, w
, h
);
561 /* Fill bottom side of the bitmap if needed. */
562 if (y
+ height
>= bitmap_height
)
564 int h
= (y
+ height
) - bitmap_height
;
567 if (bitmap_height
> ty
)
572 /* Render background layer. */
573 grub_video_fill_rect (color
, x
, ty
, width
, h
);
576 /* Render text layer as blended. */
577 grub_video_blit_render_target (text_layer
, GRUB_VIDEO_BLIT_BLEND
, x
, y
,
578 x
- virtual_screen
.offset_x
,
579 y
- virtual_screen
.offset_y
,
584 /* Render background layer. */
585 color
= virtual_screen
.bg_color
;
586 grub_video_fill_rect (color
, x
, y
, width
, height
);
588 /* Render text layer as replaced (to get texts background color). */
589 grub_video_blit_render_target (text_layer
, GRUB_VIDEO_BLIT_REPLACE
, x
, y
,
590 x
- virtual_screen
.offset_x
,
591 y
- virtual_screen
.offset_y
,
597 dirty_region_reset (void)
599 dirty_region
.top_left_x
= -1;
600 dirty_region
.top_left_y
= -1;
601 dirty_region
.bottom_right_x
= -1;
602 dirty_region
.bottom_right_y
= -1;
606 dirty_region_is_empty (void)
608 if ((dirty_region
.top_left_x
== -1)
609 || (dirty_region
.top_left_y
== -1)
610 || (dirty_region
.bottom_right_x
== -1)
611 || (dirty_region
.bottom_right_y
== -1))
617 dirty_region_add (int x
, int y
, unsigned int width
, unsigned int height
)
619 if ((width
== 0) || (height
== 0))
622 if (dirty_region_is_empty ())
624 dirty_region
.top_left_x
= x
;
625 dirty_region
.top_left_y
= y
;
626 dirty_region
.bottom_right_x
= x
+ width
- 1;
627 dirty_region
.bottom_right_y
= y
+ height
- 1;
631 if (x
< dirty_region
.top_left_x
)
632 dirty_region
.top_left_x
= x
;
633 if (y
< dirty_region
.top_left_y
)
634 dirty_region
.top_left_y
= y
;
635 if ((x
+ (int)width
- 1) > dirty_region
.bottom_right_x
)
636 dirty_region
.bottom_right_x
= x
+ width
- 1;
637 if ((y
+ (int)height
- 1) > dirty_region
.bottom_right_y
)
638 dirty_region
.bottom_right_y
= y
+ height
- 1;
643 dirty_region_add_virtualscreen (void)
645 /* Mark virtual screen as dirty. */
646 dirty_region_add (virtual_screen
.offset_x
, virtual_screen
.offset_y
,
647 virtual_screen
.width
, virtual_screen
.height
);
652 dirty_region_redraw (void)
659 if (dirty_region_is_empty ())
662 x
= dirty_region
.top_left_x
;
663 y
= dirty_region
.top_left_y
;
665 width
= dirty_region
.bottom_right_x
- x
+ 1;
666 height
= dirty_region
.bottom_right_y
- y
+ 1;
668 redraw_screen_rect (x
, y
, width
, height
);
670 dirty_region_reset ();
676 struct grub_colored_char
*p
;
677 struct grub_font_glyph
*glyph
;
678 grub_video_color_t color
;
679 grub_video_color_t bgcolor
;
686 /* Find out active character. */
687 p
= (virtual_screen
.text_buffer
688 + virtual_screen
.cursor_x
689 + (virtual_screen
.cursor_y
* virtual_screen
.columns
));
693 /* Get glyph for character. */
694 glyph
= grub_font_get_glyph (virtual_screen
.font
, p
->code
);
695 ascent
= grub_font_get_ascent (virtual_screen
.font
);
697 width
= virtual_screen
.normal_char_width
* calculate_character_width(glyph
);
698 height
= virtual_screen
.normal_char_height
;
701 bgcolor
= p
->bg_color
;
703 x
= virtual_screen
.cursor_x
* virtual_screen
.normal_char_width
;
704 y
= virtual_screen
.cursor_y
* virtual_screen
.normal_char_height
;
706 /* Render glyph to text layer. */
707 grub_video_set_active_render_target (text_layer
);
708 grub_video_fill_rect (bgcolor
, x
, y
, width
, height
);
709 grub_font_draw_glyph (glyph
, color
, x
, y
+ ascent
);
710 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
712 /* Mark character to be drawn. */
713 dirty_region_add (virtual_screen
.offset_x
+ x
, virtual_screen
.offset_y
+ y
,
718 draw_cursor (int show
)
724 grub_video_color_t color
;
726 /* Determine cursor properties and position on text layer. */
727 x
= virtual_screen
.cursor_x
* virtual_screen
.normal_char_width
;
728 y
= (virtual_screen
.cursor_y
* virtual_screen
.normal_char_height
729 + grub_font_get_ascent (virtual_screen
.font
));
730 width
= virtual_screen
.normal_char_width
;
735 color
= virtual_screen
.fg_color
;
739 color
= virtual_screen
.bg_color
;
740 y
= virtual_screen
.cursor_y
* virtual_screen
.normal_char_height
;
741 height
= virtual_screen
.normal_char_height
;
744 /* Render cursor to text layer. */
745 grub_video_set_active_render_target (text_layer
);
746 grub_video_fill_rect (color
, x
, y
, width
, height
);
747 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
749 /* Mark cursor to be redrawn. */
750 dirty_region_add (virtual_screen
.offset_x
+ x
, virtual_screen
.offset_y
+ y
,
758 grub_video_color_t color
;
760 /* If we don't have background bitmap, remove cursor. */
766 /* Redraw only changed regions. */
767 dirty_region_redraw ();
770 /* Scroll text buffer with one line to up. */
771 grub_memmove (virtual_screen
.text_buffer
,
772 virtual_screen
.text_buffer
+ virtual_screen
.columns
,
773 sizeof (*virtual_screen
.text_buffer
)
774 * virtual_screen
.columns
775 * (virtual_screen
.rows
- 1));
777 /* Clear last line in text buffer. */
778 for (i
= virtual_screen
.columns
* (virtual_screen
.rows
- 1);
779 i
< virtual_screen
.columns
* virtual_screen
.rows
;
782 virtual_screen
.text_buffer
[i
].code
= ' ';
783 virtual_screen
.text_buffer
[i
].fg_color
= virtual_screen
.fg_color
;
784 virtual_screen
.text_buffer
[i
].bg_color
= virtual_screen
.bg_color
;
785 virtual_screen
.text_buffer
[i
].width
= 0;
786 virtual_screen
.text_buffer
[i
].index
= 0;
789 /* Scroll physical screen. */
790 grub_video_set_active_render_target (text_layer
);
791 color
= virtual_screen
.bg_color
;
792 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
);
793 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
795 /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */
798 /* Mark virtual screen to be redrawn. */
799 dirty_region_add_virtualscreen ();
803 /* Clear new border area. */
804 grub_video_fill_rect (color
,
805 virtual_screen
.offset_x
, virtual_screen
.offset_y
,
806 virtual_screen
.width
, virtual_screen
.normal_char_height
);
808 /* Scroll physical screen. */
809 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
);
811 /* Draw cursor if visible. */
812 if (virtual_screen
.cursor_state
)
818 grub_gfxterm_putchar (grub_uint32_t c
)
824 if (c
== '\b' || c
== '\n' || c
== '\r')
826 /* Erase current cursor, if any. */
827 if (virtual_screen
.cursor_state
)
833 if (virtual_screen
.cursor_x
> 0)
834 virtual_screen
.cursor_x
--;
838 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
841 virtual_screen
.cursor_y
++;
845 virtual_screen
.cursor_x
= 0;
849 /* Redraw cursor if visible. */
850 if (virtual_screen
.cursor_state
)
855 struct grub_font_glyph
*glyph
;
856 struct grub_colored_char
*p
;
857 unsigned char char_width
;
859 /* Erase current cursor, if any. */
860 if (virtual_screen
.cursor_state
)
863 /* Get properties of the character. */
864 glyph
= grub_font_get_glyph (virtual_screen
.font
, c
);
866 /* Calculate actual character width for glyph. This is number of
867 times of normal_font_width. */
868 char_width
= calculate_character_width(glyph
);
870 /* If we are about to exceed line length, wrap to next line. */
871 if (virtual_screen
.cursor_x
+ char_width
> virtual_screen
.columns
)
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
);
879 p
->fg_color
= virtual_screen
.fg_color
;
880 p
->bg_color
= virtual_screen
.bg_color
;
881 p
->width
= char_width
- 1;
884 /* If we have large glyph, add fixup info. */
889 for (i
= 1; i
< char_width
; i
++)
892 p
[i
].width
= char_width
- 1;
900 /* Make sure we scroll screen when needed and wrap line correctly. */
901 virtual_screen
.cursor_x
+= char_width
;
902 if (virtual_screen
.cursor_x
>= virtual_screen
.columns
)
904 virtual_screen
.cursor_x
= 0;
906 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
909 virtual_screen
.cursor_y
++;
912 /* Draw cursor if visible. */
913 if (virtual_screen
.cursor_state
)
918 /* Use ASCII characters to determine normal character width. */
920 calculate_normal_character_width (grub_font_t font
)
922 struct grub_font_glyph
*glyph
;
923 unsigned int width
= 0;
926 /* Get properties of every printable ASCII character. */
927 for (i
= 32; i
< 127; i
++)
929 glyph
= grub_font_get_glyph (font
, i
);
931 /* Skip unknown characters. Should never happen on normal conditions. */
935 if (glyph
->device_width
> width
)
936 width
= glyph
->device_width
;
943 calculate_character_width (struct grub_font_glyph
*glyph
)
945 if (! glyph
|| glyph
->device_width
== 0)
948 return (glyph
->device_width
949 + (virtual_screen
.normal_char_width
- 1))
950 / virtual_screen
.normal_char_width
;
954 grub_gfxterm_getcharwidth (grub_uint32_t c
)
956 struct grub_font_glyph
*glyph
;
957 unsigned char char_width
;
959 /* Get properties of the character. */
960 glyph
= grub_font_get_glyph (virtual_screen
.font
, c
);
962 /* Calculate actual character width for glyph. */
963 char_width
= calculate_character_width (glyph
);
969 grub_virtual_screen_getwh (void)
971 return (virtual_screen
.columns
<< 8) | virtual_screen
.rows
;
975 grub_virtual_screen_getxy (void)
977 return ((virtual_screen
.cursor_x
<< 8) | virtual_screen
.cursor_y
);
981 grub_gfxterm_gotoxy (grub_uint8_t x
, grub_uint8_t y
)
983 if (x
>= virtual_screen
.columns
)
984 x
= virtual_screen
.columns
- 1;
986 if (y
>= virtual_screen
.rows
)
987 y
= virtual_screen
.rows
- 1;
989 /* Erase current cursor, if any. */
990 if (virtual_screen
.cursor_state
)
993 virtual_screen
.cursor_x
= x
;
994 virtual_screen
.cursor_y
= y
;
996 /* Draw cursor if visible. */
997 if (virtual_screen
.cursor_state
)
1002 grub_virtual_screen_cls (void)
1006 for (i
= 0; i
< virtual_screen
.columns
* virtual_screen
.rows
; i
++)
1008 virtual_screen
.text_buffer
[i
].code
= ' ';
1009 virtual_screen
.text_buffer
[i
].fg_color
= virtual_screen
.fg_color
;
1010 virtual_screen
.text_buffer
[i
].bg_color
= virtual_screen
.bg_color
;
1011 virtual_screen
.text_buffer
[i
].width
= 0;
1012 virtual_screen
.text_buffer
[i
].index
= 0;
1015 virtual_screen
.cursor_x
= virtual_screen
.cursor_y
= 0;
1019 grub_gfxterm_cls (void)
1021 grub_video_color_t color
;
1023 /* Clear virtual screen. */
1024 grub_virtual_screen_cls ();
1026 /* Clear text layer. */
1027 grub_video_set_active_render_target (text_layer
);
1028 color
= virtual_screen
.bg_color
;
1029 grub_video_fill_rect (color
, 0, 0, mode_info
.width
, mode_info
.height
);
1030 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
1032 /* Mark virtual screen to be redrawn. */
1033 dirty_region_add_virtualscreen ();
1037 grub_virtual_screen_setcolorstate (grub_term_color_state state
)
1041 case GRUB_TERM_COLOR_STANDARD
:
1042 virtual_screen
.term_color
= virtual_screen
.standard_color_setting
;
1045 case GRUB_TERM_COLOR_NORMAL
:
1046 virtual_screen
.term_color
= virtual_screen
.normal_color_setting
;
1049 case GRUB_TERM_COLOR_HIGHLIGHT
:
1050 virtual_screen
.term_color
= virtual_screen
.highlight_color_setting
;
1057 /* Change color to virtual terminal. */
1058 set_term_color (virtual_screen
.term_color
);
1062 grub_virtual_screen_setcolor (grub_uint8_t normal_color
,
1063 grub_uint8_t highlight_color
)
1065 virtual_screen
.normal_color_setting
= normal_color
;
1066 virtual_screen
.highlight_color_setting
= highlight_color
;
1070 grub_virtual_screen_getcolor (grub_uint8_t
*normal_color
,
1071 grub_uint8_t
*highlight_color
)
1073 *normal_color
= virtual_screen
.normal_color_setting
;
1074 *highlight_color
= virtual_screen
.highlight_color_setting
;
1078 grub_gfxterm_setcursor (int on
)
1080 if (virtual_screen
.cursor_state
!= on
)
1082 if (virtual_screen
.cursor_state
)
1087 virtual_screen
.cursor_state
= on
;
1092 grub_gfxterm_refresh (void)
1094 /* Redraw only changed regions. */
1095 dirty_region_redraw ();
1099 grub_gfxterm_background_image_cmd (struct grub_arg_list
*state
__attribute__ ((unused
)),
1103 /* Check that we have video adapter active. */
1104 if (grub_video_get_info(NULL
) != GRUB_ERR_NONE
)
1107 /* Destroy existing background bitmap if loaded. */
1110 grub_video_bitmap_destroy (bitmap
);
1113 /* Mark whole screen as dirty. */
1114 dirty_region_reset ();
1115 dirty_region_add (0, 0, mode_info
.width
, mode_info
.height
);
1118 /* If filename was provided, try to load that. */
1121 /* Try to load new one. */
1122 grub_video_bitmap_load (&bitmap
, args
[0]);
1123 if (grub_errno
!= GRUB_ERR_NONE
)
1126 /* If bitmap was loaded correctly, display it. */
1129 /* Determine bitmap dimensions. */
1130 bitmap_width
= grub_video_bitmap_get_width (bitmap
);
1131 bitmap_height
= grub_video_bitmap_get_width (bitmap
);
1133 /* Mark whole screen as dirty. */
1134 dirty_region_reset ();
1135 dirty_region_add (0, 0, mode_info
.width
, mode_info
.height
);
1140 grub_errno
= GRUB_ERR_NONE
;
1144 static struct grub_term_output grub_video_term
=
1147 .init
= grub_gfxterm_init
,
1148 .fini
= grub_gfxterm_fini
,
1149 .putchar
= grub_gfxterm_putchar
,
1150 .getcharwidth
= grub_gfxterm_getcharwidth
,
1151 .getwh
= grub_virtual_screen_getwh
,
1152 .getxy
= grub_virtual_screen_getxy
,
1153 .gotoxy
= grub_gfxterm_gotoxy
,
1154 .cls
= grub_gfxterm_cls
,
1155 .setcolorstate
= grub_virtual_screen_setcolorstate
,
1156 .setcolor
= grub_virtual_screen_setcolor
,
1157 .getcolor
= grub_virtual_screen_getcolor
,
1158 .setcursor
= grub_gfxterm_setcursor
,
1159 .refresh
= grub_gfxterm_refresh
,
1164 GRUB_MOD_INIT(term_gfxterm
)
1167 grub_term_register_output (&grub_video_term
);
1169 grub_register_command ("background_image",
1170 grub_gfxterm_background_image_cmd
,
1171 GRUB_COMMAND_FLAG_BOTH
,
1173 "Load background image for active terminal",
1177 GRUB_MOD_FINI(term_gfxterm
)
1179 grub_unregister_command ("bgimage");
1180 grub_term_unregister_output (&grub_video_term
);