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/bitmap_scale.h>
32 #include <grub/i18n.h>
34 #define DEFAULT_VIDEO_MODE "auto"
35 #define DEFAULT_BORDER_WIDTH 10
37 #define DEFAULT_STANDARD_COLOR 0x07
39 struct grub_dirty_region
47 struct grub_colored_char
49 /* An Unicode codepoint. */
50 struct grub_unicode_glyph
*code
;
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 term_color
;
96 grub_video_color_t fg_color
;
97 grub_video_color_t bg_color
;
98 grub_video_color_t bg_color_display
;
100 /* Text buffer for virtual screen. Contains (columns * rows) number
102 struct grub_colored_char
*text_buffer
;
107 struct grub_gfxterm_window
116 static struct grub_video_render_target
*render_target
;
117 void (*grub_gfxterm_decorator_hook
) (void) = NULL
;
118 static struct grub_gfxterm_window window
;
119 static struct grub_virtual_screen virtual_screen
;
120 static grub_gfxterm_repaint_callback_t repaint_callback
;
121 static int repaint_scheduled
= 0;
122 static int repaint_was_scheduled
= 0;
124 static void destroy_window (void);
126 static struct grub_video_render_target
*text_layer
;
128 static unsigned int bitmap_width
;
129 static unsigned int bitmap_height
;
130 static struct grub_video_bitmap
*bitmap
;
132 static struct grub_dirty_region dirty_region
;
134 static void dirty_region_reset (void);
136 static int dirty_region_is_empty (void);
138 static void dirty_region_add (int x
, int y
,
139 unsigned int width
, unsigned int height
);
141 static unsigned int calculate_normal_character_width (grub_font_t font
);
143 static unsigned char calculate_character_width (struct grub_font_glyph
*glyph
);
145 static void grub_gfxterm_refresh (struct grub_term_output
*term
__attribute__ ((unused
)));
148 grub_gfxterm_getcharwidth (struct grub_term_output
*term
__attribute__ ((unused
)),
149 const struct grub_unicode_glyph
*c
);
152 set_term_color (grub_uint8_t term_color
)
154 struct grub_video_render_target
*old_target
;
156 /* Save previous target and switch to text layer. */
157 grub_video_get_active_render_target (&old_target
);
158 grub_video_set_active_render_target (text_layer
);
160 /* Map terminal color to text layer compatible video colors. */
161 virtual_screen
.fg_color
= grub_video_map_color(term_color
& 0x0f);
163 /* Special case: use black as transparent color. */
164 if (((term_color
>> 4) & 0x0f) == 0)
166 virtual_screen
.bg_color
= grub_video_map_rgba(0, 0, 0, 0);
170 virtual_screen
.bg_color
= grub_video_map_color((term_color
>> 4) & 0x0f);
173 /* Restore previous target. */
174 grub_video_set_active_render_target (old_target
);
178 clear_char (struct grub_colored_char
*c
)
181 c
->code
= grub_unicode_glyph_from_code (' ');
183 grub_errno
= GRUB_ERR_NONE
;
184 c
->fg_color
= virtual_screen
.fg_color
;
185 c
->bg_color
= virtual_screen
.bg_color
;
191 grub_virtual_screen_free (void)
193 /* If virtual screen has been allocated, free it. */
194 if (virtual_screen
.text_buffer
!= 0)
195 grub_free (virtual_screen
.text_buffer
);
197 /* Reset virtual screen data. */
198 grub_memset (&virtual_screen
, 0, sizeof (virtual_screen
));
200 /* Free render targets. */
201 grub_video_delete_render_target (text_layer
);
206 grub_virtual_screen_setup (unsigned int x
, unsigned int y
,
207 unsigned int width
, unsigned int height
,
208 const char *font_name
)
212 /* Free old virtual screen. */
213 grub_virtual_screen_free ();
215 /* Initialize with default data. */
216 virtual_screen
.font
= grub_font_get (font_name
);
217 if (!virtual_screen
.font
)
218 return grub_error (GRUB_ERR_BAD_FONT
,
220 virtual_screen
.width
= width
;
221 virtual_screen
.height
= height
;
222 virtual_screen
.offset_x
= x
;
223 virtual_screen
.offset_y
= y
;
224 virtual_screen
.normal_char_width
=
225 calculate_normal_character_width (virtual_screen
.font
);
226 virtual_screen
.normal_char_height
=
227 grub_font_get_max_char_height (virtual_screen
.font
);
228 virtual_screen
.cursor_x
= 0;
229 virtual_screen
.cursor_y
= 0;
230 virtual_screen
.cursor_state
= 1;
231 virtual_screen
.total_scroll
= 0;
233 /* Calculate size of text buffer. */
234 virtual_screen
.columns
= virtual_screen
.width
/ virtual_screen
.normal_char_width
;
235 virtual_screen
.rows
= virtual_screen
.height
/ virtual_screen
.normal_char_height
;
237 /* Allocate memory for text buffer. */
238 virtual_screen
.text_buffer
=
239 (struct grub_colored_char
*) grub_malloc (virtual_screen
.columns
240 * virtual_screen
.rows
241 * sizeof (*virtual_screen
.text_buffer
));
242 if (grub_errno
!= GRUB_ERR_NONE
)
245 /* Create new render target for text layer. */
246 grub_video_create_render_target (&text_layer
,
247 virtual_screen
.width
,
248 virtual_screen
.height
,
249 GRUB_VIDEO_MODE_TYPE_RGB
250 | GRUB_VIDEO_MODE_TYPE_ALPHA
);
251 if (grub_errno
!= GRUB_ERR_NONE
)
254 /* As we want to have colors compatible with rendering target,
255 we can only have those after mode is initialized. */
256 grub_video_set_active_render_target (text_layer
);
258 virtual_screen
.standard_color_setting
= DEFAULT_STANDARD_COLOR
;
260 virtual_screen
.term_color
= GRUB_TERM_DEFAULT_NORMAL_COLOR
;
262 set_term_color (virtual_screen
.term_color
);
264 grub_video_set_active_render_target (render_target
);
266 virtual_screen
.bg_color_display
= grub_video_map_rgba(0, 0, 0, 0);
268 /* Clear out text buffer. */
269 for (i
= 0; i
< virtual_screen
.columns
* virtual_screen
.rows
; i
++)
271 virtual_screen
.text_buffer
[i
].code
= 0;
272 clear_char (&(virtual_screen
.text_buffer
[i
]));
279 grub_gfxterm_schedule_repaint (void)
281 repaint_scheduled
= 1;
285 grub_gfxterm_set_window (struct grub_video_render_target
*target
,
286 int x
, int y
, int width
, int height
,
288 const char *font_name
, int border_width
)
290 /* Clean up any prior instance. */
293 /* Set the render target. */
294 render_target
= target
;
296 /* Create virtual screen. */
297 if (grub_virtual_screen_setup (border_width
, border_width
,
298 width
- 2 * border_width
,
299 height
- 2 * border_width
,
306 /* Set window bounds. */
309 window
.width
= width
;
310 window
.height
= height
;
311 window
.double_repaint
= double_repaint
;
313 dirty_region_reset ();
314 grub_gfxterm_schedule_repaint ();
320 grub_gfxterm_fullscreen (void)
322 const char *font_name
;
323 struct grub_video_mode_info mode_info
;
324 grub_video_color_t color
;
328 err
= grub_video_get_info (&mode_info
);
329 /* Figure out what mode we ended up. */
333 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
335 double_redraw
= mode_info
.mode_type
& GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
336 && !(mode_info
.mode_type
& GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
);
338 /* Make sure screen is black. */
339 color
= grub_video_map_rgb (0, 0, 0);
340 grub_video_fill_rect (color
, 0, 0, mode_info
.width
, mode_info
.height
);
343 grub_video_swap_buffers ();
344 grub_video_fill_rect (color
, 0, 0, mode_info
.width
, mode_info
.height
);
348 /* Select the font to use. */
349 font_name
= grub_env_get ("gfxterm_font");
351 font_name
= ""; /* Allow fallback to any font. */
353 grub_gfxterm_decorator_hook
= NULL
;
355 return grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY
,
356 0, 0, mode_info
.width
, mode_info
.height
,
358 font_name
, DEFAULT_BORDER_WIDTH
);
362 grub_gfxterm_term_init (struct grub_term_output
*term
__attribute__ ((unused
)))
368 /* Parse gfxmode environment variable if set. */
369 modevar
= grub_env_get ("gfxmode");
370 if (! modevar
|| *modevar
== 0)
371 err
= grub_video_set_mode (DEFAULT_VIDEO_MODE
,
372 GRUB_VIDEO_MODE_TYPE_PURE_TEXT
, 0);
375 tmp
= grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE
, modevar
);
378 err
= grub_video_set_mode (tmp
, GRUB_VIDEO_MODE_TYPE_PURE_TEXT
, 0);
385 err
= grub_gfxterm_fullscreen ();
387 grub_video_restore ();
393 destroy_window (void)
397 grub_video_bitmap_destroy (bitmap
);
401 repaint_callback
= 0;
402 grub_virtual_screen_free ();
406 grub_gfxterm_term_fini (struct grub_term_output
*term
__attribute__ ((unused
)))
409 grub_video_restore ();
411 /* Clear error state. */
412 grub_errno
= GRUB_ERR_NONE
;
413 return GRUB_ERR_NONE
;
417 redraw_screen_rect (unsigned int x
, unsigned int y
,
418 unsigned int width
, unsigned int height
)
420 grub_video_color_t color
;
421 grub_video_rect_t saved_view
;
423 grub_video_set_active_render_target (render_target
);
424 /* Save viewport and set it to our window. */
425 grub_video_get_viewport ((unsigned *) &saved_view
.x
,
426 (unsigned *) &saved_view
.y
,
427 (unsigned *) &saved_view
.width
,
428 (unsigned *) &saved_view
.height
);
429 grub_video_set_viewport (window
.x
, window
.y
, window
.width
, window
.height
);
433 /* Render bitmap as background. */
434 grub_video_blit_bitmap (bitmap
, GRUB_VIDEO_BLIT_REPLACE
, x
, y
,
438 /* If bitmap is smaller than requested blit area, use background
440 color
= virtual_screen
.bg_color_display
;
442 /* Fill right side of the bitmap if needed. */
443 if ((x
+ width
>= bitmap_width
) && (y
< bitmap_height
))
445 int w
= (x
+ width
) - bitmap_width
;
449 if (y
+ height
>= bitmap_height
)
451 h
= bitmap_height
- y
;
454 if (bitmap_width
> tx
)
459 /* Render background layer. */
460 grub_video_fill_rect (color
, tx
, y
, w
, h
);
463 /* Fill bottom side of the bitmap if needed. */
464 if (y
+ height
>= bitmap_height
)
466 int h
= (y
+ height
) - bitmap_height
;
469 if (bitmap_height
> ty
)
474 /* Render background layer. */
475 grub_video_fill_rect (color
, x
, ty
, width
, h
);
478 /* Render text layer as blended. */
479 grub_video_blit_render_target (text_layer
, GRUB_VIDEO_BLIT_BLEND
, x
, y
,
480 x
- virtual_screen
.offset_x
,
481 y
- virtual_screen
.offset_y
,
486 /* Render background layer. */
487 color
= virtual_screen
.bg_color_display
;
488 grub_video_fill_rect (color
, x
, y
, width
, height
);
490 /* Render text layer as replaced (to get texts background color). */
491 grub_video_blit_render_target (text_layer
, GRUB_VIDEO_BLIT_REPLACE
, x
, y
,
492 x
- virtual_screen
.offset_x
,
493 y
- virtual_screen
.offset_y
,
497 /* Restore saved viewport. */
498 grub_video_set_viewport (saved_view
.x
, saved_view
.y
,
499 saved_view
.width
, saved_view
.height
);
500 grub_video_set_active_render_target (render_target
);
502 if (repaint_callback
)
503 repaint_callback (x
, y
, width
, height
);
507 dirty_region_reset (void)
509 dirty_region
.top_left_x
= -1;
510 dirty_region
.top_left_y
= -1;
511 dirty_region
.bottom_right_x
= -1;
512 dirty_region
.bottom_right_y
= -1;
513 repaint_was_scheduled
= 0;
517 dirty_region_is_empty (void)
519 if ((dirty_region
.top_left_x
== -1)
520 || (dirty_region
.top_left_y
== -1)
521 || (dirty_region
.bottom_right_x
== -1)
522 || (dirty_region
.bottom_right_y
== -1))
528 dirty_region_add (int x
, int y
, unsigned int width
, unsigned int height
)
530 if ((width
== 0) || (height
== 0))
533 if (repaint_scheduled
)
535 x
= virtual_screen
.offset_x
;
536 y
= virtual_screen
.offset_y
;
537 width
= virtual_screen
.width
;
538 height
= virtual_screen
.height
;
539 repaint_scheduled
= 0;
540 repaint_was_scheduled
= 1;
543 if (dirty_region_is_empty ())
545 dirty_region
.top_left_x
= x
;
546 dirty_region
.top_left_y
= y
;
547 dirty_region
.bottom_right_x
= x
+ width
- 1;
548 dirty_region
.bottom_right_y
= y
+ height
- 1;
552 if (x
< dirty_region
.top_left_x
)
553 dirty_region
.top_left_x
= x
;
554 if (y
< dirty_region
.top_left_y
)
555 dirty_region
.top_left_y
= y
;
556 if ((x
+ (int)width
- 1) > dirty_region
.bottom_right_x
)
557 dirty_region
.bottom_right_x
= x
+ width
- 1;
558 if ((y
+ (int)height
- 1) > dirty_region
.bottom_right_y
)
559 dirty_region
.bottom_right_y
= y
+ height
- 1;
564 dirty_region_add_virtualscreen (void)
566 /* Mark virtual screen as dirty. */
567 dirty_region_add (virtual_screen
.offset_x
, virtual_screen
.offset_y
,
568 virtual_screen
.width
, virtual_screen
.height
);
573 dirty_region_redraw (void)
580 if (dirty_region_is_empty ())
583 x
= dirty_region
.top_left_x
;
584 y
= dirty_region
.top_left_y
;
586 width
= dirty_region
.bottom_right_x
- x
+ 1;
587 height
= dirty_region
.bottom_right_y
- y
+ 1;
589 if (repaint_was_scheduled
&& grub_gfxterm_decorator_hook
)
590 grub_gfxterm_decorator_hook ();
592 redraw_screen_rect (x
, y
, width
, height
);
596 paint_char (unsigned cx
, unsigned cy
)
598 struct grub_colored_char
*p
;
599 struct grub_font_glyph
*glyph
;
600 grub_video_color_t color
;
601 grub_video_color_t bgcolor
;
608 if (cy
+ virtual_screen
.total_scroll
>= virtual_screen
.rows
)
611 /* Find out active character. */
612 p
= (virtual_screen
.text_buffer
613 + cx
+ (cy
* virtual_screen
.columns
));
617 /* Get glyph for character. */
618 glyph
= grub_font_construct_glyph (virtual_screen
.font
, p
->code
);
621 grub_errno
= GRUB_ERR_NONE
;
624 ascent
= grub_font_get_ascent (virtual_screen
.font
);
626 width
= virtual_screen
.normal_char_width
* calculate_character_width(glyph
);
627 height
= virtual_screen
.normal_char_height
;
630 bgcolor
= p
->bg_color
;
632 x
= cx
* virtual_screen
.normal_char_width
;
633 y
= (cy
+ virtual_screen
.total_scroll
) * virtual_screen
.normal_char_height
;
635 /* Render glyph to text layer. */
636 grub_video_set_active_render_target (text_layer
);
637 grub_video_fill_rect (bgcolor
, x
, y
, width
, height
);
638 grub_font_draw_glyph (glyph
, color
, x
, y
+ ascent
);
639 grub_video_set_active_render_target (render_target
);
641 /* Mark character to be drawn. */
642 dirty_region_add (virtual_screen
.offset_x
+ x
, virtual_screen
.offset_y
+ y
,
650 paint_char (virtual_screen
.cursor_x
, virtual_screen
.cursor_y
);
654 draw_cursor (int show
)
660 grub_video_color_t color
;
667 if (virtual_screen
.cursor_y
+ virtual_screen
.total_scroll
668 >= virtual_screen
.rows
)
671 /* Determine cursor properties and position on text layer. */
672 x
= virtual_screen
.cursor_x
* virtual_screen
.normal_char_width
;
673 width
= virtual_screen
.normal_char_width
;
674 color
= virtual_screen
.fg_color
;
675 y
= ((virtual_screen
.cursor_y
+ virtual_screen
.total_scroll
)
676 * virtual_screen
.normal_char_height
677 + grub_font_get_ascent (virtual_screen
.font
));
680 /* Render cursor to text layer. */
681 grub_video_set_active_render_target (text_layer
);
682 grub_video_fill_rect (color
, x
, y
, width
, height
);
683 grub_video_set_active_render_target (render_target
);
685 /* Mark cursor to be redrawn. */
686 dirty_region_add (virtual_screen
.offset_x
+ x
,
687 virtual_screen
.offset_y
+ y
,
694 unsigned int i
, j
, was_scroll
;
695 grub_video_color_t color
;
697 if (!virtual_screen
.total_scroll
)
700 /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */
703 /* Scroll physical screen. */
704 grub_video_set_active_render_target (text_layer
);
705 color
= virtual_screen
.bg_color
;
706 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
707 * virtual_screen
.total_scroll
);
709 /* Mark virtual screen to be redrawn. */
710 dirty_region_add_virtualscreen ();
714 grub_video_rect_t saved_view
;
719 grub_video_set_active_render_target (render_target
);
721 i
= window
.double_repaint
? 2 : 1;
723 color
= virtual_screen
.bg_color
;
727 /* Save viewport and set it to our window. */
728 grub_video_get_viewport ((unsigned *) &saved_view
.x
,
729 (unsigned *) &saved_view
.y
,
730 (unsigned *) &saved_view
.width
,
731 (unsigned *) &saved_view
.height
);
733 grub_video_set_viewport (window
.x
, window
.y
, window
.width
,
736 /* Clear new border area. */
737 grub_video_fill_rect (color
,
738 virtual_screen
.offset_x
,
739 virtual_screen
.offset_y
,
740 virtual_screen
.width
,
741 virtual_screen
.normal_char_height
742 * virtual_screen
.total_scroll
);
744 grub_video_set_active_render_target (render_target
);
745 dirty_region_redraw ();
747 /* Scroll physical screen. */
748 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
749 * virtual_screen
.total_scroll
);
751 /* Restore saved viewport. */
752 grub_video_set_viewport (saved_view
.x
, saved_view
.y
,
753 saved_view
.width
, saved_view
.height
);
756 grub_video_swap_buffers ();
758 dirty_region_reset ();
760 /* Scroll physical screen. */
761 grub_video_set_active_render_target (text_layer
);
762 color
= virtual_screen
.bg_color
;
763 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
764 * virtual_screen
.total_scroll
);
766 grub_video_set_active_render_target (render_target
);
770 was_scroll
= virtual_screen
.total_scroll
;
771 virtual_screen
.total_scroll
= 0;
773 if (was_scroll
> virtual_screen
.rows
)
774 was_scroll
= virtual_screen
.rows
;
776 /* Draw shadow part. */
777 for (i
= virtual_screen
.rows
- was_scroll
;
778 i
< virtual_screen
.rows
; i
++)
779 for (j
= 0; j
< virtual_screen
.columns
; j
++)
782 /* Draw cursor if visible. */
783 if (virtual_screen
.cursor_state
)
786 if (repaint_callback
)
787 repaint_callback (window
.x
, window
.y
, window
.width
, window
.height
);
795 /* Clear first line in text buffer. */
797 i
< virtual_screen
.columns
;
800 virtual_screen
.text_buffer
[i
].code
= 0;
801 clear_char (&(virtual_screen
.text_buffer
[i
]));
804 /* Scroll text buffer with one line to up. */
805 grub_memmove (virtual_screen
.text_buffer
,
806 virtual_screen
.text_buffer
+ virtual_screen
.columns
,
807 sizeof (*virtual_screen
.text_buffer
)
808 * virtual_screen
.columns
809 * (virtual_screen
.rows
- 1));
811 /* Clear last line in text buffer. */
812 for (i
= virtual_screen
.columns
* (virtual_screen
.rows
- 1);
813 i
< virtual_screen
.columns
* virtual_screen
.rows
;
816 virtual_screen
.text_buffer
[i
].code
= 0;
817 clear_char (&(virtual_screen
.text_buffer
[i
]));
820 virtual_screen
.total_scroll
++;
824 grub_gfxterm_putchar (struct grub_term_output
*term
,
825 const struct grub_unicode_glyph
*c
)
831 /* Erase current cursor, if any. */
832 if (virtual_screen
.cursor_state
)
835 if (c
->base
== '\b' || c
->base
== '\n' || c
->base
== '\r')
840 if (virtual_screen
.cursor_x
> 0)
841 virtual_screen
.cursor_x
--;
845 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
848 virtual_screen
.cursor_y
++;
852 virtual_screen
.cursor_x
= 0;
858 struct grub_colored_char
*p
;
859 unsigned char char_width
;
861 /* Calculate actual character width for glyph. This is number of
862 times of normal_font_width. */
863 char_width
= grub_gfxterm_getcharwidth (term
, c
);
865 /* If we are about to exceed line length, wrap to next line. */
866 if (virtual_screen
.cursor_x
+ char_width
> virtual_screen
.columns
)
868 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
871 virtual_screen
.cursor_y
++;
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
->code
= grub_unicode_glyph_dup (c
);
881 grub_errno
= GRUB_ERR_NONE
;
882 p
->fg_color
= virtual_screen
.fg_color
;
883 p
->bg_color
= virtual_screen
.bg_color
;
884 p
->width
= char_width
- 1;
887 /* If we have large glyph, add fixup info. */
892 for (i
= 1; i
< char_width
; i
++)
894 grub_free (p
[i
].code
);
895 p
[i
].code
= grub_unicode_glyph_from_code (' ');
897 grub_errno
= GRUB_ERR_NONE
;
898 p
[i
].width
= char_width
- 1;
906 /* Make sure we scroll screen when needed and wrap line correctly. */
907 virtual_screen
.cursor_x
+= char_width
;
908 if (virtual_screen
.cursor_x
>= virtual_screen
.columns
)
910 virtual_screen
.cursor_x
= 0;
912 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
915 virtual_screen
.cursor_y
++;
919 /* Redraw cursor if it should be visible. */
920 /* Note: This will redraw the character as well, which means that the
921 above call to write_char is redundant when the cursor is showing. */
922 if (virtual_screen
.cursor_state
)
926 /* Use ASCII characters to determine normal character width. */
928 calculate_normal_character_width (grub_font_t font
)
930 struct grub_font_glyph
*glyph
;
931 unsigned int width
= 0;
934 /* Get properties of every printable ASCII character. */
935 for (i
= 32; i
< 127; i
++)
937 glyph
= grub_font_get_glyph (font
, i
);
939 /* Skip unknown characters. Should never happen on normal conditions. */
943 if (glyph
->device_width
> width
)
944 width
= glyph
->device_width
;
951 calculate_character_width (struct grub_font_glyph
*glyph
)
953 if (! glyph
|| glyph
->device_width
== 0)
956 return (glyph
->device_width
957 + (virtual_screen
.normal_char_width
- 1))
958 / virtual_screen
.normal_char_width
;
962 grub_gfxterm_getcharwidth (struct grub_term_output
*term
__attribute__ ((unused
)),
963 const struct grub_unicode_glyph
*c
)
966 dev_width
= grub_font_get_constructed_device_width (virtual_screen
.font
, c
);
971 return (dev_width
+ (virtual_screen
.normal_char_width
- 1))
972 / virtual_screen
.normal_char_width
;
976 grub_virtual_screen_getwh (struct grub_term_output
*term
__attribute__ ((unused
)))
978 return (virtual_screen
.columns
<< 8) | virtual_screen
.rows
;
982 grub_virtual_screen_getxy (struct grub_term_output
*term
__attribute__ ((unused
)))
984 return ((virtual_screen
.cursor_x
<< 8) | virtual_screen
.cursor_y
);
988 grub_gfxterm_gotoxy (struct grub_term_output
*term
__attribute__ ((unused
)),
989 grub_uint8_t x
, grub_uint8_t y
)
991 if (x
>= virtual_screen
.columns
)
992 x
= virtual_screen
.columns
- 1;
994 if (y
>= virtual_screen
.rows
)
995 y
= virtual_screen
.rows
- 1;
997 /* Erase current cursor, if any. */
998 if (virtual_screen
.cursor_state
)
1001 virtual_screen
.cursor_x
= x
;
1002 virtual_screen
.cursor_y
= y
;
1004 /* Draw cursor if visible. */
1005 if (virtual_screen
.cursor_state
)
1010 grub_virtual_screen_cls (struct grub_term_output
*term
__attribute__ ((unused
)))
1014 for (i
= 0; i
< virtual_screen
.columns
* virtual_screen
.rows
; i
++)
1015 clear_char (&(virtual_screen
.text_buffer
[i
]));
1017 virtual_screen
.cursor_x
= virtual_screen
.cursor_y
= 0;
1021 grub_gfxterm_cls (struct grub_term_output
*term
)
1023 grub_video_color_t color
;
1025 /* Clear virtual screen. */
1026 grub_virtual_screen_cls (term
);
1028 /* Clear text layer. */
1029 grub_video_set_active_render_target (text_layer
);
1030 color
= virtual_screen
.bg_color
;
1031 grub_video_fill_rect (color
, 0, 0,
1032 virtual_screen
.width
, virtual_screen
.height
);
1033 grub_video_set_active_render_target (render_target
);
1035 /* Mark virtual screen to be redrawn. */
1036 dirty_region_add_virtualscreen ();
1038 grub_gfxterm_refresh (term
);
1042 grub_virtual_screen_setcolorstate (struct grub_term_output
*term
,
1043 grub_term_color_state state
)
1047 case GRUB_TERM_COLOR_STANDARD
:
1048 virtual_screen
.term_color
= virtual_screen
.standard_color_setting
;
1051 case GRUB_TERM_COLOR_NORMAL
:
1052 virtual_screen
.term_color
= term
->normal_color
;
1055 case GRUB_TERM_COLOR_HIGHLIGHT
:
1056 virtual_screen
.term_color
= term
->highlight_color
;
1063 /* Change color to virtual terminal. */
1064 set_term_color (virtual_screen
.term_color
);
1068 grub_gfxterm_setcursor (struct grub_term_output
*term
__attribute__ ((unused
)),
1071 if (virtual_screen
.cursor_state
!= on
)
1073 if (virtual_screen
.cursor_state
)
1078 virtual_screen
.cursor_state
= on
;
1083 grub_gfxterm_refresh (struct grub_term_output
*term
__attribute__ ((unused
)))
1087 /* Redraw only changed regions. */
1088 dirty_region_redraw ();
1090 grub_video_swap_buffers ();
1092 if (window
.double_repaint
)
1093 dirty_region_redraw ();
1094 dirty_region_reset ();
1098 grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func
)
1100 repaint_callback
= func
;
1103 /* Option array indices. */
1104 #define BACKGROUND_CMD_ARGINDEX_MODE 0
1106 static const struct grub_arg_option background_image_cmd_options
[] =
1108 {"mode", 'm', 0, "Background image mode.", "stretch|normal",
1114 grub_gfxterm_background_image_cmd (grub_extcmd_t cmd
__attribute__ ((unused
)),
1118 struct grub_arg_list
*state
= cmd
->state
;
1120 /* Check that we have video adapter active. */
1121 if (grub_video_get_info(NULL
) != GRUB_ERR_NONE
)
1124 /* Destroy existing background bitmap if loaded. */
1127 grub_video_bitmap_destroy (bitmap
);
1130 /* Mark whole screen as dirty. */
1131 dirty_region_add (0, 0, window
.width
, window
.height
);
1134 /* If filename was provided, try to load that. */
1137 /* Try to load new one. */
1138 grub_video_bitmap_load (&bitmap
, args
[0]);
1139 if (grub_errno
!= GRUB_ERR_NONE
)
1142 /* Determine if the bitmap should be scaled to fit the screen. */
1143 if (!state
[BACKGROUND_CMD_ARGINDEX_MODE
].set
1144 || grub_strcmp (state
[BACKGROUND_CMD_ARGINDEX_MODE
].arg
,
1147 if (window
.width
!= grub_video_bitmap_get_width (bitmap
)
1148 || window
.height
!= grub_video_bitmap_get_height (bitmap
))
1150 struct grub_video_bitmap
*scaled_bitmap
;
1151 grub_video_bitmap_create_scaled (&scaled_bitmap
,
1155 GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST
);
1156 if (grub_errno
== GRUB_ERR_NONE
)
1158 /* Replace the original bitmap with the scaled one. */
1159 grub_video_bitmap_destroy (bitmap
);
1160 bitmap
= scaled_bitmap
;
1165 /* If bitmap was loaded correctly, display it. */
1168 /* Determine bitmap dimensions. */
1169 bitmap_width
= grub_video_bitmap_get_width (bitmap
);
1170 bitmap_height
= grub_video_bitmap_get_height (bitmap
);
1172 /* Mark whole screen as dirty. */
1173 dirty_region_add (0, 0, window
.width
, window
.height
);
1178 grub_errno
= GRUB_ERR_NONE
;
1182 static struct grub_term_output grub_video_term
=
1185 .init
= grub_gfxterm_term_init
,
1186 .fini
= grub_gfxterm_term_fini
,
1187 .putchar
= grub_gfxterm_putchar
,
1188 .getcharwidth
= grub_gfxterm_getcharwidth
,
1189 .getwh
= grub_virtual_screen_getwh
,
1190 .getxy
= grub_virtual_screen_getxy
,
1191 .gotoxy
= grub_gfxterm_gotoxy
,
1192 .cls
= grub_gfxterm_cls
,
1193 .setcolorstate
= grub_virtual_screen_setcolorstate
,
1194 .setcursor
= grub_gfxterm_setcursor
,
1195 .refresh
= grub_gfxterm_refresh
,
1196 .flags
= GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS
,
1197 .normal_color
= GRUB_TERM_DEFAULT_NORMAL_COLOR
,
1198 .highlight_color
= GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR
,
1202 static grub_extcmd_t background_image_cmd_handle
;
1204 GRUB_MOD_INIT(gfxterm
)
1206 grub_term_register_output ("gfxterm", &grub_video_term
);
1207 background_image_cmd_handle
=
1208 grub_register_extcmd ("background_image",
1209 grub_gfxterm_background_image_cmd
,
1210 GRUB_COMMAND_FLAG_BOTH
,
1211 N_("[-m (stretch|normal)] FILE"),
1212 N_("Load background image for active terminal."),
1213 background_image_cmd_options
);
1216 GRUB_MOD_FINI(gfxterm
)
1218 grub_unregister_extcmd (background_image_cmd_handle
);
1219 grub_term_unregister_output (&grub_video_term
);