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/command.h>
30 #include <grub/extcmd.h>
31 #include <grub/i18n.h>
33 GRUB_MOD_LICENSE ("GPLv3+");
35 #define DEFAULT_VIDEO_MODE "auto"
36 #define DEFAULT_BORDER_WIDTH 10
38 #define DEFAULT_STANDARD_COLOR 0x07
40 struct grub_dirty_region
48 struct grub_colored_char
50 /* An Unicode codepoint. */
51 struct grub_unicode_glyph code
;
54 grub_video_color_t fg_color
;
55 grub_video_color_t bg_color
;
58 struct grub_virtual_screen
60 /* Dimensions of the virtual screen in pixels. */
64 /* Offset in the display in pixels. */
65 unsigned int offset_x
;
66 unsigned int offset_y
;
68 /* TTY Character sizes in pixes. */
69 unsigned int normal_char_width
;
70 unsigned int normal_char_height
;
72 /* Virtual screen TTY size in characters. */
76 /* Current cursor location in characters. */
77 unsigned int cursor_x
;
78 unsigned int cursor_y
;
80 /* Current cursor state. */
86 /* Terminal color settings. */
87 grub_uint8_t standard_color_setting
;
88 grub_uint8_t term_color
;
91 grub_video_color_t fg_color
;
92 grub_video_color_t bg_color
;
93 grub_video_color_t bg_color_display
;
95 /* Text buffer for virtual screen. Contains (columns * rows) number
97 struct grub_colored_char
*text_buffer
;
104 struct grub_gfxterm_window
113 static struct grub_video_render_target
*render_target
;
114 void (*grub_gfxterm_decorator_hook
) (void) = NULL
;
115 static struct grub_gfxterm_window window
;
116 static struct grub_virtual_screen virtual_screen
;
117 static int repaint_scheduled
= 0;
118 static int repaint_was_scheduled
= 0;
120 static void destroy_window (void);
122 static struct grub_video_render_target
*text_layer
;
124 struct grub_gfxterm_background grub_gfxterm_background
;
126 static struct grub_dirty_region dirty_region
;
128 static void dirty_region_reset (void);
130 static int dirty_region_is_empty (void);
132 static void dirty_region_add (int x
, int y
,
133 unsigned int width
, unsigned int height
);
135 static unsigned int calculate_normal_character_width (grub_font_t font
);
137 static unsigned char calculate_character_width (struct grub_font_glyph
*glyph
);
139 static void grub_gfxterm_refresh (struct grub_term_output
*term
__attribute__ ((unused
)));
142 grub_gfxterm_getcharwidth (struct grub_term_output
*term
__attribute__ ((unused
)),
143 const struct grub_unicode_glyph
*c
);
146 set_term_color (grub_uint8_t term_color
)
148 struct grub_video_render_target
*old_target
;
150 /* Save previous target and switch to text layer. */
151 grub_video_get_active_render_target (&old_target
);
152 grub_video_set_active_render_target (text_layer
);
154 /* Map terminal color to text layer compatible video colors. */
155 virtual_screen
.fg_color
= grub_video_map_color(term_color
& 0x0f);
157 /* Special case: use black as transparent color. */
158 if (((term_color
>> 4) & 0x0f) == 0)
160 virtual_screen
.bg_color
= grub_video_map_rgba(0, 0, 0, 0);
164 virtual_screen
.bg_color
= grub_video_map_color((term_color
>> 4) & 0x0f);
167 /* Restore previous target. */
168 grub_video_set_active_render_target (old_target
);
172 clear_char (struct grub_colored_char
*c
)
174 grub_unicode_destroy_glyph (&c
->code
);
175 grub_unicode_set_glyph_from_code (&c
->code
, ' ');
176 c
->fg_color
= virtual_screen
.fg_color
;
177 c
->bg_color
= virtual_screen
.bg_color
;
181 grub_virtual_screen_free (void)
183 virtual_screen
.functional
= 0;
185 /* If virtual screen has been allocated, free it. */
186 if (virtual_screen
.text_buffer
!= 0)
190 i
< virtual_screen
.columns
* virtual_screen
.rows
;
192 grub_unicode_destroy_glyph (&virtual_screen
.text_buffer
[i
].code
);
193 grub_free (virtual_screen
.text_buffer
);
196 /* Reset virtual screen data. */
197 grub_memset (&virtual_screen
, 0, sizeof (virtual_screen
));
199 /* Free render targets. */
200 grub_video_delete_render_target (text_layer
);
205 grub_virtual_screen_setup (unsigned int x
, unsigned int y
,
206 unsigned int width
, unsigned int height
,
211 /* Free old virtual screen. */
212 grub_virtual_screen_free ();
214 /* Initialize with default data. */
215 virtual_screen
.font
= font
;
216 virtual_screen
.width
= width
;
217 virtual_screen
.height
= height
;
218 virtual_screen
.offset_x
= x
;
219 virtual_screen
.offset_y
= y
;
220 virtual_screen
.normal_char_width
=
221 calculate_normal_character_width (virtual_screen
.font
);
222 virtual_screen
.normal_char_height
=
223 grub_font_get_max_char_height (virtual_screen
.font
);
224 if (virtual_screen
.normal_char_height
== 0)
225 virtual_screen
.normal_char_height
= 16;
226 virtual_screen
.cursor_x
= 0;
227 virtual_screen
.cursor_y
= 0;
228 virtual_screen
.cursor_state
= 1;
229 virtual_screen
.total_scroll
= 0;
231 /* Calculate size of text buffer. */
232 virtual_screen
.columns
= virtual_screen
.width
/ virtual_screen
.normal_char_width
;
233 virtual_screen
.rows
= virtual_screen
.height
/ virtual_screen
.normal_char_height
;
236 * There must be a minimum number of rows and columns for the screen to
237 * make sense. Arbitrarily pick half of 80x24. If either dimensions is 0
238 * we would allocate 0 bytes for the text_buffer.
240 if (virtual_screen
.columns
< 40 || virtual_screen
.rows
< 12)
241 return grub_error (GRUB_ERR_BAD_FONT
,
242 "font: glyphs too large to fit on screen");
244 /* Allocate memory for text buffer. */
245 virtual_screen
.text_buffer
=
246 (struct grub_colored_char
*) grub_malloc (virtual_screen
.columns
247 * virtual_screen
.rows
248 * sizeof (*virtual_screen
.text_buffer
));
249 if (grub_errno
!= GRUB_ERR_NONE
)
252 /* Create new render target for text layer. */
253 grub_video_create_render_target (&text_layer
,
254 virtual_screen
.width
,
255 virtual_screen
.height
,
256 GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
257 | GRUB_VIDEO_MODE_TYPE_ALPHA
);
258 if (grub_errno
!= GRUB_ERR_NONE
)
261 /* As we want to have colors compatible with rendering target,
262 we can only have those after mode is initialized. */
263 grub_video_set_active_render_target (text_layer
);
265 virtual_screen
.standard_color_setting
= DEFAULT_STANDARD_COLOR
;
267 virtual_screen
.term_color
= virtual_screen
.standard_color_setting
;
269 set_term_color (virtual_screen
.term_color
);
271 grub_video_set_active_render_target (render_target
);
273 virtual_screen
.bg_color_display
=
274 grub_video_map_rgba_color (grub_gfxterm_background
.default_bg_color
);
276 /* Clear out text buffer. */
277 for (i
= 0; i
< virtual_screen
.columns
* virtual_screen
.rows
; i
++)
279 virtual_screen
.text_buffer
[i
].code
.ncomb
= 0;
280 clear_char (&(virtual_screen
.text_buffer
[i
]));
285 virtual_screen
.functional
= 1;
287 return GRUB_ERR_NONE
;
291 grub_gfxterm_schedule_repaint (void)
293 repaint_scheduled
= 1;
297 grub_gfxterm_set_window (struct grub_video_render_target
*target
,
298 int x
, int y
, int width
, int height
,
300 grub_font_t font
, int border_width
)
302 /* Clean up any prior instance. */
305 /* Set the render target. */
306 render_target
= target
;
308 /* Create virtual screen. */
309 if (grub_virtual_screen_setup (border_width
, border_width
,
310 width
- 2 * border_width
,
311 height
- 2 * border_width
,
318 /* Set window bounds. */
321 window
.width
= width
;
322 window
.height
= height
;
323 window
.double_repaint
= double_repaint
;
325 dirty_region_reset ();
326 grub_gfxterm_schedule_repaint ();
332 grub_gfxterm_fullscreen (void)
334 const char *font_name
;
335 struct grub_video_mode_info mode_info
;
336 grub_video_color_t color
;
341 err
= grub_video_get_info (&mode_info
);
342 /* Figure out what mode we ended up. */
346 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
348 double_redraw
= mode_info
.mode_type
& GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
349 && !(mode_info
.mode_type
& GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
);
351 /* Make sure screen is set to the default background color. */
352 color
= grub_video_map_rgba_color (grub_gfxterm_background
.default_bg_color
);
353 grub_video_fill_rect (color
, 0, 0, mode_info
.width
, mode_info
.height
);
356 grub_video_swap_buffers ();
357 grub_video_fill_rect (color
, 0, 0, mode_info
.width
, mode_info
.height
);
360 /* Select the font to use. */
361 font_name
= grub_env_get ("gfxterm_font");
363 font_name
= ""; /* Allow fallback to any font. */
365 font
= grub_font_get (font_name
);
367 return grub_error (GRUB_ERR_BAD_FONT
, "no font loaded");
369 grub_gfxterm_decorator_hook
= NULL
;
371 return grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY
,
372 0, 0, mode_info
.width
, mode_info
.height
,
374 font
, DEFAULT_BORDER_WIDTH
);
378 grub_gfxterm_term_init (struct grub_term_output
*term
__attribute__ ((unused
)))
384 /* Parse gfxmode environment variable if set. */
385 modevar
= grub_env_get ("gfxmode");
386 if (! modevar
|| *modevar
== 0)
387 err
= grub_video_set_mode (DEFAULT_VIDEO_MODE
,
388 GRUB_VIDEO_MODE_TYPE_PURE_TEXT
, 0);
391 tmp
= grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE
, modevar
);
394 err
= grub_video_set_mode (tmp
, GRUB_VIDEO_MODE_TYPE_PURE_TEXT
, 0);
401 err
= grub_gfxterm_fullscreen ();
403 grub_video_restore ();
409 destroy_window (void)
411 grub_virtual_screen_free ();
415 grub_gfxterm_term_fini (struct grub_term_output
*term
__attribute__ ((unused
)))
419 grub_video_restore ();
421 for (i
= 0; i
< virtual_screen
.columns
* virtual_screen
.rows
; i
++)
423 grub_unicode_destroy_glyph (&virtual_screen
.text_buffer
[i
].code
);
424 virtual_screen
.text_buffer
[i
].code
.ncomb
= 0;
425 virtual_screen
.text_buffer
[i
].code
.base
= 0;
428 /* Clear error state. */
429 grub_errno
= GRUB_ERR_NONE
;
430 return GRUB_ERR_NONE
;
434 redraw_screen_rect (unsigned int x
, unsigned int y
,
435 unsigned int width
, unsigned int height
)
437 grub_video_color_t color
;
438 grub_video_rect_t saved_view
;
440 grub_video_set_active_render_target (render_target
);
441 /* Save viewport and set it to our window. */
442 grub_video_get_viewport ((unsigned *) &saved_view
.x
,
443 (unsigned *) &saved_view
.y
,
444 (unsigned *) &saved_view
.width
,
445 (unsigned *) &saved_view
.height
);
446 grub_video_set_viewport (window
.x
, window
.y
, window
.width
, window
.height
);
448 if (grub_gfxterm_background
.bitmap
)
450 /* Render bitmap as background. */
451 grub_video_blit_bitmap (grub_gfxterm_background
.bitmap
,
452 GRUB_VIDEO_BLIT_REPLACE
, x
, y
,
456 /* If bitmap is smaller than requested blit area, use background
458 color
= virtual_screen
.bg_color_display
;
460 /* Fill right side of the bitmap if needed. */
461 if ((x
+ width
>= grub_gfxterm_background
.bitmap
->mode_info
.width
)
462 && (y
< grub_gfxterm_background
.bitmap
->mode_info
.height
))
464 int w
= (x
+ width
) - grub_gfxterm_background
.bitmap
->mode_info
.width
;
468 if (y
+ height
>= grub_gfxterm_background
.bitmap
->mode_info
.height
)
470 h
= grub_gfxterm_background
.bitmap
->mode_info
.height
- y
;
473 if (grub_gfxterm_background
.bitmap
->mode_info
.width
> tx
)
475 tx
= grub_gfxterm_background
.bitmap
->mode_info
.width
;
478 /* Render background layer. */
479 grub_video_fill_rect (color
, tx
, y
, w
, h
);
482 /* Fill bottom side of the bitmap if needed. */
483 if (y
+ height
>= grub_gfxterm_background
.bitmap
->mode_info
.height
)
485 int h
= (y
+ height
) - grub_gfxterm_background
.bitmap
->mode_info
.height
;
488 if (grub_gfxterm_background
.bitmap
->mode_info
.height
> ty
)
490 ty
= grub_gfxterm_background
.bitmap
->mode_info
.height
;
493 /* Render background layer. */
494 grub_video_fill_rect (color
, x
, ty
, width
, h
);
499 /* Render background layer. */
500 color
= virtual_screen
.bg_color_display
;
501 grub_video_fill_rect (color
, x
, y
, width
, height
);
504 if (grub_gfxterm_background
.blend_text_bg
)
505 /* Render text layer as blended. */
506 grub_video_blit_render_target (text_layer
, GRUB_VIDEO_BLIT_BLEND
, x
, y
,
507 x
- virtual_screen
.offset_x
,
508 y
- virtual_screen
.offset_y
,
511 /* Render text layer as replaced (to get texts background color). */
512 grub_video_blit_render_target (text_layer
, GRUB_VIDEO_BLIT_REPLACE
, x
, y
,
513 x
- virtual_screen
.offset_x
,
514 y
- virtual_screen
.offset_y
,
517 /* Restore saved viewport. */
518 grub_video_set_viewport (saved_view
.x
, saved_view
.y
,
519 saved_view
.width
, saved_view
.height
);
520 grub_video_set_active_render_target (render_target
);
524 dirty_region_reset (void)
526 dirty_region
.top_left_x
= -1;
527 dirty_region
.top_left_y
= -1;
528 dirty_region
.bottom_right_x
= -1;
529 dirty_region
.bottom_right_y
= -1;
530 repaint_was_scheduled
= 0;
534 dirty_region_is_empty (void)
536 if ((dirty_region
.top_left_x
== -1)
537 || (dirty_region
.top_left_y
== -1)
538 || (dirty_region
.bottom_right_x
== -1)
539 || (dirty_region
.bottom_right_y
== -1))
545 dirty_region_add_real (int x
, int y
, unsigned int width
, unsigned int height
)
547 if (dirty_region_is_empty ())
549 dirty_region
.top_left_x
= x
;
550 dirty_region
.top_left_y
= y
;
551 dirty_region
.bottom_right_x
= x
+ width
- 1;
552 dirty_region
.bottom_right_y
= y
+ height
- 1;
556 if (x
< dirty_region
.top_left_x
)
557 dirty_region
.top_left_x
= x
;
558 if (y
< dirty_region
.top_left_y
)
559 dirty_region
.top_left_y
= y
;
560 if ((x
+ (int)width
- 1) > dirty_region
.bottom_right_x
)
561 dirty_region
.bottom_right_x
= x
+ width
- 1;
562 if ((y
+ (int)height
- 1) > dirty_region
.bottom_right_y
)
563 dirty_region
.bottom_right_y
= y
+ height
- 1;
568 dirty_region_add (int x
, int y
, unsigned int width
, unsigned int height
)
570 if ((width
== 0) || (height
== 0))
573 if (repaint_scheduled
)
575 dirty_region_add_real (0, 0,
576 window
.width
, window
.height
);
577 repaint_scheduled
= 0;
578 repaint_was_scheduled
= 1;
580 dirty_region_add_real (x
, y
, width
, height
);
584 dirty_region_add_virtualscreen (void)
586 /* Mark virtual screen as dirty. */
587 dirty_region_add (virtual_screen
.offset_x
, virtual_screen
.offset_y
,
588 virtual_screen
.width
, virtual_screen
.height
);
593 dirty_region_redraw (void)
600 if (dirty_region_is_empty ())
603 x
= dirty_region
.top_left_x
;
604 y
= dirty_region
.top_left_y
;
606 width
= dirty_region
.bottom_right_x
- x
+ 1;
607 height
= dirty_region
.bottom_right_y
- y
+ 1;
609 if (repaint_was_scheduled
&& grub_gfxterm_decorator_hook
)
610 grub_gfxterm_decorator_hook ();
612 redraw_screen_rect (x
, y
, width
, height
);
616 paint_char (unsigned cx
, unsigned cy
)
618 struct grub_colored_char
*p
;
619 struct grub_font_glyph
*glyph
;
620 grub_video_color_t color
;
621 grub_video_color_t bgcolor
;
628 if (cy
+ virtual_screen
.total_scroll
>= virtual_screen
.rows
)
631 /* Find out active character. */
632 p
= (virtual_screen
.text_buffer
633 + cx
+ (cy
* virtual_screen
.columns
));
638 /* Get glyph for character. */
639 glyph
= grub_font_construct_glyph (virtual_screen
.font
, &p
->code
);
642 grub_errno
= GRUB_ERR_NONE
;
645 ascent
= grub_font_get_ascent (virtual_screen
.font
);
647 width
= virtual_screen
.normal_char_width
* calculate_character_width(glyph
);
648 height
= virtual_screen
.normal_char_height
;
651 bgcolor
= p
->bg_color
;
653 x
= cx
* virtual_screen
.normal_char_width
;
654 y
= (cy
+ virtual_screen
.total_scroll
) * virtual_screen
.normal_char_height
;
656 /* Render glyph to text layer. */
657 grub_video_set_active_render_target (text_layer
);
658 grub_video_fill_rect (bgcolor
, x
, y
, width
, height
);
659 grub_font_draw_glyph (glyph
, color
, x
, y
+ ascent
);
660 grub_video_set_active_render_target (render_target
);
662 /* Mark character to be drawn. */
663 dirty_region_add (virtual_screen
.offset_x
+ x
, virtual_screen
.offset_y
+ y
,
670 paint_char (virtual_screen
.cursor_x
, virtual_screen
.cursor_y
);
674 draw_cursor (int show
)
681 grub_video_color_t color
;
688 if (virtual_screen
.cursor_y
+ virtual_screen
.total_scroll
689 >= virtual_screen
.rows
)
692 /* Ensure that cursor doesn't go outside of character box. */
693 ascent
= grub_font_get_ascent(virtual_screen
.font
);
694 if (ascent
> virtual_screen
.normal_char_height
- 2)
695 ascent
= virtual_screen
.normal_char_height
- 2;
697 /* Determine cursor properties and position on text layer. */
698 x
= virtual_screen
.cursor_x
* virtual_screen
.normal_char_width
;
699 width
= virtual_screen
.normal_char_width
;
700 color
= virtual_screen
.fg_color
;
701 y
= ((virtual_screen
.cursor_y
+ virtual_screen
.total_scroll
)
702 * virtual_screen
.normal_char_height
706 /* Render cursor to text layer. */
707 grub_video_set_active_render_target (text_layer
);
708 grub_video_fill_rect (color
, x
, y
, width
, height
);
709 grub_video_set_active_render_target (render_target
);
711 /* Mark cursor to be redrawn. */
712 dirty_region_add (virtual_screen
.offset_x
+ x
,
713 virtual_screen
.offset_y
+ y
,
720 unsigned int i
, j
, was_scroll
;
721 grub_video_color_t color
;
723 if (!virtual_screen
.total_scroll
)
726 /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */
727 if (grub_gfxterm_background
.bitmap
)
729 /* Scroll physical screen. */
730 grub_video_set_active_render_target (text_layer
);
731 color
= virtual_screen
.bg_color
;
732 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
733 * virtual_screen
.total_scroll
);
735 /* Mark virtual screen to be redrawn. */
736 dirty_region_add_virtualscreen ();
740 grub_video_rect_t saved_view
;
745 grub_video_set_active_render_target (render_target
);
747 i
= window
.double_repaint
? 2 : 1;
749 color
= virtual_screen
.bg_color_display
;
753 /* Save viewport and set it to our window. */
754 grub_video_get_viewport ((unsigned *) &saved_view
.x
,
755 (unsigned *) &saved_view
.y
,
756 (unsigned *) &saved_view
.width
,
757 (unsigned *) &saved_view
.height
);
759 grub_video_set_viewport (window
.x
, window
.y
, window
.width
,
762 /* Clear new border area. */
763 grub_video_fill_rect (color
,
764 virtual_screen
.offset_x
,
765 virtual_screen
.offset_y
,
766 virtual_screen
.width
,
767 virtual_screen
.normal_char_height
768 * virtual_screen
.total_scroll
);
770 grub_video_set_active_render_target (render_target
);
771 dirty_region_redraw ();
773 /* Scroll physical screen. */
774 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
775 * virtual_screen
.total_scroll
);
777 /* Restore saved viewport. */
778 grub_video_set_viewport (saved_view
.x
, saved_view
.y
,
779 saved_view
.width
, saved_view
.height
);
782 grub_video_swap_buffers ();
784 dirty_region_reset ();
786 /* Scroll physical screen. */
787 grub_video_set_active_render_target (text_layer
);
788 color
= virtual_screen
.bg_color
;
789 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
790 * virtual_screen
.total_scroll
);
792 grub_video_set_active_render_target (render_target
);
796 was_scroll
= virtual_screen
.total_scroll
;
797 virtual_screen
.total_scroll
= 0;
799 if (was_scroll
> virtual_screen
.rows
)
800 was_scroll
= virtual_screen
.rows
;
802 /* Draw shadow part. */
803 for (i
= virtual_screen
.rows
- was_scroll
;
804 i
< virtual_screen
.rows
; i
++)
805 for (j
= 0; j
< virtual_screen
.columns
; j
++)
808 /* Draw cursor if visible. */
809 if (virtual_screen
.cursor_state
)
818 /* Clear first line in text buffer. */
819 for (i
= 0; i
< virtual_screen
.columns
; i
++)
820 grub_unicode_destroy_glyph (&virtual_screen
.text_buffer
[i
].code
);
822 /* Scroll text buffer with one line to up. */
823 grub_memmove (virtual_screen
.text_buffer
,
824 virtual_screen
.text_buffer
+ virtual_screen
.columns
,
825 sizeof (*virtual_screen
.text_buffer
)
826 * virtual_screen
.columns
827 * (virtual_screen
.rows
- 1));
829 /* Clear last line in text buffer. */
830 for (i
= virtual_screen
.columns
* (virtual_screen
.rows
- 1);
831 i
< virtual_screen
.columns
* virtual_screen
.rows
;
833 clear_char (&(virtual_screen
.text_buffer
[i
]));
835 virtual_screen
.total_scroll
++;
839 grub_gfxterm_putchar (struct grub_term_output
*term
,
840 const struct grub_unicode_glyph
*c
)
842 if (!virtual_screen
.functional
)
849 /* Erase current cursor, if any. */
850 if (virtual_screen
.cursor_state
)
853 if (c
->base
== '\b' || c
->base
== '\n' || c
->base
== '\r')
858 if (virtual_screen
.cursor_x
> 0)
859 virtual_screen
.cursor_x
--;
863 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
866 virtual_screen
.cursor_y
++;
870 virtual_screen
.cursor_x
= 0;
876 struct grub_colored_char
*p
;
877 unsigned char char_width
;
879 /* Calculate actual character width for glyph. This is number of
880 times of normal_font_width. */
881 char_width
= grub_gfxterm_getcharwidth (term
, c
);
883 /* If we are about to exceed line length, wrap to next line. */
884 if (virtual_screen
.cursor_x
+ char_width
> virtual_screen
.columns
)
886 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
889 virtual_screen
.cursor_y
++;
892 /* Find position on virtual screen, and fill information. */
893 p
= (virtual_screen
.text_buffer
+
894 virtual_screen
.cursor_x
+
895 virtual_screen
.cursor_y
* virtual_screen
.columns
);
896 grub_unicode_destroy_glyph (&p
->code
);
897 grub_unicode_set_glyph (&p
->code
, c
);
898 grub_errno
= GRUB_ERR_NONE
;
899 p
->fg_color
= virtual_screen
.fg_color
;
900 p
->bg_color
= virtual_screen
.bg_color
;
902 /* If we have large glyph, add fixup info. */
907 for (i
= 1; i
< char_width
&& p
+ i
<
908 virtual_screen
.text_buffer
+ virtual_screen
.columns
909 * virtual_screen
.rows
; i
++)
911 grub_unicode_destroy_glyph (&p
[i
].code
);
919 /* Make sure we scroll screen when needed and wrap line correctly. */
920 virtual_screen
.cursor_x
+= char_width
;
921 if (virtual_screen
.cursor_x
>= virtual_screen
.columns
)
923 virtual_screen
.cursor_x
= 0;
925 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
928 virtual_screen
.cursor_y
++;
932 /* Redraw cursor if it should be visible. */
933 /* Note: This will redraw the character as well, which means that the
934 above call to write_char is redundant when the cursor is showing. */
935 if (virtual_screen
.cursor_state
)
939 /* Use ASCII characters to determine normal character width. */
941 calculate_normal_character_width (grub_font_t font
)
943 struct grub_font_glyph
*glyph
;
944 unsigned int width
= 0;
947 /* Get properties of every printable ASCII character. */
948 for (i
= 32; i
< 127; i
++)
950 glyph
= grub_font_get_glyph (font
, i
);
952 /* Skip unknown characters. Should never happen on normal conditions. */
956 if (glyph
->device_width
> width
)
957 width
= glyph
->device_width
;
966 calculate_character_width (struct grub_font_glyph
*glyph
)
968 if (! glyph
|| glyph
->device_width
== 0)
971 return (glyph
->device_width
972 + (virtual_screen
.normal_char_width
- 1))
973 / virtual_screen
.normal_char_width
;
977 grub_gfxterm_getcharwidth (struct grub_term_output
*term
__attribute__ ((unused
)),
978 const struct grub_unicode_glyph
*c
)
981 dev_width
= grub_font_get_constructed_device_width (virtual_screen
.font
, c
);
986 return (dev_width
+ (virtual_screen
.normal_char_width
- 1))
987 / virtual_screen
.normal_char_width
;
990 static struct grub_term_coordinate
991 grub_virtual_screen_getwh (struct grub_term_output
*term
__attribute__ ((unused
)))
993 return (struct grub_term_coordinate
) { virtual_screen
.columns
, virtual_screen
.rows
};
996 static struct grub_term_coordinate
997 grub_virtual_screen_getxy (struct grub_term_output
*term
__attribute__ ((unused
)))
999 return (struct grub_term_coordinate
) { virtual_screen
.cursor_x
, virtual_screen
.cursor_y
};
1003 grub_gfxterm_gotoxy (struct grub_term_output
*term
__attribute__ ((unused
)),
1004 struct grub_term_coordinate pos
)
1006 if (pos
.x
>= virtual_screen
.columns
)
1007 pos
.x
= virtual_screen
.columns
- 1;
1009 if (pos
.y
>= virtual_screen
.rows
)
1010 pos
.y
= virtual_screen
.rows
- 1;
1012 /* Erase current cursor, if any. */
1013 if (virtual_screen
.cursor_state
)
1016 virtual_screen
.cursor_x
= pos
.x
;
1017 virtual_screen
.cursor_y
= pos
.y
;
1019 /* Draw cursor if visible. */
1020 if (virtual_screen
.cursor_state
)
1025 grub_virtual_screen_cls (struct grub_term_output
*term
__attribute__ ((unused
)))
1029 for (i
= 0; i
< virtual_screen
.columns
* virtual_screen
.rows
; i
++)
1030 clear_char (&(virtual_screen
.text_buffer
[i
]));
1032 virtual_screen
.cursor_x
= virtual_screen
.cursor_y
= 0;
1036 grub_gfxterm_cls (struct grub_term_output
*term
)
1038 grub_video_color_t color
;
1040 /* Clear virtual screen. */
1041 grub_virtual_screen_cls (term
);
1043 /* Clear text layer. */
1044 grub_video_set_active_render_target (text_layer
);
1045 color
= virtual_screen
.bg_color
;
1046 grub_video_fill_rect (color
, 0, 0,
1047 virtual_screen
.width
, virtual_screen
.height
);
1048 grub_video_set_active_render_target (render_target
);
1050 /* Mark virtual screen to be redrawn. */
1051 dirty_region_add_virtualscreen ();
1053 grub_gfxterm_refresh (term
);
1057 grub_virtual_screen_setcolorstate (struct grub_term_output
*term
__attribute__ ((unused
)),
1058 grub_term_color_state state
)
1062 case GRUB_TERM_COLOR_STANDARD
:
1063 virtual_screen
.term_color
= virtual_screen
.standard_color_setting
;
1066 case GRUB_TERM_COLOR_NORMAL
:
1067 virtual_screen
.term_color
= grub_term_normal_color
;
1070 case GRUB_TERM_COLOR_HIGHLIGHT
:
1071 virtual_screen
.term_color
= grub_term_highlight_color
;
1078 /* Change color to virtual terminal. */
1079 set_term_color (virtual_screen
.term_color
);
1083 grub_gfxterm_setcursor (struct grub_term_output
*term
__attribute__ ((unused
)),
1086 if (virtual_screen
.cursor_state
!= on
)
1088 if (virtual_screen
.cursor_state
)
1093 virtual_screen
.cursor_state
= on
;
1098 grub_gfxterm_refresh (struct grub_term_output
*term
__attribute__ ((unused
)))
1102 /* Redraw only changed regions. */
1103 dirty_region_redraw ();
1105 grub_video_swap_buffers ();
1107 if (window
.double_repaint
)
1108 dirty_region_redraw ();
1109 dirty_region_reset ();
1112 static struct grub_term_output grub_video_term
=
1115 .init
= grub_gfxterm_term_init
,
1116 .fini
= grub_gfxterm_term_fini
,
1117 .putchar
= grub_gfxterm_putchar
,
1118 .getcharwidth
= grub_gfxterm_getcharwidth
,
1119 .getwh
= grub_virtual_screen_getwh
,
1120 .getxy
= grub_virtual_screen_getxy
,
1121 .gotoxy
= grub_gfxterm_gotoxy
,
1122 .cls
= grub_gfxterm_cls
,
1123 .setcolorstate
= grub_virtual_screen_setcolorstate
,
1124 .setcursor
= grub_gfxterm_setcursor
,
1125 .refresh
= grub_gfxterm_refresh
,
1126 .fullscreen
= grub_gfxterm_fullscreen
,
1127 .flags
= GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS
,
1128 .progress_update_divisor
= GRUB_PROGRESS_SLOW
,
1133 grub_gfxterm_video_update_color (void)
1135 struct grub_video_render_target
*old_target
;
1137 grub_video_get_active_render_target (&old_target
);
1138 grub_video_set_active_render_target (text_layer
);
1139 virtual_screen
.bg_color
= grub_video_map_rgba_color (grub_gfxterm_background
.default_bg_color
);
1140 grub_video_set_active_render_target (old_target
);
1141 virtual_screen
.bg_color_display
=
1142 grub_video_map_rgba_color (grub_gfxterm_background
.default_bg_color
);
1146 grub_gfxterm_get_dimensions (unsigned *width
, unsigned *height
)
1148 *width
= window
.width
;
1149 *height
= window
.height
;
1152 GRUB_MOD_INIT(gfxterm
)
1154 grub_term_register_output ("gfxterm", &grub_video_term
);
1157 GRUB_MOD_FINI(gfxterm
)
1159 grub_term_unregister_output (&grub_video_term
);