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/font.h>
26 #include <grub/video.h>
27 #include <grub/gfxterm.h>
28 #include <grub/bitmap.h>
29 #include <grub/bitmap_scale.h>
30 #include <grub/extcmd.h>
32 #define DEFAULT_VIDEO_MODE "1024x768,800x600,640x480"
33 #define DEFAULT_BORDER_WIDTH 10
35 #define DEFAULT_STANDARD_COLOR 0x07
36 #define DEFAULT_NORMAL_COLOR 0x07
37 #define DEFAULT_HIGHLIGHT_COLOR 0x70
39 struct grub_dirty_region
47 struct grub_colored_char
49 /* An Unicode codepoint. */
53 grub_video_color_t fg_color
;
54 grub_video_color_t bg_color
;
56 /* The width of this character minus one. */
59 /* The column index of this character. */
63 struct grub_virtual_screen
65 /* Dimensions of the virtual screen in pixels. */
69 /* Offset in the display in pixels. */
70 unsigned int offset_x
;
71 unsigned int offset_y
;
73 /* TTY Character sizes in pixes. */
74 unsigned int normal_char_width
;
75 unsigned int normal_char_height
;
77 /* Virtual screen TTY size in characters. */
81 /* Current cursor location in characters. */
82 unsigned int cursor_x
;
83 unsigned int cursor_y
;
85 /* Current cursor state. */
91 /* Terminal color settings. */
92 grub_uint8_t standard_color_setting
;
93 grub_uint8_t normal_color_setting
;
94 grub_uint8_t highlight_color_setting
;
95 grub_uint8_t term_color
;
98 grub_video_color_t fg_color
;
99 grub_video_color_t bg_color
;
101 /* Text buffer for virtual screen. Contains (columns * rows) number
103 struct grub_colored_char
*text_buffer
;
107 static struct grub_video_render_target
*render_target
;
108 static grub_video_rect_t window
;
109 static struct grub_virtual_screen virtual_screen
;
110 static grub_gfxterm_repaint_callback_t repaint_callback
;
112 static grub_err_t
init_window (struct grub_video_render_target
*target
,
113 int x
, int y
, int width
, int height
,
114 const char *font_name
, int border_width
);
116 static void destroy_window (void);
119 static struct grub_video_render_target
*text_layer
;
121 static unsigned int bitmap_width
;
122 static unsigned int bitmap_height
;
123 static struct grub_video_bitmap
*bitmap
;
125 static struct grub_dirty_region dirty_region
;
127 static void dirty_region_reset (void);
129 static int dirty_region_is_empty (void);
131 static void dirty_region_add (int x
, int y
,
132 unsigned int width
, unsigned int height
);
134 static unsigned int calculate_normal_character_width (grub_font_t font
);
136 static unsigned char calculate_character_width (struct grub_font_glyph
*glyph
);
139 set_term_color (grub_uint8_t term_color
)
141 struct grub_video_render_target
*old_target
;
143 /* Save previous target and switch to text layer. */
144 grub_video_get_active_render_target (&old_target
);
145 grub_video_set_active_render_target (text_layer
);
147 /* Map terminal color to text layer compatible video colors. */
148 virtual_screen
.fg_color
= grub_video_map_color(term_color
& 0x0f);
150 /* Special case: use black as transparent color. */
151 if (((term_color
>> 4) & 0x0f) == 0)
153 virtual_screen
.bg_color
= grub_video_map_rgba(0, 0, 0, 0);
157 virtual_screen
.bg_color
= grub_video_map_color((term_color
>> 4) & 0x0f);
160 /* Restore previous target. */
161 grub_video_set_active_render_target (old_target
);
165 grub_virtual_screen_free (void)
167 /* If virtual screen has been allocated, free it. */
168 if (virtual_screen
.text_buffer
!= 0)
169 grub_free (virtual_screen
.text_buffer
);
171 /* Reset virtual screen data. */
172 grub_memset (&virtual_screen
, 0, sizeof (virtual_screen
));
174 /* Free render targets. */
175 grub_video_delete_render_target (text_layer
);
180 grub_virtual_screen_setup (unsigned int x
, unsigned int y
,
181 unsigned int width
, unsigned int height
,
182 const char *font_name
)
186 /* Free old virtual screen. */
187 grub_virtual_screen_free ();
189 /* Initialize with default data. */
190 virtual_screen
.font
= grub_font_get (font_name
);
191 if (!virtual_screen
.font
)
192 return grub_error (GRUB_ERR_BAD_FONT
,
194 virtual_screen
.width
= width
;
195 virtual_screen
.height
= height
;
196 virtual_screen
.offset_x
= x
;
197 virtual_screen
.offset_y
= y
;
198 virtual_screen
.normal_char_width
=
199 calculate_normal_character_width (virtual_screen
.font
);
200 virtual_screen
.normal_char_height
=
201 grub_font_get_max_char_height (virtual_screen
.font
);
202 virtual_screen
.cursor_x
= 0;
203 virtual_screen
.cursor_y
= 0;
204 virtual_screen
.cursor_state
= 1;
206 /* Calculate size of text buffer. */
207 virtual_screen
.columns
= virtual_screen
.width
/ virtual_screen
.normal_char_width
;
208 virtual_screen
.rows
= virtual_screen
.height
/ virtual_screen
.normal_char_height
;
210 /* Allocate memory for text buffer. */
211 virtual_screen
.text_buffer
=
212 (struct grub_colored_char
*) grub_malloc (virtual_screen
.columns
213 * virtual_screen
.rows
214 * sizeof (*virtual_screen
.text_buffer
));
215 if (grub_errno
!= GRUB_ERR_NONE
)
218 /* Create new render target for text layer. */
219 grub_video_create_render_target (&text_layer
,
220 virtual_screen
.width
,
221 virtual_screen
.height
,
222 GRUB_VIDEO_MODE_TYPE_RGB
223 | GRUB_VIDEO_MODE_TYPE_ALPHA
);
224 if (grub_errno
!= GRUB_ERR_NONE
)
227 /* As we want to have colors compatible with rendering target,
228 we can only have those after mode is initialized. */
229 grub_video_set_active_render_target (text_layer
);
231 virtual_screen
.standard_color_setting
= DEFAULT_STANDARD_COLOR
;
232 virtual_screen
.normal_color_setting
= DEFAULT_NORMAL_COLOR
;
233 virtual_screen
.highlight_color_setting
= DEFAULT_HIGHLIGHT_COLOR
;
235 virtual_screen
.term_color
= virtual_screen
.normal_color_setting
;
237 set_term_color (virtual_screen
.term_color
);
239 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
241 /* Clear out text buffer. */
242 for(i
= 0; i
< virtual_screen
.columns
* virtual_screen
.rows
; i
++)
244 virtual_screen
.text_buffer
[i
].code
= ' ';
245 virtual_screen
.text_buffer
[i
].fg_color
= virtual_screen
.fg_color
;
246 virtual_screen
.text_buffer
[i
].bg_color
= virtual_screen
.bg_color
;
247 virtual_screen
.text_buffer
[i
].width
= 0;
248 virtual_screen
.text_buffer
[i
].index
= 0;
254 static int NESTED_FUNC_ATTR
video_hook (grub_video_adapter_t p
__attribute__ ((unused
)),
255 struct grub_video_mode_info
*info
)
257 return ! (info
->mode_type
& GRUB_VIDEO_MODE_TYPE_PURE_TEXT
);
261 init_window (struct grub_video_render_target
*target
,
262 int x
, int y
, int width
, int height
,
263 const char *font_name
, int border_width
)
265 /* Clean up any prior instance. */
268 /* Create virtual screen. */
269 if (grub_virtual_screen_setup (border_width
, border_width
,
270 width
- 2 * border_width
,
271 height
- 2 * border_width
,
278 /* Set the render target. */
279 render_target
= target
;
281 /* Set window bounds. */
284 window
.width
= width
;
285 window
.height
= height
;
287 /* Mark whole window as dirty. */
288 dirty_region_reset ();
289 dirty_region_add (0, 0, width
, height
);
295 grub_gfxterm_init_window (struct grub_video_render_target
*target
,
296 int x
, int y
, int width
, int height
,
297 const char *font_name
, int border_width
)
300 init_window (target
, x
, y
, width
, height
, font_name
, border_width
);
305 grub_gfxterm_init (void)
307 const char *font_name
;
309 struct grub_video_mode_info mode_info
;
313 /* If gfxterm has already been initialized by calling the init_window
314 function, then leave it alone when it is set as the current terminal. */
316 return GRUB_ERR_NONE
;
318 /* Select the font to use. */
319 font_name
= grub_env_get ("gfxterm_font");
321 font_name
= ""; /* Allow fallback to any font. */
323 /* Parse gfxmode environment variable if set. */
324 modevar
= grub_env_get ("gfxmode");
325 if (! modevar
|| *modevar
== 0)
326 err
= grub_video_set_mode (DEFAULT_VIDEO_MODE
, video_hook
);
329 tmp
= grub_malloc (grub_strlen (modevar
)
330 + sizeof (DEFAULT_VIDEO_MODE
) + 1);
333 grub_sprintf (tmp
, "%s;" DEFAULT_VIDEO_MODE
, modevar
);
334 err
= grub_video_set_mode (tmp
, video_hook
);
341 err
= grub_video_get_info (&mode_info
);
342 /* Figure out what mode we ended up. */
346 /* Make sure screen is black. */
347 grub_video_fill_rect (grub_video_map_rgb (0, 0, 0),
348 0, 0, mode_info
.width
, mode_info
.height
);
351 /* Select the font to use. */
352 font_name
= grub_env_get ("gfxterm_font");
354 font_name
= ""; /* Allow fallback to any font. */
356 /* Leave borders for virtual screen. */
357 if (init_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY
,
358 0, 0, mode_info
.width
, mode_info
.height
,
360 DEFAULT_BORDER_WIDTH
) != GRUB_ERR_NONE
)
362 grub_video_restore ();
370 destroy_window (void)
374 grub_video_bitmap_destroy (bitmap
);
378 repaint_callback
= 0;
379 grub_virtual_screen_free ();
383 grub_gfxterm_destroy_window (void)
390 grub_gfxterm_fini (void)
392 /* Don't destroy an explicitly initialized terminal instance when it is
393 unset as the current terminal. */
397 grub_video_restore ();
400 /* Clear error state. */
401 return (grub_errno
= GRUB_ERR_NONE
);
405 redraw_screen_rect (unsigned int x
, unsigned int y
,
406 unsigned int width
, unsigned int height
)
408 grub_video_color_t color
;
409 grub_video_rect_t saved_view
;
411 grub_video_set_active_render_target (render_target
);
412 /* Save viewport and set it to our window. */
413 grub_video_get_viewport ((unsigned *) &saved_view
.x
,
414 (unsigned *) &saved_view
.y
,
415 (unsigned *) &saved_view
.width
,
416 (unsigned *) &saved_view
.height
);
417 grub_video_set_viewport (window
.x
, window
.y
, window
.width
, window
.height
);
421 /* Render bitmap as background. */
422 grub_video_blit_bitmap (bitmap
, GRUB_VIDEO_BLIT_REPLACE
, x
, y
,
426 /* If bitmap is smaller than requested blit area, use background
428 color
= virtual_screen
.bg_color
;
430 /* Fill right side of the bitmap if needed. */
431 if ((x
+ width
>= bitmap_width
) && (y
< bitmap_height
))
433 int w
= (x
+ width
) - bitmap_width
;
437 if (y
+ height
>= bitmap_height
)
439 h
= bitmap_height
- y
;
442 if (bitmap_width
> tx
)
447 /* Render background layer. */
448 grub_video_fill_rect (color
, tx
, y
, w
, h
);
451 /* Fill bottom side of the bitmap if needed. */
452 if (y
+ height
>= bitmap_height
)
454 int h
= (y
+ height
) - bitmap_height
;
457 if (bitmap_height
> ty
)
462 /* Render background layer. */
463 grub_video_fill_rect (color
, x
, ty
, width
, h
);
466 /* Render text layer as blended. */
467 grub_video_blit_render_target (text_layer
, GRUB_VIDEO_BLIT_BLEND
, x
, y
,
468 x
- virtual_screen
.offset_x
,
469 y
- virtual_screen
.offset_y
,
474 /* Render background layer. */
475 color
= virtual_screen
.bg_color
;
476 grub_video_fill_rect (color
, x
, y
, width
, height
);
478 /* Render text layer as replaced (to get texts background color). */
479 grub_video_blit_render_target (text_layer
, GRUB_VIDEO_BLIT_REPLACE
, x
, y
,
480 x
- virtual_screen
.offset_x
,
481 y
- virtual_screen
.offset_y
,
485 /* Restore saved viewport. */
486 grub_video_set_viewport (saved_view
.x
, saved_view
.y
,
487 saved_view
.width
, saved_view
.height
);
488 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
490 if (repaint_callback
)
491 repaint_callback (x
, y
, width
, height
);
495 dirty_region_reset (void)
497 dirty_region
.top_left_x
= -1;
498 dirty_region
.top_left_y
= -1;
499 dirty_region
.bottom_right_x
= -1;
500 dirty_region
.bottom_right_y
= -1;
504 dirty_region_is_empty (void)
506 if ((dirty_region
.top_left_x
== -1)
507 || (dirty_region
.top_left_y
== -1)
508 || (dirty_region
.bottom_right_x
== -1)
509 || (dirty_region
.bottom_right_y
== -1))
515 dirty_region_add (int x
, int y
, unsigned int width
, unsigned int height
)
517 if ((width
== 0) || (height
== 0))
520 if (dirty_region_is_empty ())
522 dirty_region
.top_left_x
= x
;
523 dirty_region
.top_left_y
= y
;
524 dirty_region
.bottom_right_x
= x
+ width
- 1;
525 dirty_region
.bottom_right_y
= y
+ height
- 1;
529 if (x
< dirty_region
.top_left_x
)
530 dirty_region
.top_left_x
= x
;
531 if (y
< dirty_region
.top_left_y
)
532 dirty_region
.top_left_y
= y
;
533 if ((x
+ (int)width
- 1) > dirty_region
.bottom_right_x
)
534 dirty_region
.bottom_right_x
= x
+ width
- 1;
535 if ((y
+ (int)height
- 1) > dirty_region
.bottom_right_y
)
536 dirty_region
.bottom_right_y
= y
+ height
- 1;
541 dirty_region_add_virtualscreen (void)
543 /* Mark virtual screen as dirty. */
544 dirty_region_add (virtual_screen
.offset_x
, virtual_screen
.offset_y
,
545 virtual_screen
.width
, virtual_screen
.height
);
550 dirty_region_redraw (void)
557 if (dirty_region_is_empty ())
560 x
= dirty_region
.top_left_x
;
561 y
= dirty_region
.top_left_y
;
563 width
= dirty_region
.bottom_right_x
- x
+ 1;
564 height
= dirty_region
.bottom_right_y
- y
+ 1;
566 redraw_screen_rect (x
, y
, width
, height
);
568 dirty_region_reset ();
569 grub_video_swap_buffers ();
575 struct grub_colored_char
*p
;
576 struct grub_font_glyph
*glyph
;
577 grub_video_color_t color
;
578 grub_video_color_t bgcolor
;
585 /* Find out active character. */
586 p
= (virtual_screen
.text_buffer
587 + virtual_screen
.cursor_x
588 + (virtual_screen
.cursor_y
* virtual_screen
.columns
));
592 /* Get glyph for character. */
593 glyph
= grub_font_get_glyph (virtual_screen
.font
, p
->code
);
594 ascent
= grub_font_get_ascent (virtual_screen
.font
);
596 width
= virtual_screen
.normal_char_width
* calculate_character_width(glyph
);
597 height
= virtual_screen
.normal_char_height
;
600 bgcolor
= p
->bg_color
;
602 x
= virtual_screen
.cursor_x
* virtual_screen
.normal_char_width
;
603 y
= virtual_screen
.cursor_y
* virtual_screen
.normal_char_height
;
605 /* Render glyph to text layer. */
606 grub_video_set_active_render_target (text_layer
);
607 grub_video_fill_rect (bgcolor
, x
, y
, width
, height
);
608 grub_font_draw_glyph (glyph
, color
, x
, y
+ ascent
);
609 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
611 /* Mark character to be drawn. */
612 dirty_region_add (virtual_screen
.offset_x
+ x
, virtual_screen
.offset_y
+ y
,
617 draw_cursor (int show
)
627 grub_video_color_t color
;
629 /* Determine cursor properties and position on text layer. */
630 x
= virtual_screen
.cursor_x
* virtual_screen
.normal_char_width
;
631 width
= virtual_screen
.normal_char_width
;
632 color
= virtual_screen
.fg_color
;
633 y
= (virtual_screen
.cursor_y
* virtual_screen
.normal_char_height
634 + grub_font_get_ascent (virtual_screen
.font
));
637 /* Render cursor to text layer. */
638 grub_video_set_active_render_target (text_layer
);
639 grub_video_fill_rect (color
, x
, y
, width
, height
);
640 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
642 /* Mark cursor to be redrawn. */
643 dirty_region_add (virtual_screen
.offset_x
+ x
,
644 virtual_screen
.offset_y
+ y
,
653 grub_video_color_t color
;
655 /* If we don't have background bitmap, remove cursor. */
661 /* Redraw only changed regions. */
662 dirty_region_redraw ();
665 /* Scroll text buffer with one line to up. */
666 grub_memmove (virtual_screen
.text_buffer
,
667 virtual_screen
.text_buffer
+ virtual_screen
.columns
,
668 sizeof (*virtual_screen
.text_buffer
)
669 * virtual_screen
.columns
670 * (virtual_screen
.rows
- 1));
672 /* Clear last line in text buffer. */
673 for (i
= virtual_screen
.columns
* (virtual_screen
.rows
- 1);
674 i
< virtual_screen
.columns
* virtual_screen
.rows
;
677 virtual_screen
.text_buffer
[i
].code
= ' ';
678 virtual_screen
.text_buffer
[i
].fg_color
= virtual_screen
.fg_color
;
679 virtual_screen
.text_buffer
[i
].bg_color
= virtual_screen
.bg_color
;
680 virtual_screen
.text_buffer
[i
].width
= 0;
681 virtual_screen
.text_buffer
[i
].index
= 0;
684 /* Scroll physical screen. */
685 grub_video_set_active_render_target (text_layer
);
686 color
= virtual_screen
.bg_color
;
687 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
);
688 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
690 /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */
693 /* Mark virtual screen to be redrawn. */
694 dirty_region_add_virtualscreen ();
698 grub_video_rect_t saved_view
;
699 grub_video_set_active_render_target (render_target
);
700 /* Save viewport and set it to our window. */
701 grub_video_get_viewport ((unsigned *) &saved_view
.x
,
702 (unsigned *) &saved_view
.y
,
703 (unsigned *) &saved_view
.width
,
704 (unsigned *) &saved_view
.height
);
705 grub_video_set_viewport (window
.x
, window
.y
, window
.width
, window
.height
);
707 /* Clear new border area. */
708 grub_video_fill_rect (color
,
709 virtual_screen
.offset_x
, virtual_screen
.offset_y
,
710 virtual_screen
.width
, virtual_screen
.normal_char_height
);
712 /* Scroll physical screen. */
713 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
);
715 /* Restore saved viewport. */
716 grub_video_set_viewport (saved_view
.x
, saved_view
.y
,
717 saved_view
.width
, saved_view
.height
);
718 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
720 /* Draw cursor if visible. */
721 if (virtual_screen
.cursor_state
)
725 if (repaint_callback
)
726 repaint_callback (window
.x
, window
.y
, window
.width
, window
.height
);
730 grub_gfxterm_putchar (grub_uint32_t c
)
736 /* Erase current cursor, if any. */
737 if (virtual_screen
.cursor_state
)
740 if (c
== '\b' || c
== '\n' || c
== '\r')
745 if (virtual_screen
.cursor_x
> 0)
746 virtual_screen
.cursor_x
--;
750 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
753 virtual_screen
.cursor_y
++;
757 virtual_screen
.cursor_x
= 0;
763 struct grub_font_glyph
*glyph
;
764 struct grub_colored_char
*p
;
765 unsigned char char_width
;
767 /* Get properties of the character. */
768 glyph
= grub_font_get_glyph (virtual_screen
.font
, c
);
770 /* Calculate actual character width for glyph. This is number of
771 times of normal_font_width. */
772 char_width
= calculate_character_width(glyph
);
774 /* If we are about to exceed line length, wrap to next line. */
775 if (virtual_screen
.cursor_x
+ char_width
> virtual_screen
.columns
)
778 /* Find position on virtual screen, and fill information. */
779 p
= (virtual_screen
.text_buffer
+
780 virtual_screen
.cursor_x
+
781 virtual_screen
.cursor_y
* virtual_screen
.columns
);
783 p
->fg_color
= virtual_screen
.fg_color
;
784 p
->bg_color
= virtual_screen
.bg_color
;
785 p
->width
= char_width
- 1;
788 /* If we have large glyph, add fixup info. */
793 for (i
= 1; i
< char_width
; i
++)
796 p
[i
].width
= char_width
- 1;
804 /* Make sure we scroll screen when needed and wrap line correctly. */
805 virtual_screen
.cursor_x
+= char_width
;
806 if (virtual_screen
.cursor_x
>= virtual_screen
.columns
)
808 virtual_screen
.cursor_x
= 0;
810 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
813 virtual_screen
.cursor_y
++;
817 /* Redraw cursor if it should be visible. */
818 /* Note: This will redraw the character as well, which means that the
819 above call to write_char is redundant when the cursor is showing. */
820 if (virtual_screen
.cursor_state
)
824 /* Use ASCII characters to determine normal character width. */
826 calculate_normal_character_width (grub_font_t font
)
828 struct grub_font_glyph
*glyph
;
829 unsigned int width
= 0;
832 /* Get properties of every printable ASCII character. */
833 for (i
= 32; i
< 127; i
++)
835 glyph
= grub_font_get_glyph (font
, i
);
837 /* Skip unknown characters. Should never happen on normal conditions. */
841 if (glyph
->device_width
> width
)
842 width
= glyph
->device_width
;
849 calculate_character_width (struct grub_font_glyph
*glyph
)
851 if (! glyph
|| glyph
->device_width
== 0)
854 return (glyph
->device_width
855 + (virtual_screen
.normal_char_width
- 1))
856 / virtual_screen
.normal_char_width
;
860 grub_gfxterm_getcharwidth (grub_uint32_t c
__attribute__((unused
)))
862 struct grub_font_glyph
*glyph
;
863 unsigned char char_width
;
865 /* Get properties of the character. */
866 glyph
= grub_font_get_glyph (virtual_screen
.font
, c
);
868 /* Calculate actual character width for glyph. */
869 char_width
= calculate_character_width (glyph
);
875 grub_virtual_screen_getwh (void)
877 return (virtual_screen
.columns
<< 8) | virtual_screen
.rows
;
881 grub_virtual_screen_getxy (void)
883 return ((virtual_screen
.cursor_x
<< 8) | virtual_screen
.cursor_y
);
887 grub_gfxterm_gotoxy (grub_uint8_t x
, grub_uint8_t y
)
889 if (x
>= virtual_screen
.columns
)
890 x
= virtual_screen
.columns
- 1;
892 if (y
>= virtual_screen
.rows
)
893 y
= virtual_screen
.rows
- 1;
895 /* Erase current cursor, if any. */
896 if (virtual_screen
.cursor_state
)
899 virtual_screen
.cursor_x
= x
;
900 virtual_screen
.cursor_y
= y
;
902 /* Draw cursor if visible. */
903 if (virtual_screen
.cursor_state
)
908 grub_virtual_screen_cls (void)
912 for (i
= 0; i
< virtual_screen
.columns
* virtual_screen
.rows
; i
++)
914 virtual_screen
.text_buffer
[i
].code
= ' ';
915 virtual_screen
.text_buffer
[i
].fg_color
= virtual_screen
.fg_color
;
916 virtual_screen
.text_buffer
[i
].bg_color
= virtual_screen
.bg_color
;
917 virtual_screen
.text_buffer
[i
].width
= 0;
918 virtual_screen
.text_buffer
[i
].index
= 0;
921 virtual_screen
.cursor_x
= virtual_screen
.cursor_y
= 0;
925 grub_gfxterm_cls (void)
927 grub_video_color_t color
;
929 /* Clear virtual screen. */
930 grub_virtual_screen_cls ();
932 /* Clear text layer. */
933 grub_video_set_active_render_target (text_layer
);
934 color
= virtual_screen
.bg_color
;
935 grub_video_fill_rect (color
, 0, 0,
936 virtual_screen
.width
, virtual_screen
.height
);
937 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
939 /* Mark virtual screen to be redrawn. */
940 dirty_region_add_virtualscreen ();
944 grub_virtual_screen_setcolorstate (grub_term_color_state state
)
948 case GRUB_TERM_COLOR_STANDARD
:
949 virtual_screen
.term_color
= virtual_screen
.standard_color_setting
;
952 case GRUB_TERM_COLOR_NORMAL
:
953 virtual_screen
.term_color
= virtual_screen
.normal_color_setting
;
956 case GRUB_TERM_COLOR_HIGHLIGHT
:
957 virtual_screen
.term_color
= virtual_screen
.highlight_color_setting
;
964 /* Change color to virtual terminal. */
965 set_term_color (virtual_screen
.term_color
);
969 grub_virtual_screen_setcolor (grub_uint8_t normal_color
,
970 grub_uint8_t highlight_color
)
972 virtual_screen
.normal_color_setting
= normal_color
;
973 virtual_screen
.highlight_color_setting
= highlight_color
;
977 grub_virtual_screen_getcolor (grub_uint8_t
*normal_color
,
978 grub_uint8_t
*highlight_color
)
980 *normal_color
= virtual_screen
.normal_color_setting
;
981 *highlight_color
= virtual_screen
.highlight_color_setting
;
985 grub_gfxterm_setcursor (int on
)
987 if (virtual_screen
.cursor_state
!= on
)
989 if (virtual_screen
.cursor_state
)
994 virtual_screen
.cursor_state
= on
;
999 grub_gfxterm_refresh (void)
1001 /* Redraw only changed regions. */
1002 dirty_region_redraw ();
1006 grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func
)
1008 repaint_callback
= func
;
1011 /* Option array indices. */
1012 #define BACKGROUND_CMD_ARGINDEX_MODE 0
1014 static const struct grub_arg_option background_image_cmd_options
[] =
1016 {"mode", 'm', 0, "Background image mode (`stretch', `normal').", 0,
1022 grub_gfxterm_background_image_cmd (grub_extcmd_t cmd
,
1026 struct grub_arg_list
*state
= cmd
->state
;
1028 /* Check that we have video adapter active. */
1029 if (grub_video_get_info(NULL
) != GRUB_ERR_NONE
)
1032 /* Destroy existing background bitmap if loaded. */
1035 grub_video_bitmap_destroy (bitmap
);
1038 /* Mark whole screen as dirty. */
1039 dirty_region_reset ();
1040 dirty_region_add (0, 0, window
.width
, window
.height
);
1043 /* If filename was provided, try to load that. */
1046 /* Try to load new one. */
1047 grub_video_bitmap_load (&bitmap
, args
[0]);
1048 if (grub_errno
!= GRUB_ERR_NONE
)
1051 /* Determine if the bitmap should be scaled to fit the screen. */
1052 if (!state
[BACKGROUND_CMD_ARGINDEX_MODE
].set
1053 || grub_strcmp (state
[BACKGROUND_CMD_ARGINDEX_MODE
].arg
,
1056 if (window
.width
!= (int) grub_video_bitmap_get_width (bitmap
)
1057 || window
.height
!= (int) grub_video_bitmap_get_height (bitmap
))
1059 struct grub_video_bitmap
*scaled_bitmap
;
1060 grub_video_bitmap_create_scaled (&scaled_bitmap
,
1064 GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST
);
1065 if (grub_errno
== GRUB_ERR_NONE
)
1067 /* Replace the original bitmap with the scaled one. */
1068 grub_video_bitmap_destroy (bitmap
);
1069 bitmap
= scaled_bitmap
;
1075 /* If bitmap was loaded correctly, display it. */
1078 /* Determine bitmap dimensions. */
1079 bitmap_width
= grub_video_bitmap_get_width (bitmap
);
1080 bitmap_height
= grub_video_bitmap_get_height (bitmap
);
1082 /* Mark whole screen as dirty. */
1083 dirty_region_reset ();
1084 dirty_region_add (0, 0, window
.width
, window
.height
);
1089 grub_errno
= GRUB_ERR_NONE
;
1093 static struct grub_term_output grub_video_term
=
1096 .init
= grub_gfxterm_init
,
1097 .fini
= grub_gfxterm_fini
,
1098 .putchar
= grub_gfxterm_putchar
,
1099 .getcharwidth
= grub_gfxterm_getcharwidth
,
1100 .getwh
= grub_virtual_screen_getwh
,
1101 .getxy
= grub_virtual_screen_getxy
,
1102 .gotoxy
= grub_gfxterm_gotoxy
,
1103 .cls
= grub_gfxterm_cls
,
1104 .setcolorstate
= grub_virtual_screen_setcolorstate
,
1105 .setcolor
= grub_virtual_screen_setcolor
,
1106 .getcolor
= grub_virtual_screen_getcolor
,
1107 .setcursor
= grub_gfxterm_setcursor
,
1108 .refresh
= grub_gfxterm_refresh
,
1114 grub_gfxterm_get_term (void)
1116 return &grub_video_term
;
1119 static grub_extcmd_t background_image_cmd_handle
;
1121 GRUB_MOD_INIT(term_gfxterm
)
1125 grub_term_register_output ("gfxterm", &grub_video_term
);
1126 background_image_cmd_handle
=
1127 grub_register_extcmd ("background_image",
1128 grub_gfxterm_background_image_cmd
,
1129 GRUB_COMMAND_FLAG_BOTH
,
1130 "background_image [-m (stretch|normal)] FILE",
1131 "Load background image for active terminal.",
1132 background_image_cmd_options
);
1135 GRUB_MOD_FINI(term_gfxterm
)
1137 grub_unregister_extcmd (background_image_cmd_handle
);
1138 grub_term_unregister_output (&grub_video_term
);