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 GRUB_MOD_LICENSE ("GPLv3+");
36 #define DEFAULT_VIDEO_MODE "auto"
37 #define DEFAULT_BORDER_WIDTH 10
39 #define DEFAULT_STANDARD_COLOR 0x07
41 struct grub_dirty_region
49 struct grub_colored_char
51 /* An Unicode codepoint. */
52 struct grub_unicode_glyph
*code
;
55 grub_video_color_t fg_color
;
56 grub_video_color_t bg_color
;
59 struct grub_virtual_screen
61 /* Dimensions of the virtual screen in pixels. */
65 /* Offset in the display in pixels. */
66 unsigned int offset_x
;
67 unsigned int offset_y
;
69 /* TTY Character sizes in pixes. */
70 unsigned int normal_char_width
;
71 unsigned int normal_char_height
;
73 /* Virtual screen TTY size in characters. */
77 /* Current cursor location in characters. */
78 unsigned int cursor_x
;
79 unsigned int cursor_y
;
81 /* Current cursor state. */
87 /* Terminal color settings. */
88 grub_uint8_t standard_color_setting
;
89 grub_uint8_t term_color
;
92 grub_video_color_t fg_color
;
93 grub_video_color_t bg_color
;
94 grub_video_color_t bg_color_display
;
96 /* Text buffer for virtual screen. Contains (columns * rows) number
98 struct grub_colored_char
*text_buffer
;
103 struct grub_gfxterm_window
112 static struct grub_video_render_target
*render_target
;
113 void (*grub_gfxterm_decorator_hook
) (void) = NULL
;
114 static struct grub_gfxterm_window window
;
115 static struct grub_virtual_screen virtual_screen
;
116 static grub_gfxterm_repaint_callback_t repaint_callback
;
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 static unsigned int bitmap_width
;
125 static unsigned int bitmap_height
;
126 static struct grub_video_bitmap
*bitmap
;
127 static int blend_text_bg
;
128 static grub_video_rgba_color_t default_bg_color
= { 0, 0, 0, 0 };
130 static struct grub_dirty_region dirty_region
;
132 static void dirty_region_reset (void);
134 static int dirty_region_is_empty (void);
136 static void dirty_region_add (int x
, int y
,
137 unsigned int width
, unsigned int height
);
139 static unsigned int calculate_normal_character_width (grub_font_t font
);
141 static unsigned char calculate_character_width (struct grub_font_glyph
*glyph
);
143 static void grub_gfxterm_refresh (struct grub_term_output
*term
__attribute__ ((unused
)));
146 grub_gfxterm_getcharwidth (struct grub_term_output
*term
__attribute__ ((unused
)),
147 const struct grub_unicode_glyph
*c
);
150 set_term_color (grub_uint8_t term_color
)
152 struct grub_video_render_target
*old_target
;
154 /* Save previous target and switch to text layer. */
155 grub_video_get_active_render_target (&old_target
);
156 grub_video_set_active_render_target (text_layer
);
158 /* Map terminal color to text layer compatible video colors. */
159 virtual_screen
.fg_color
= grub_video_map_color(term_color
& 0x0f);
161 /* Special case: use black as transparent color. */
162 if (((term_color
>> 4) & 0x0f) == 0)
164 virtual_screen
.bg_color
= grub_video_map_rgba(0, 0, 0, 0);
168 virtual_screen
.bg_color
= grub_video_map_color((term_color
>> 4) & 0x0f);
171 /* Restore previous target. */
172 grub_video_set_active_render_target (old_target
);
176 clear_char (struct grub_colored_char
*c
)
179 c
->code
= grub_unicode_glyph_from_code (' ');
181 grub_errno
= GRUB_ERR_NONE
;
182 c
->fg_color
= virtual_screen
.fg_color
;
183 c
->bg_color
= virtual_screen
.bg_color
;
187 grub_virtual_screen_free (void)
189 /* If virtual screen has been allocated, free it. */
190 if (virtual_screen
.text_buffer
!= 0)
191 grub_free (virtual_screen
.text_buffer
);
193 /* Reset virtual screen data. */
194 grub_memset (&virtual_screen
, 0, sizeof (virtual_screen
));
196 /* Free render targets. */
197 grub_video_delete_render_target (text_layer
);
202 grub_virtual_screen_setup (unsigned int x
, unsigned int y
,
203 unsigned int width
, unsigned int height
,
204 const char *font_name
)
208 /* Free old virtual screen. */
209 grub_virtual_screen_free ();
211 /* Initialize with default data. */
212 virtual_screen
.font
= grub_font_get (font_name
);
213 if (!virtual_screen
.font
)
214 return grub_error (GRUB_ERR_BAD_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 virtual_screen
.cursor_x
= 0;
225 virtual_screen
.cursor_y
= 0;
226 virtual_screen
.cursor_state
= 1;
227 virtual_screen
.total_scroll
= 0;
229 /* Calculate size of text buffer. */
230 virtual_screen
.columns
= virtual_screen
.width
/ virtual_screen
.normal_char_width
;
231 virtual_screen
.rows
= virtual_screen
.height
/ virtual_screen
.normal_char_height
;
233 /* Allocate memory for text buffer. */
234 virtual_screen
.text_buffer
=
235 (struct grub_colored_char
*) grub_malloc (virtual_screen
.columns
236 * virtual_screen
.rows
237 * sizeof (*virtual_screen
.text_buffer
));
238 if (grub_errno
!= GRUB_ERR_NONE
)
241 /* Create new render target for text layer. */
242 grub_video_create_render_target (&text_layer
,
243 virtual_screen
.width
,
244 virtual_screen
.height
,
245 GRUB_VIDEO_MODE_TYPE_RGB
246 | GRUB_VIDEO_MODE_TYPE_ALPHA
);
247 if (grub_errno
!= GRUB_ERR_NONE
)
250 /* As we want to have colors compatible with rendering target,
251 we can only have those after mode is initialized. */
252 grub_video_set_active_render_target (text_layer
);
254 virtual_screen
.standard_color_setting
= DEFAULT_STANDARD_COLOR
;
256 virtual_screen
.term_color
= GRUB_TERM_DEFAULT_NORMAL_COLOR
;
258 set_term_color (virtual_screen
.term_color
);
260 grub_video_set_active_render_target (render_target
);
262 virtual_screen
.bg_color_display
=
263 grub_video_map_rgba_color (default_bg_color
);
265 /* Clear out text buffer. */
266 for (i
= 0; i
< virtual_screen
.columns
* virtual_screen
.rows
; i
++)
268 virtual_screen
.text_buffer
[i
].code
= 0;
269 clear_char (&(virtual_screen
.text_buffer
[i
]));
276 grub_gfxterm_schedule_repaint (void)
278 repaint_scheduled
= 1;
282 grub_gfxterm_set_window (struct grub_video_render_target
*target
,
283 int x
, int y
, int width
, int height
,
285 const char *font_name
, int border_width
)
287 /* Clean up any prior instance. */
290 /* Set the render target. */
291 render_target
= target
;
293 /* Create virtual screen. */
294 if (grub_virtual_screen_setup (border_width
, border_width
,
295 width
- 2 * border_width
,
296 height
- 2 * border_width
,
303 /* Set window bounds. */
306 window
.width
= width
;
307 window
.height
= height
;
308 window
.double_repaint
= double_repaint
;
310 dirty_region_reset ();
311 grub_gfxterm_schedule_repaint ();
317 grub_gfxterm_fullscreen (void)
319 const char *font_name
;
320 struct grub_video_mode_info mode_info
;
321 grub_video_color_t color
;
325 err
= grub_video_get_info (&mode_info
);
326 /* Figure out what mode we ended up. */
330 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY
);
332 double_redraw
= mode_info
.mode_type
& GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
333 && !(mode_info
.mode_type
& GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
);
335 /* Make sure screen is set to the default background color. */
336 color
= grub_video_map_rgba_color (default_bg_color
);
337 grub_video_fill_rect (color
, 0, 0, mode_info
.width
, mode_info
.height
);
340 grub_video_swap_buffers ();
341 grub_video_fill_rect (color
, 0, 0, mode_info
.width
, mode_info
.height
);
344 /* Select the font to use. */
345 font_name
= grub_env_get ("gfxterm_font");
347 font_name
= ""; /* Allow fallback to any font. */
349 grub_gfxterm_decorator_hook
= NULL
;
351 return grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY
,
352 0, 0, mode_info
.width
, mode_info
.height
,
354 font_name
, DEFAULT_BORDER_WIDTH
);
358 grub_gfxterm_term_init (struct grub_term_output
*term
__attribute__ ((unused
)))
364 /* Parse gfxmode environment variable if set. */
365 modevar
= grub_env_get ("gfxmode");
366 if (! modevar
|| *modevar
== 0)
367 err
= grub_video_set_mode (DEFAULT_VIDEO_MODE
,
368 GRUB_VIDEO_MODE_TYPE_PURE_TEXT
, 0);
371 tmp
= grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE
, modevar
);
374 err
= grub_video_set_mode (tmp
, GRUB_VIDEO_MODE_TYPE_PURE_TEXT
, 0);
381 err
= grub_gfxterm_fullscreen ();
383 grub_video_restore ();
389 destroy_window (void)
391 repaint_callback
= 0;
392 grub_virtual_screen_free ();
396 grub_gfxterm_term_fini (struct grub_term_output
*term
__attribute__ ((unused
)))
400 grub_video_restore ();
402 for (i
= 0; i
< virtual_screen
.columns
* virtual_screen
.rows
; i
++)
404 grub_free (virtual_screen
.text_buffer
[i
].code
);
405 virtual_screen
.text_buffer
[i
].code
= 0;
408 /* Clear error state. */
409 grub_errno
= GRUB_ERR_NONE
;
410 return GRUB_ERR_NONE
;
414 redraw_screen_rect (unsigned int x
, unsigned int y
,
415 unsigned int width
, unsigned int height
)
417 grub_video_color_t color
;
418 grub_video_rect_t saved_view
;
420 grub_video_set_active_render_target (render_target
);
421 /* Save viewport and set it to our window. */
422 grub_video_get_viewport ((unsigned *) &saved_view
.x
,
423 (unsigned *) &saved_view
.y
,
424 (unsigned *) &saved_view
.width
,
425 (unsigned *) &saved_view
.height
);
426 grub_video_set_viewport (window
.x
, window
.y
, window
.width
, window
.height
);
430 /* Render bitmap as background. */
431 grub_video_blit_bitmap (bitmap
, GRUB_VIDEO_BLIT_REPLACE
, x
, y
,
435 /* If bitmap is smaller than requested blit area, use background
437 color
= virtual_screen
.bg_color_display
;
439 /* Fill right side of the bitmap if needed. */
440 if ((x
+ width
>= bitmap_width
) && (y
< bitmap_height
))
442 int w
= (x
+ width
) - bitmap_width
;
446 if (y
+ height
>= bitmap_height
)
448 h
= bitmap_height
- y
;
451 if (bitmap_width
> tx
)
456 /* Render background layer. */
457 grub_video_fill_rect (color
, tx
, y
, w
, h
);
460 /* Fill bottom side of the bitmap if needed. */
461 if (y
+ height
>= bitmap_height
)
463 int h
= (y
+ height
) - bitmap_height
;
466 if (bitmap_height
> ty
)
471 /* Render background layer. */
472 grub_video_fill_rect (color
, x
, ty
, width
, h
);
477 /* Render background layer. */
478 color
= virtual_screen
.bg_color_display
;
479 grub_video_fill_rect (color
, x
, y
, width
, height
);
483 /* Render text layer as blended. */
484 grub_video_blit_render_target (text_layer
, GRUB_VIDEO_BLIT_BLEND
, x
, y
,
485 x
- virtual_screen
.offset_x
,
486 y
- virtual_screen
.offset_y
,
489 /* Render text layer as replaced (to get texts background color). */
490 grub_video_blit_render_target (text_layer
, GRUB_VIDEO_BLIT_REPLACE
, x
, y
,
491 x
- virtual_screen
.offset_x
,
492 y
- virtual_screen
.offset_y
,
495 /* Restore saved viewport. */
496 grub_video_set_viewport (saved_view
.x
, saved_view
.y
,
497 saved_view
.width
, saved_view
.height
);
498 grub_video_set_active_render_target (render_target
);
500 if (repaint_callback
)
501 repaint_callback (x
, y
, width
, height
);
505 dirty_region_reset (void)
507 dirty_region
.top_left_x
= -1;
508 dirty_region
.top_left_y
= -1;
509 dirty_region
.bottom_right_x
= -1;
510 dirty_region
.bottom_right_y
= -1;
511 repaint_was_scheduled
= 0;
515 dirty_region_is_empty (void)
517 if ((dirty_region
.top_left_x
== -1)
518 || (dirty_region
.top_left_y
== -1)
519 || (dirty_region
.bottom_right_x
== -1)
520 || (dirty_region
.bottom_right_y
== -1))
526 dirty_region_add_real (int x
, int y
, unsigned int width
, unsigned int height
)
528 if (dirty_region_is_empty ())
530 dirty_region
.top_left_x
= x
;
531 dirty_region
.top_left_y
= y
;
532 dirty_region
.bottom_right_x
= x
+ width
- 1;
533 dirty_region
.bottom_right_y
= y
+ height
- 1;
537 if (x
< dirty_region
.top_left_x
)
538 dirty_region
.top_left_x
= x
;
539 if (y
< dirty_region
.top_left_y
)
540 dirty_region
.top_left_y
= y
;
541 if ((x
+ (int)width
- 1) > dirty_region
.bottom_right_x
)
542 dirty_region
.bottom_right_x
= x
+ width
- 1;
543 if ((y
+ (int)height
- 1) > dirty_region
.bottom_right_y
)
544 dirty_region
.bottom_right_y
= y
+ height
- 1;
549 dirty_region_add (int x
, int y
, unsigned int width
, unsigned int height
)
551 if ((width
== 0) || (height
== 0))
554 if (repaint_scheduled
)
556 dirty_region_add_real (virtual_screen
.offset_x
, virtual_screen
.offset_y
,
557 virtual_screen
.width
, virtual_screen
.height
);
558 repaint_scheduled
= 0;
559 repaint_was_scheduled
= 1;
561 dirty_region_add_real (x
, y
, width
, height
);
565 dirty_region_add_virtualscreen (void)
567 /* Mark virtual screen as dirty. */
568 dirty_region_add (virtual_screen
.offset_x
, virtual_screen
.offset_y
,
569 virtual_screen
.width
, virtual_screen
.height
);
574 dirty_region_redraw (void)
581 if (dirty_region_is_empty ())
584 x
= dirty_region
.top_left_x
;
585 y
= dirty_region
.top_left_y
;
587 width
= dirty_region
.bottom_right_x
- x
+ 1;
588 height
= dirty_region
.bottom_right_y
- y
+ 1;
590 if (repaint_was_scheduled
&& grub_gfxterm_decorator_hook
)
591 grub_gfxterm_decorator_hook ();
593 redraw_screen_rect (x
, y
, width
, height
);
597 paint_char (unsigned cx
, unsigned cy
)
599 struct grub_colored_char
*p
;
600 struct grub_font_glyph
*glyph
;
601 grub_video_color_t color
;
602 grub_video_color_t bgcolor
;
609 if (cy
+ virtual_screen
.total_scroll
>= virtual_screen
.rows
)
612 /* Find out active character. */
613 p
= (virtual_screen
.text_buffer
614 + cx
+ (cy
* virtual_screen
.columns
));
619 /* Get glyph for character. */
620 glyph
= grub_font_construct_glyph (virtual_screen
.font
, p
->code
);
623 grub_errno
= GRUB_ERR_NONE
;
626 ascent
= grub_font_get_ascent (virtual_screen
.font
);
628 width
= virtual_screen
.normal_char_width
* calculate_character_width(glyph
);
629 height
= virtual_screen
.normal_char_height
;
632 bgcolor
= p
->bg_color
;
634 x
= cx
* virtual_screen
.normal_char_width
;
635 y
= (cy
+ virtual_screen
.total_scroll
) * virtual_screen
.normal_char_height
;
637 /* Render glyph to text layer. */
638 grub_video_set_active_render_target (text_layer
);
639 grub_video_fill_rect (bgcolor
, x
, y
, width
, height
);
640 grub_font_draw_glyph (glyph
, color
, x
, y
+ ascent
);
641 grub_video_set_active_render_target (render_target
);
643 /* Mark character to be drawn. */
644 dirty_region_add (virtual_screen
.offset_x
+ x
, virtual_screen
.offset_y
+ y
,
652 paint_char (virtual_screen
.cursor_x
, virtual_screen
.cursor_y
);
656 draw_cursor (int show
)
662 grub_video_color_t color
;
669 if (virtual_screen
.cursor_y
+ virtual_screen
.total_scroll
670 >= virtual_screen
.rows
)
673 /* Determine cursor properties and position on text layer. */
674 x
= virtual_screen
.cursor_x
* virtual_screen
.normal_char_width
;
675 width
= virtual_screen
.normal_char_width
;
676 color
= virtual_screen
.fg_color
;
677 y
= ((virtual_screen
.cursor_y
+ virtual_screen
.total_scroll
)
678 * virtual_screen
.normal_char_height
679 + grub_font_get_ascent (virtual_screen
.font
));
682 /* Render cursor to text layer. */
683 grub_video_set_active_render_target (text_layer
);
684 grub_video_fill_rect (color
, x
, y
, width
, height
);
685 grub_video_set_active_render_target (render_target
);
687 /* Mark cursor to be redrawn. */
688 dirty_region_add (virtual_screen
.offset_x
+ x
,
689 virtual_screen
.offset_y
+ y
,
696 unsigned int i
, j
, was_scroll
;
697 grub_video_color_t color
;
699 if (!virtual_screen
.total_scroll
)
702 /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */
705 /* Scroll physical screen. */
706 grub_video_set_active_render_target (text_layer
);
707 color
= virtual_screen
.bg_color
;
708 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
709 * virtual_screen
.total_scroll
);
711 /* Mark virtual screen to be redrawn. */
712 dirty_region_add_virtualscreen ();
716 grub_video_rect_t saved_view
;
721 grub_video_set_active_render_target (render_target
);
723 i
= window
.double_repaint
? 2 : 1;
725 color
= virtual_screen
.bg_color
;
729 /* Save viewport and set it to our window. */
730 grub_video_get_viewport ((unsigned *) &saved_view
.x
,
731 (unsigned *) &saved_view
.y
,
732 (unsigned *) &saved_view
.width
,
733 (unsigned *) &saved_view
.height
);
735 grub_video_set_viewport (window
.x
, window
.y
, window
.width
,
738 /* Clear new border area. */
739 grub_video_fill_rect (color
,
740 virtual_screen
.offset_x
,
741 virtual_screen
.offset_y
,
742 virtual_screen
.width
,
743 virtual_screen
.normal_char_height
744 * virtual_screen
.total_scroll
);
746 grub_video_set_active_render_target (render_target
);
747 dirty_region_redraw ();
749 /* Scroll physical screen. */
750 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
751 * virtual_screen
.total_scroll
);
753 /* Restore saved viewport. */
754 grub_video_set_viewport (saved_view
.x
, saved_view
.y
,
755 saved_view
.width
, saved_view
.height
);
758 grub_video_swap_buffers ();
760 dirty_region_reset ();
762 /* Scroll physical screen. */
763 grub_video_set_active_render_target (text_layer
);
764 color
= virtual_screen
.bg_color
;
765 grub_video_scroll (color
, 0, -virtual_screen
.normal_char_height
766 * virtual_screen
.total_scroll
);
768 grub_video_set_active_render_target (render_target
);
772 was_scroll
= virtual_screen
.total_scroll
;
773 virtual_screen
.total_scroll
= 0;
775 if (was_scroll
> virtual_screen
.rows
)
776 was_scroll
= virtual_screen
.rows
;
778 /* Draw shadow part. */
779 for (i
= virtual_screen
.rows
- was_scroll
;
780 i
< virtual_screen
.rows
; i
++)
781 for (j
= 0; j
< virtual_screen
.columns
; j
++)
784 /* Draw cursor if visible. */
785 if (virtual_screen
.cursor_state
)
788 if (repaint_callback
)
789 repaint_callback (window
.x
, window
.y
, window
.width
, window
.height
);
797 /* Clear first line in text buffer. */
798 for (i
= 0; i
< virtual_screen
.columns
; i
++)
799 grub_free (virtual_screen
.text_buffer
[i
].code
);
801 /* Scroll text buffer with one line to up. */
802 grub_memmove (virtual_screen
.text_buffer
,
803 virtual_screen
.text_buffer
+ virtual_screen
.columns
,
804 sizeof (*virtual_screen
.text_buffer
)
805 * virtual_screen
.columns
806 * (virtual_screen
.rows
- 1));
808 /* Clear last line in text buffer. */
809 for (i
= virtual_screen
.columns
* (virtual_screen
.rows
- 1);
810 i
< virtual_screen
.columns
* virtual_screen
.rows
;
813 virtual_screen
.text_buffer
[i
].code
= 0;
814 clear_char (&(virtual_screen
.text_buffer
[i
]));
817 virtual_screen
.total_scroll
++;
821 grub_gfxterm_putchar (struct grub_term_output
*term
,
822 const struct grub_unicode_glyph
*c
)
828 /* Erase current cursor, if any. */
829 if (virtual_screen
.cursor_state
)
832 if (c
->base
== '\b' || c
->base
== '\n' || c
->base
== '\r')
837 if (virtual_screen
.cursor_x
> 0)
838 virtual_screen
.cursor_x
--;
842 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
845 virtual_screen
.cursor_y
++;
849 virtual_screen
.cursor_x
= 0;
855 struct grub_colored_char
*p
;
856 unsigned char char_width
;
858 /* Calculate actual character width for glyph. This is number of
859 times of normal_font_width. */
860 char_width
= grub_gfxterm_getcharwidth (term
, c
);
862 /* If we are about to exceed line length, wrap to next line. */
863 if (virtual_screen
.cursor_x
+ char_width
> virtual_screen
.columns
)
865 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
868 virtual_screen
.cursor_y
++;
871 /* Find position on virtual screen, and fill information. */
872 p
= (virtual_screen
.text_buffer
+
873 virtual_screen
.cursor_x
+
874 virtual_screen
.cursor_y
* virtual_screen
.columns
);
876 p
->code
= grub_unicode_glyph_dup (c
);
878 grub_errno
= GRUB_ERR_NONE
;
879 p
->fg_color
= virtual_screen
.fg_color
;
880 p
->bg_color
= virtual_screen
.bg_color
;
882 /* If we have large glyph, add fixup info. */
887 for (i
= 1; i
< char_width
&& p
+ i
<
888 virtual_screen
.text_buffer
+ virtual_screen
.columns
889 * virtual_screen
.rows
; i
++)
891 grub_free (p
[i
].code
);
899 /* Make sure we scroll screen when needed and wrap line correctly. */
900 virtual_screen
.cursor_x
+= char_width
;
901 if (virtual_screen
.cursor_x
>= virtual_screen
.columns
)
903 virtual_screen
.cursor_x
= 0;
905 if (virtual_screen
.cursor_y
>= virtual_screen
.rows
- 1)
908 virtual_screen
.cursor_y
++;
912 /* Redraw cursor if it should be visible. */
913 /* Note: This will redraw the character as well, which means that the
914 above call to write_char is redundant when the cursor is showing. */
915 if (virtual_screen
.cursor_state
)
919 /* Use ASCII characters to determine normal character width. */
921 calculate_normal_character_width (grub_font_t font
)
923 struct grub_font_glyph
*glyph
;
924 unsigned int width
= 0;
927 /* Get properties of every printable ASCII character. */
928 for (i
= 32; i
< 127; i
++)
930 glyph
= grub_font_get_glyph (font
, i
);
932 /* Skip unknown characters. Should never happen on normal conditions. */
936 if (glyph
->device_width
> width
)
937 width
= glyph
->device_width
;
946 calculate_character_width (struct grub_font_glyph
*glyph
)
948 if (! glyph
|| glyph
->device_width
== 0)
951 return (glyph
->device_width
952 + (virtual_screen
.normal_char_width
- 1))
953 / virtual_screen
.normal_char_width
;
957 grub_gfxterm_getcharwidth (struct grub_term_output
*term
__attribute__ ((unused
)),
958 const struct grub_unicode_glyph
*c
)
961 dev_width
= grub_font_get_constructed_device_width (virtual_screen
.font
, c
);
966 return (dev_width
+ (virtual_screen
.normal_char_width
- 1))
967 / virtual_screen
.normal_char_width
;
971 grub_virtual_screen_getwh (struct grub_term_output
*term
__attribute__ ((unused
)))
973 return (virtual_screen
.columns
<< 8) | virtual_screen
.rows
;
977 grub_virtual_screen_getxy (struct grub_term_output
*term
__attribute__ ((unused
)))
979 return ((virtual_screen
.cursor_x
<< 8) | virtual_screen
.cursor_y
);
983 grub_gfxterm_gotoxy (struct grub_term_output
*term
__attribute__ ((unused
)),
984 grub_uint8_t x
, grub_uint8_t y
)
986 if (x
>= virtual_screen
.columns
)
987 x
= virtual_screen
.columns
- 1;
989 if (y
>= virtual_screen
.rows
)
990 y
= virtual_screen
.rows
- 1;
992 /* Erase current cursor, if any. */
993 if (virtual_screen
.cursor_state
)
996 virtual_screen
.cursor_x
= x
;
997 virtual_screen
.cursor_y
= y
;
999 /* Draw cursor if visible. */
1000 if (virtual_screen
.cursor_state
)
1005 grub_virtual_screen_cls (struct grub_term_output
*term
__attribute__ ((unused
)))
1009 for (i
= 0; i
< virtual_screen
.columns
* virtual_screen
.rows
; i
++)
1010 clear_char (&(virtual_screen
.text_buffer
[i
]));
1012 virtual_screen
.cursor_x
= virtual_screen
.cursor_y
= 0;
1016 grub_gfxterm_cls (struct grub_term_output
*term
)
1018 grub_video_color_t color
;
1020 /* Clear virtual screen. */
1021 grub_virtual_screen_cls (term
);
1023 /* Clear text layer. */
1024 grub_video_set_active_render_target (text_layer
);
1025 color
= virtual_screen
.bg_color
;
1026 grub_video_fill_rect (color
, 0, 0,
1027 virtual_screen
.width
, virtual_screen
.height
);
1028 grub_video_set_active_render_target (render_target
);
1030 /* Mark virtual screen to be redrawn. */
1031 dirty_region_add_virtualscreen ();
1033 grub_gfxterm_refresh (term
);
1037 grub_virtual_screen_setcolorstate (struct grub_term_output
*term
,
1038 grub_term_color_state state
)
1042 case GRUB_TERM_COLOR_STANDARD
:
1043 virtual_screen
.term_color
= virtual_screen
.standard_color_setting
;
1046 case GRUB_TERM_COLOR_NORMAL
:
1047 virtual_screen
.term_color
= term
->normal_color
;
1050 case GRUB_TERM_COLOR_HIGHLIGHT
:
1051 virtual_screen
.term_color
= term
->highlight_color
;
1058 /* Change color to virtual terminal. */
1059 set_term_color (virtual_screen
.term_color
);
1063 grub_gfxterm_setcursor (struct grub_term_output
*term
__attribute__ ((unused
)),
1066 if (virtual_screen
.cursor_state
!= on
)
1068 if (virtual_screen
.cursor_state
)
1073 virtual_screen
.cursor_state
= on
;
1078 grub_gfxterm_refresh (struct grub_term_output
*term
__attribute__ ((unused
)))
1082 /* Redraw only changed regions. */
1083 dirty_region_redraw ();
1085 grub_video_swap_buffers ();
1087 if (window
.double_repaint
)
1088 dirty_region_redraw ();
1089 dirty_region_reset ();
1093 grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func
)
1095 repaint_callback
= func
;
1098 /* Option array indices. */
1099 #define BACKGROUND_CMD_ARGINDEX_MODE 0
1101 static const struct grub_arg_option background_image_cmd_options
[] =
1103 {"mode", 'm', 0, N_("Background image mode."),
1104 /* TRANSLATORS: This refers to background image mode (stretched or
1105 in left-top corner). Note that GRUB will accept only original
1106 keywords stretch and normal, not the translated ones.
1107 So please put both in translation
1108 e.g. stretch(=%STRETCH%)|normal(=%NORMAL%).
1109 The percents mark the translated version. Since many people
1110 may not know the word stretch or normal I recommend
1111 putting the translation either here or in "Background image mode."
1113 N_("stretch|normal"),
1119 grub_gfxterm_background_image_cmd (grub_extcmd_context_t ctxt
,
1120 int argc
, char **args
)
1122 struct grub_arg_list
*state
= ctxt
->state
;
1124 /* Check that we have video adapter active. */
1125 if (grub_video_get_info(NULL
) != GRUB_ERR_NONE
)
1128 /* Destroy existing background bitmap if loaded. */
1131 grub_video_bitmap_destroy (bitmap
);
1135 /* Mark whole screen as dirty. */
1136 dirty_region_add (0, 0, window
.width
, window
.height
);
1139 /* If filename was provided, try to load that. */
1142 /* Try to load new one. */
1143 grub_video_bitmap_load (&bitmap
, args
[0]);
1144 if (grub_errno
!= GRUB_ERR_NONE
)
1147 /* Determine if the bitmap should be scaled to fit the screen. */
1148 if (!state
[BACKGROUND_CMD_ARGINDEX_MODE
].set
1149 || grub_strcmp (state
[BACKGROUND_CMD_ARGINDEX_MODE
].arg
,
1152 if (window
.width
!= grub_video_bitmap_get_width (bitmap
)
1153 || window
.height
!= grub_video_bitmap_get_height (bitmap
))
1155 struct grub_video_bitmap
*scaled_bitmap
;
1156 grub_video_bitmap_create_scaled (&scaled_bitmap
,
1160 GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST
);
1161 if (grub_errno
== GRUB_ERR_NONE
)
1163 /* Replace the original bitmap with the scaled one. */
1164 grub_video_bitmap_destroy (bitmap
);
1165 bitmap
= scaled_bitmap
;
1170 /* If bitmap was loaded correctly, display it. */
1175 /* Determine bitmap dimensions. */
1176 bitmap_width
= grub_video_bitmap_get_width (bitmap
);
1177 bitmap_height
= grub_video_bitmap_get_height (bitmap
);
1179 /* Mark whole screen as dirty. */
1180 dirty_region_add (0, 0, window
.width
, window
.height
);
1185 grub_errno
= GRUB_ERR_NONE
;
1190 grub_gfxterm_background_color_cmd (grub_command_t cmd
__attribute__ ((unused
)),
1191 int argc
, char **args
)
1193 struct grub_video_render_target
*old_target
;
1196 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("one argument expected"));
1198 /* Check that we have video adapter active. */
1199 if (grub_video_get_info (NULL
) != GRUB_ERR_NONE
)
1202 if (grub_video_parse_color (args
[0], &default_bg_color
) != GRUB_ERR_NONE
)
1205 /* Destroy existing background bitmap if loaded. */
1208 grub_video_bitmap_destroy (bitmap
);
1211 /* Mark whole screen as dirty. */
1212 dirty_region_add (0, 0, window
.width
, window
.height
);
1215 /* Set the background and border colors. The background color needs to be
1216 compatible with the text layer. */
1217 grub_video_get_active_render_target (&old_target
);
1218 grub_video_set_active_render_target (text_layer
);
1219 virtual_screen
.bg_color
= grub_video_map_rgba_color (default_bg_color
);
1220 grub_video_set_active_render_target (old_target
);
1221 virtual_screen
.bg_color_display
=
1222 grub_video_map_rgba_color (default_bg_color
);
1225 /* Mark whole screen as dirty. */
1226 dirty_region_add (0, 0, window
.width
, window
.height
);
1228 return GRUB_ERR_NONE
;
1231 static struct grub_term_output grub_video_term
=
1234 .init
= grub_gfxterm_term_init
,
1235 .fini
= grub_gfxterm_term_fini
,
1236 .putchar
= grub_gfxterm_putchar
,
1237 .getcharwidth
= grub_gfxterm_getcharwidth
,
1238 .getwh
= grub_virtual_screen_getwh
,
1239 .getxy
= grub_virtual_screen_getxy
,
1240 .gotoxy
= grub_gfxterm_gotoxy
,
1241 .cls
= grub_gfxterm_cls
,
1242 .setcolorstate
= grub_virtual_screen_setcolorstate
,
1243 .setcursor
= grub_gfxterm_setcursor
,
1244 .refresh
= grub_gfxterm_refresh
,
1245 .fullscreen
= grub_gfxterm_fullscreen
,
1246 .flags
= GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS
,
1247 .normal_color
= GRUB_TERM_DEFAULT_NORMAL_COLOR
,
1248 .highlight_color
= GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR
,
1252 static grub_extcmd_t background_image_cmd_handle
;
1253 static grub_command_t background_color_cmd_handle
;
1255 #if defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS)
1256 void grub_gfxterm_init (void)
1258 GRUB_MOD_INIT(gfxterm
)
1261 grub_term_register_output ("gfxterm", &grub_video_term
);
1262 background_image_cmd_handle
=
1263 grub_register_extcmd ("background_image",
1264 grub_gfxterm_background_image_cmd
, 0,
1265 N_("[-m (stretch|normal)] FILE"),
1266 N_("Load background image for active terminal."),
1267 background_image_cmd_options
);
1268 background_color_cmd_handle
=
1269 grub_register_command ("background_color",
1270 grub_gfxterm_background_color_cmd
,
1272 N_("Set background color for active terminal."));
1275 #if defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS)
1276 void grub_gfxterm_fini (void)
1278 GRUB_MOD_FINI(gfxterm
)
1281 grub_unregister_command (background_color_cmd_handle
);
1282 grub_unregister_extcmd (background_image_cmd_handle
);
1283 grub_term_unregister_output (&grub_video_term
);