123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146 |
- /*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
- *
- * GRUB is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GRUB is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <grub/term.h>
- #include <grub/types.h>
- #include <grub/dl.h>
- #include <grub/misc.h>
- #include <grub/font.h>
- #include <grub/mm.h>
- #include <grub/env.h>
- #include <grub/video.h>
- #include <grub/gfxterm.h>
- #include <grub/bitmap.h>
- #include <grub/command.h>
- #include <grub/extcmd.h>
- #include <grub/i18n.h>
- GRUB_MOD_LICENSE ("GPLv3+");
- #define DEFAULT_VIDEO_MODE "auto"
- #define DEFAULT_BORDER_WIDTH 10
- #define DEFAULT_STANDARD_COLOR 0x07
- struct grub_dirty_region
- {
- int top_left_x;
- int top_left_y;
- int bottom_right_x;
- int bottom_right_y;
- };
- struct grub_colored_char
- {
- /* An Unicode codepoint. */
- struct grub_unicode_glyph code;
- /* Color values. */
- grub_video_color_t fg_color;
- grub_video_color_t bg_color;
- };
- struct grub_virtual_screen
- {
- /* Dimensions of the virtual screen in pixels. */
- unsigned int width;
- unsigned int height;
- /* Offset in the display in pixels. */
- unsigned int offset_x;
- unsigned int offset_y;
- /* TTY Character sizes in pixes. */
- unsigned int normal_char_width;
- unsigned int normal_char_height;
- /* Virtual screen TTY size in characters. */
- unsigned int columns;
- unsigned int rows;
- /* Current cursor location in characters. */
- unsigned int cursor_x;
- unsigned int cursor_y;
- /* Current cursor state. */
- int cursor_state;
- /* Font settings. */
- grub_font_t font;
- /* Terminal color settings. */
- grub_uint8_t standard_color_setting;
- grub_uint8_t term_color;
- /* Color settings. */
- grub_video_color_t fg_color;
- grub_video_color_t bg_color;
- grub_video_color_t bg_color_display;
- /* Text buffer for virtual screen. Contains (columns * rows) number
- of entries. */
- struct grub_colored_char *text_buffer;
- int total_scroll;
- int functional;
- };
- struct grub_gfxterm_window
- {
- unsigned x;
- unsigned y;
- unsigned width;
- unsigned height;
- int double_repaint;
- };
- static struct grub_video_render_target *render_target;
- void (*grub_gfxterm_decorator_hook) (void) = NULL;
- static struct grub_gfxterm_window window;
- static struct grub_virtual_screen virtual_screen;
- static int repaint_scheduled = 0;
- static int repaint_was_scheduled = 0;
- static void destroy_window (void);
- static struct grub_video_render_target *text_layer;
- struct grub_gfxterm_background grub_gfxterm_background;
- static struct grub_dirty_region dirty_region;
- static void dirty_region_reset (void);
- static int dirty_region_is_empty (void);
- static void dirty_region_add (int x, int y,
- unsigned int width, unsigned int height);
- static unsigned int calculate_normal_character_width (grub_font_t font);
- static unsigned char calculate_character_width (struct grub_font_glyph *glyph);
- static void grub_gfxterm_refresh (struct grub_term_output *term __attribute__ ((unused)));
- static grub_size_t
- grub_gfxterm_getcharwidth (struct grub_term_output *term __attribute__ ((unused)),
- const struct grub_unicode_glyph *c);
- static void
- set_term_color (grub_uint8_t term_color)
- {
- struct grub_video_render_target *old_target;
- /* Save previous target and switch to text layer. */
- grub_video_get_active_render_target (&old_target);
- grub_video_set_active_render_target (text_layer);
- /* Map terminal color to text layer compatible video colors. */
- virtual_screen.fg_color = grub_video_map_color(term_color & 0x0f);
- /* Special case: use black as transparent color. */
- if (((term_color >> 4) & 0x0f) == 0)
- {
- virtual_screen.bg_color = grub_video_map_rgba(0, 0, 0, 0);
- }
- else
- {
- virtual_screen.bg_color = grub_video_map_color((term_color >> 4) & 0x0f);
- }
- /* Restore previous target. */
- grub_video_set_active_render_target (old_target);
- }
- static void
- clear_char (struct grub_colored_char *c)
- {
- grub_unicode_destroy_glyph (&c->code);
- grub_unicode_set_glyph_from_code (&c->code, ' ');
- c->fg_color = virtual_screen.fg_color;
- c->bg_color = virtual_screen.bg_color;
- }
- static void
- grub_virtual_screen_free (void)
- {
- virtual_screen.functional = 0;
- /* If virtual screen has been allocated, free it. */
- if (virtual_screen.text_buffer != 0)
- {
- unsigned i;
- for (i = 0;
- i < virtual_screen.columns * virtual_screen.rows;
- i++)
- grub_unicode_destroy_glyph (&virtual_screen.text_buffer[i].code);
- grub_free (virtual_screen.text_buffer);
- }
- /* Reset virtual screen data. */
- grub_memset (&virtual_screen, 0, sizeof (virtual_screen));
- /* Free render targets. */
- grub_video_delete_render_target (text_layer);
- text_layer = 0;
- }
- static grub_err_t
- grub_virtual_screen_setup (unsigned int x, unsigned int y,
- unsigned int width, unsigned int height,
- grub_font_t font)
- {
- unsigned int i;
- /* Free old virtual screen. */
- grub_virtual_screen_free ();
- /* Initialize with default data. */
- virtual_screen.font = font;
- virtual_screen.width = width;
- virtual_screen.height = height;
- virtual_screen.offset_x = x;
- virtual_screen.offset_y = y;
- virtual_screen.normal_char_width =
- calculate_normal_character_width (virtual_screen.font);
- virtual_screen.normal_char_height =
- grub_font_get_max_char_height (virtual_screen.font);
- if (virtual_screen.normal_char_height == 0)
- virtual_screen.normal_char_height = 16;
- virtual_screen.cursor_x = 0;
- virtual_screen.cursor_y = 0;
- virtual_screen.cursor_state = 1;
- virtual_screen.total_scroll = 0;
- /* Calculate size of text buffer. */
- virtual_screen.columns = virtual_screen.width / virtual_screen.normal_char_width;
- virtual_screen.rows = virtual_screen.height / virtual_screen.normal_char_height;
- /* Allocate memory for text buffer. */
- virtual_screen.text_buffer =
- (struct grub_colored_char *) grub_malloc (virtual_screen.columns
- * virtual_screen.rows
- * sizeof (*virtual_screen.text_buffer));
- if (grub_errno != GRUB_ERR_NONE)
- return grub_errno;
- /* Create new render target for text layer. */
- grub_video_create_render_target (&text_layer,
- virtual_screen.width,
- virtual_screen.height,
- GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
- | GRUB_VIDEO_MODE_TYPE_ALPHA);
- if (grub_errno != GRUB_ERR_NONE)
- return grub_errno;
- /* As we want to have colors compatible with rendering target,
- we can only have those after mode is initialized. */
- grub_video_set_active_render_target (text_layer);
- virtual_screen.standard_color_setting = DEFAULT_STANDARD_COLOR;
- virtual_screen.term_color = virtual_screen.standard_color_setting;
- set_term_color (virtual_screen.term_color);
- grub_video_set_active_render_target (render_target);
- virtual_screen.bg_color_display =
- grub_video_map_rgba_color (grub_gfxterm_background.default_bg_color);
- /* Clear out text buffer. */
- for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
- {
- virtual_screen.text_buffer[i].code.ncomb = 0;
- clear_char (&(virtual_screen.text_buffer[i]));
- }
- if (grub_errno)
- return grub_errno;
- virtual_screen.functional = 1;
- return GRUB_ERR_NONE;
- }
- void
- grub_gfxterm_schedule_repaint (void)
- {
- repaint_scheduled = 1;
- }
- grub_err_t
- grub_gfxterm_set_window (struct grub_video_render_target *target,
- int x, int y, int width, int height,
- int double_repaint,
- grub_font_t font, int border_width)
- {
- /* Clean up any prior instance. */
- destroy_window ();
- /* Set the render target. */
- render_target = target;
- /* Create virtual screen. */
- if (grub_virtual_screen_setup (border_width, border_width,
- width - 2 * border_width,
- height - 2 * border_width,
- font)
- != GRUB_ERR_NONE)
- {
- return grub_errno;
- }
- /* Set window bounds. */
- window.x = x;
- window.y = y;
- window.width = width;
- window.height = height;
- window.double_repaint = double_repaint;
- dirty_region_reset ();
- grub_gfxterm_schedule_repaint ();
- return grub_errno;
- }
- static grub_err_t
- grub_gfxterm_fullscreen (void)
- {
- const char *font_name;
- struct grub_video_mode_info mode_info;
- grub_video_color_t color;
- grub_err_t err;
- int double_redraw;
- grub_font_t font;
- err = grub_video_get_info (&mode_info);
- /* Figure out what mode we ended up. */
- if (err)
- return err;
- grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
- double_redraw = mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
- && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
- /* Make sure screen is set to the default background color. */
- color = grub_video_map_rgba_color (grub_gfxterm_background.default_bg_color);
- grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
- if (double_redraw)
- {
- grub_video_swap_buffers ();
- grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
- }
- /* Select the font to use. */
- font_name = grub_env_get ("gfxterm_font");
- if (! font_name)
- font_name = ""; /* Allow fallback to any font. */
- font = grub_font_get (font_name);
- if (!font)
- return grub_error (GRUB_ERR_BAD_FONT, "no font loaded");
- grub_gfxterm_decorator_hook = NULL;
- return grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY,
- 0, 0, mode_info.width, mode_info.height,
- double_redraw,
- font, DEFAULT_BORDER_WIDTH);
- }
- static grub_err_t
- grub_gfxterm_term_init (struct grub_term_output *term __attribute__ ((unused)))
- {
- char *tmp;
- grub_err_t err;
- const char *modevar;
- /* Parse gfxmode environment variable if set. */
- modevar = grub_env_get ("gfxmode");
- if (! modevar || *modevar == 0)
- err = grub_video_set_mode (DEFAULT_VIDEO_MODE,
- GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
- else
- {
- tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
- if (!tmp)
- return grub_errno;
- err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
- grub_free (tmp);
- }
- if (err)
- return err;
- err = grub_gfxterm_fullscreen ();
- if (err)
- grub_video_restore ();
- return err;
- }
- static void
- destroy_window (void)
- {
- grub_virtual_screen_free ();
- }
- static grub_err_t
- grub_gfxterm_term_fini (struct grub_term_output *term __attribute__ ((unused)))
- {
- unsigned i;
- destroy_window ();
- grub_video_restore ();
- for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
- {
- grub_unicode_destroy_glyph (&virtual_screen.text_buffer[i].code);
- virtual_screen.text_buffer[i].code.ncomb = 0;
- virtual_screen.text_buffer[i].code.base = 0;
- }
- /* Clear error state. */
- grub_errno = GRUB_ERR_NONE;
- return GRUB_ERR_NONE;
- }
- static void
- redraw_screen_rect (unsigned int x, unsigned int y,
- unsigned int width, unsigned int height)
- {
- grub_video_color_t color;
- grub_video_rect_t saved_view;
- grub_video_set_active_render_target (render_target);
- /* Save viewport and set it to our window. */
- grub_video_get_viewport ((unsigned *) &saved_view.x,
- (unsigned *) &saved_view.y,
- (unsigned *) &saved_view.width,
- (unsigned *) &saved_view.height);
- grub_video_set_viewport (window.x, window.y, window.width, window.height);
- if (grub_gfxterm_background.bitmap)
- {
- /* Render bitmap as background. */
- grub_video_blit_bitmap (grub_gfxterm_background.bitmap,
- GRUB_VIDEO_BLIT_REPLACE, x, y,
- x, y,
- width, height);
- /* If bitmap is smaller than requested blit area, use background
- color. */
- color = virtual_screen.bg_color_display;
- /* Fill right side of the bitmap if needed. */
- if ((x + width >= grub_gfxterm_background.bitmap->mode_info.width)
- && (y < grub_gfxterm_background.bitmap->mode_info.height))
- {
- int w = (x + width) - grub_gfxterm_background.bitmap->mode_info.width;
- int h = height;
- unsigned int tx = x;
- if (y + height >= grub_gfxterm_background.bitmap->mode_info.height)
- {
- h = grub_gfxterm_background.bitmap->mode_info.height - y;
- }
- if (grub_gfxterm_background.bitmap->mode_info.width > tx)
- {
- tx = grub_gfxterm_background.bitmap->mode_info.width;
- }
- /* Render background layer. */
- grub_video_fill_rect (color, tx, y, w, h);
- }
- /* Fill bottom side of the bitmap if needed. */
- if (y + height >= grub_gfxterm_background.bitmap->mode_info.height)
- {
- int h = (y + height) - grub_gfxterm_background.bitmap->mode_info.height;
- unsigned int ty = y;
- if (grub_gfxterm_background.bitmap->mode_info.height > ty)
- {
- ty = grub_gfxterm_background.bitmap->mode_info.height;
- }
- /* Render background layer. */
- grub_video_fill_rect (color, x, ty, width, h);
- }
- }
- else
- {
- /* Render background layer. */
- color = virtual_screen.bg_color_display;
- grub_video_fill_rect (color, x, y, width, height);
- }
- if (grub_gfxterm_background.blend_text_bg)
- /* Render text layer as blended. */
- grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, x, y,
- x - virtual_screen.offset_x,
- y - virtual_screen.offset_y,
- width, height);
- else
- /* Render text layer as replaced (to get texts background color). */
- grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_REPLACE, x, y,
- x - virtual_screen.offset_x,
- y - virtual_screen.offset_y,
- width, height);
- /* Restore saved viewport. */
- grub_video_set_viewport (saved_view.x, saved_view.y,
- saved_view.width, saved_view.height);
- grub_video_set_active_render_target (render_target);
- }
- static void
- dirty_region_reset (void)
- {
- dirty_region.top_left_x = -1;
- dirty_region.top_left_y = -1;
- dirty_region.bottom_right_x = -1;
- dirty_region.bottom_right_y = -1;
- repaint_was_scheduled = 0;
- }
- static int
- dirty_region_is_empty (void)
- {
- if ((dirty_region.top_left_x == -1)
- || (dirty_region.top_left_y == -1)
- || (dirty_region.bottom_right_x == -1)
- || (dirty_region.bottom_right_y == -1))
- return 1;
- return 0;
- }
- static void
- dirty_region_add_real (int x, int y, unsigned int width, unsigned int height)
- {
- if (dirty_region_is_empty ())
- {
- dirty_region.top_left_x = x;
- dirty_region.top_left_y = y;
- dirty_region.bottom_right_x = x + width - 1;
- dirty_region.bottom_right_y = y + height - 1;
- }
- else
- {
- if (x < dirty_region.top_left_x)
- dirty_region.top_left_x = x;
- if (y < dirty_region.top_left_y)
- dirty_region.top_left_y = y;
- if ((x + (int)width - 1) > dirty_region.bottom_right_x)
- dirty_region.bottom_right_x = x + width - 1;
- if ((y + (int)height - 1) > dirty_region.bottom_right_y)
- dirty_region.bottom_right_y = y + height - 1;
- }
- }
- static void
- dirty_region_add (int x, int y, unsigned int width, unsigned int height)
- {
- if ((width == 0) || (height == 0))
- return;
- if (repaint_scheduled)
- {
- dirty_region_add_real (0, 0,
- window.width, window.height);
- repaint_scheduled = 0;
- repaint_was_scheduled = 1;
- }
- dirty_region_add_real (x, y, width, height);
- }
- static void
- dirty_region_add_virtualscreen (void)
- {
- /* Mark virtual screen as dirty. */
- dirty_region_add (virtual_screen.offset_x, virtual_screen.offset_y,
- virtual_screen.width, virtual_screen.height);
- }
- static void
- dirty_region_redraw (void)
- {
- int x;
- int y;
- int width;
- int height;
- if (dirty_region_is_empty ())
- return;
- x = dirty_region.top_left_x;
- y = dirty_region.top_left_y;
- width = dirty_region.bottom_right_x - x + 1;
- height = dirty_region.bottom_right_y - y + 1;
- if (repaint_was_scheduled && grub_gfxterm_decorator_hook)
- grub_gfxterm_decorator_hook ();
- redraw_screen_rect (x, y, width, height);
- }
- static inline void
- paint_char (unsigned cx, unsigned cy)
- {
- struct grub_colored_char *p;
- struct grub_font_glyph *glyph;
- grub_video_color_t color;
- grub_video_color_t bgcolor;
- unsigned int x;
- unsigned int y;
- int ascent;
- unsigned int height;
- unsigned int width;
- if (cy + virtual_screen.total_scroll >= virtual_screen.rows)
- return;
- /* Find out active character. */
- p = (virtual_screen.text_buffer
- + cx + (cy * virtual_screen.columns));
- if (!p->code.base)
- return;
- /* Get glyph for character. */
- glyph = grub_font_construct_glyph (virtual_screen.font, &p->code);
- if (!glyph)
- {
- grub_errno = GRUB_ERR_NONE;
- return;
- }
- ascent = grub_font_get_ascent (virtual_screen.font);
- width = virtual_screen.normal_char_width * calculate_character_width(glyph);
- height = virtual_screen.normal_char_height;
- color = p->fg_color;
- bgcolor = p->bg_color;
- x = cx * virtual_screen.normal_char_width;
- y = (cy + virtual_screen.total_scroll) * virtual_screen.normal_char_height;
- /* Render glyph to text layer. */
- grub_video_set_active_render_target (text_layer);
- grub_video_fill_rect (bgcolor, x, y, width, height);
- grub_font_draw_glyph (glyph, color, x, y + ascent);
- grub_video_set_active_render_target (render_target);
- /* Mark character to be drawn. */
- dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
- width, height);
- }
- static inline void
- write_char (void)
- {
- paint_char (virtual_screen.cursor_x, virtual_screen.cursor_y);
- }
- static inline void
- draw_cursor (int show)
- {
- unsigned int x;
- unsigned int y;
- unsigned int width;
- unsigned int height;
- grub_video_color_t color;
-
- write_char ();
- if (!show)
- return;
- if (virtual_screen.cursor_y + virtual_screen.total_scroll
- >= virtual_screen.rows)
- return;
- /* Determine cursor properties and position on text layer. */
- x = virtual_screen.cursor_x * virtual_screen.normal_char_width;
- width = virtual_screen.normal_char_width;
- color = virtual_screen.fg_color;
- y = ((virtual_screen.cursor_y + virtual_screen.total_scroll)
- * virtual_screen.normal_char_height
- + grub_font_get_ascent (virtual_screen.font));
- height = 2;
-
- /* Render cursor to text layer. */
- grub_video_set_active_render_target (text_layer);
- grub_video_fill_rect (color, x, y, width, height);
- grub_video_set_active_render_target (render_target);
-
- /* Mark cursor to be redrawn. */
- dirty_region_add (virtual_screen.offset_x + x,
- virtual_screen.offset_y + y,
- width, height);
- }
- static void
- real_scroll (void)
- {
- unsigned int i, j, was_scroll;
- grub_video_color_t color;
- if (!virtual_screen.total_scroll)
- return;
- /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */
- if (grub_gfxterm_background.bitmap)
- {
- /* Scroll physical screen. */
- grub_video_set_active_render_target (text_layer);
- color = virtual_screen.bg_color;
- grub_video_scroll (color, 0, -virtual_screen.normal_char_height
- * virtual_screen.total_scroll);
- /* Mark virtual screen to be redrawn. */
- dirty_region_add_virtualscreen ();
- }
- else
- {
- grub_video_rect_t saved_view;
- /* Remove cursor. */
- draw_cursor (0);
- grub_video_set_active_render_target (render_target);
- i = window.double_repaint ? 2 : 1;
- color = virtual_screen.bg_color_display;
- while (i--)
- {
- /* Save viewport and set it to our window. */
- grub_video_get_viewport ((unsigned *) &saved_view.x,
- (unsigned *) &saved_view.y,
- (unsigned *) &saved_view.width,
- (unsigned *) &saved_view.height);
- grub_video_set_viewport (window.x, window.y, window.width,
- window.height);
- /* Clear new border area. */
- grub_video_fill_rect (color,
- virtual_screen.offset_x,
- virtual_screen.offset_y,
- virtual_screen.width,
- virtual_screen.normal_char_height
- * virtual_screen.total_scroll);
- grub_video_set_active_render_target (render_target);
- dirty_region_redraw ();
- /* Scroll physical screen. */
- grub_video_scroll (color, 0, -virtual_screen.normal_char_height
- * virtual_screen.total_scroll);
- /* Restore saved viewport. */
- grub_video_set_viewport (saved_view.x, saved_view.y,
- saved_view.width, saved_view.height);
- if (i)
- grub_video_swap_buffers ();
- }
- dirty_region_reset ();
- /* Scroll physical screen. */
- grub_video_set_active_render_target (text_layer);
- color = virtual_screen.bg_color;
- grub_video_scroll (color, 0, -virtual_screen.normal_char_height
- * virtual_screen.total_scroll);
- grub_video_set_active_render_target (render_target);
- }
- was_scroll = virtual_screen.total_scroll;
- virtual_screen.total_scroll = 0;
- if (was_scroll > virtual_screen.rows)
- was_scroll = virtual_screen.rows;
- /* Draw shadow part. */
- for (i = virtual_screen.rows - was_scroll;
- i < virtual_screen.rows; i++)
- for (j = 0; j < virtual_screen.columns; j++)
- paint_char (j, i);
- /* Draw cursor if visible. */
- if (virtual_screen.cursor_state)
- draw_cursor (1);
- }
- static void
- scroll_up (void)
- {
- unsigned int i;
- /* Clear first line in text buffer. */
- for (i = 0; i < virtual_screen.columns; i++)
- grub_unicode_destroy_glyph (&virtual_screen.text_buffer[i].code);
-
- /* Scroll text buffer with one line to up. */
- grub_memmove (virtual_screen.text_buffer,
- virtual_screen.text_buffer + virtual_screen.columns,
- sizeof (*virtual_screen.text_buffer)
- * virtual_screen.columns
- * (virtual_screen.rows - 1));
- /* Clear last line in text buffer. */
- for (i = virtual_screen.columns * (virtual_screen.rows - 1);
- i < virtual_screen.columns * virtual_screen.rows;
- i++)
- clear_char (&(virtual_screen.text_buffer[i]));
- virtual_screen.total_scroll++;
- }
- static void
- grub_gfxterm_putchar (struct grub_term_output *term,
- const struct grub_unicode_glyph *c)
- {
- if (!virtual_screen.functional)
- return;
- if (c->base == '\a')
- /* FIXME */
- return;
- /* Erase current cursor, if any. */
- if (virtual_screen.cursor_state)
- draw_cursor (0);
- if (c->base == '\b' || c->base == '\n' || c->base == '\r')
- {
- switch (c->base)
- {
- case '\b':
- if (virtual_screen.cursor_x > 0)
- virtual_screen.cursor_x--;
- break;
- case '\n':
- if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
- scroll_up ();
- else
- virtual_screen.cursor_y++;
- break;
- case '\r':
- virtual_screen.cursor_x = 0;
- break;
- }
- }
- else
- {
- struct grub_colored_char *p;
- unsigned char char_width;
- /* Calculate actual character width for glyph. This is number of
- times of normal_font_width. */
- char_width = grub_gfxterm_getcharwidth (term, c);
- /* If we are about to exceed line length, wrap to next line. */
- if (virtual_screen.cursor_x + char_width > virtual_screen.columns)
- {
- if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
- scroll_up ();
- else
- virtual_screen.cursor_y++;
- }
- /* Find position on virtual screen, and fill information. */
- p = (virtual_screen.text_buffer +
- virtual_screen.cursor_x +
- virtual_screen.cursor_y * virtual_screen.columns);
- grub_unicode_destroy_glyph (&p->code);
- grub_unicode_set_glyph (&p->code, c);
- grub_errno = GRUB_ERR_NONE;
- p->fg_color = virtual_screen.fg_color;
- p->bg_color = virtual_screen.bg_color;
- /* If we have large glyph, add fixup info. */
- if (char_width > 1)
- {
- unsigned i;
- for (i = 1; i < char_width && p + i <
- virtual_screen.text_buffer + virtual_screen.columns
- * virtual_screen.rows; i++)
- {
- grub_unicode_destroy_glyph (&p[i].code);
- p[i].code.base = 0;
- }
- }
- /* Draw glyph. */
- write_char ();
- /* Make sure we scroll screen when needed and wrap line correctly. */
- virtual_screen.cursor_x += char_width;
- if (virtual_screen.cursor_x >= virtual_screen.columns)
- {
- virtual_screen.cursor_x = 0;
- if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
- scroll_up ();
- else
- virtual_screen.cursor_y++;
- }
- }
- /* Redraw cursor if it should be visible. */
- /* Note: This will redraw the character as well, which means that the
- above call to write_char is redundant when the cursor is showing. */
- if (virtual_screen.cursor_state)
- draw_cursor (1);
- }
- /* Use ASCII characters to determine normal character width. */
- static unsigned int
- calculate_normal_character_width (grub_font_t font)
- {
- struct grub_font_glyph *glyph;
- unsigned int width = 0;
- unsigned int i;
- /* Get properties of every printable ASCII character. */
- for (i = 32; i < 127; i++)
- {
- glyph = grub_font_get_glyph (font, i);
- /* Skip unknown characters. Should never happen on normal conditions. */
- if (! glyph)
- continue;
- if (glyph->device_width > width)
- width = glyph->device_width;
- }
- if (!width)
- return 8;
- return width;
- }
- static unsigned char
- calculate_character_width (struct grub_font_glyph *glyph)
- {
- if (! glyph || glyph->device_width == 0)
- return 1;
- return (glyph->device_width
- + (virtual_screen.normal_char_width - 1))
- / virtual_screen.normal_char_width;
- }
- static grub_size_t
- grub_gfxterm_getcharwidth (struct grub_term_output *term __attribute__ ((unused)),
- const struct grub_unicode_glyph *c)
- {
- int dev_width;
- dev_width = grub_font_get_constructed_device_width (virtual_screen.font, c);
- if (dev_width == 0)
- return 1;
- return (dev_width + (virtual_screen.normal_char_width - 1))
- / virtual_screen.normal_char_width;
- }
- static struct grub_term_coordinate
- grub_virtual_screen_getwh (struct grub_term_output *term __attribute__ ((unused)))
- {
- return (struct grub_term_coordinate) { virtual_screen.columns, virtual_screen.rows };
- }
- static struct grub_term_coordinate
- grub_virtual_screen_getxy (struct grub_term_output *term __attribute__ ((unused)))
- {
- return (struct grub_term_coordinate) { virtual_screen.cursor_x, virtual_screen.cursor_y };
- }
- static void
- grub_gfxterm_gotoxy (struct grub_term_output *term __attribute__ ((unused)),
- struct grub_term_coordinate pos)
- {
- if (pos.x >= virtual_screen.columns)
- pos.x = virtual_screen.columns - 1;
- if (pos.y >= virtual_screen.rows)
- pos.y = virtual_screen.rows - 1;
- /* Erase current cursor, if any. */
- if (virtual_screen.cursor_state)
- draw_cursor (0);
- virtual_screen.cursor_x = pos.x;
- virtual_screen.cursor_y = pos.y;
- /* Draw cursor if visible. */
- if (virtual_screen.cursor_state)
- draw_cursor (1);
- }
- static void
- grub_virtual_screen_cls (struct grub_term_output *term __attribute__ ((unused)))
- {
- grub_uint32_t i;
- for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
- clear_char (&(virtual_screen.text_buffer[i]));
- virtual_screen.cursor_x = virtual_screen.cursor_y = 0;
- }
- static void
- grub_gfxterm_cls (struct grub_term_output *term)
- {
- grub_video_color_t color;
- /* Clear virtual screen. */
- grub_virtual_screen_cls (term);
- /* Clear text layer. */
- grub_video_set_active_render_target (text_layer);
- color = virtual_screen.bg_color;
- grub_video_fill_rect (color, 0, 0,
- virtual_screen.width, virtual_screen.height);
- grub_video_set_active_render_target (render_target);
- /* Mark virtual screen to be redrawn. */
- dirty_region_add_virtualscreen ();
- grub_gfxterm_refresh (term);
- }
- static void
- grub_virtual_screen_setcolorstate (struct grub_term_output *term __attribute__ ((unused)),
- grub_term_color_state state)
- {
- switch (state)
- {
- case GRUB_TERM_COLOR_STANDARD:
- virtual_screen.term_color = virtual_screen.standard_color_setting;
- break;
- case GRUB_TERM_COLOR_NORMAL:
- virtual_screen.term_color = grub_term_normal_color;
- break;
- case GRUB_TERM_COLOR_HIGHLIGHT:
- virtual_screen.term_color = grub_term_highlight_color;
- break;
- default:
- break;
- }
- /* Change color to virtual terminal. */
- set_term_color (virtual_screen.term_color);
- }
- static void
- grub_gfxterm_setcursor (struct grub_term_output *term __attribute__ ((unused)),
- int on)
- {
- if (virtual_screen.cursor_state != on)
- {
- if (virtual_screen.cursor_state)
- draw_cursor (0);
- else
- draw_cursor (1);
- virtual_screen.cursor_state = on;
- }
- }
- static void
- grub_gfxterm_refresh (struct grub_term_output *term __attribute__ ((unused)))
- {
- real_scroll ();
- /* Redraw only changed regions. */
- dirty_region_redraw ();
- grub_video_swap_buffers ();
- if (window.double_repaint)
- dirty_region_redraw ();
- dirty_region_reset ();
- }
- static struct grub_term_output grub_video_term =
- {
- .name = "gfxterm",
- .init = grub_gfxterm_term_init,
- .fini = grub_gfxterm_term_fini,
- .putchar = grub_gfxterm_putchar,
- .getcharwidth = grub_gfxterm_getcharwidth,
- .getwh = grub_virtual_screen_getwh,
- .getxy = grub_virtual_screen_getxy,
- .gotoxy = grub_gfxterm_gotoxy,
- .cls = grub_gfxterm_cls,
- .setcolorstate = grub_virtual_screen_setcolorstate,
- .setcursor = grub_gfxterm_setcursor,
- .refresh = grub_gfxterm_refresh,
- .fullscreen = grub_gfxterm_fullscreen,
- .flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS,
- .progress_update_divisor = GRUB_PROGRESS_SLOW,
- .next = 0
- };
- void
- grub_gfxterm_video_update_color (void)
- {
- struct grub_video_render_target *old_target;
- grub_video_get_active_render_target (&old_target);
- grub_video_set_active_render_target (text_layer);
- virtual_screen.bg_color = grub_video_map_rgba_color (grub_gfxterm_background.default_bg_color);
- grub_video_set_active_render_target (old_target);
- virtual_screen.bg_color_display =
- grub_video_map_rgba_color (grub_gfxterm_background.default_bg_color);
- }
- void
- grub_gfxterm_get_dimensions (unsigned *width, unsigned *height)
- {
- *width = window.width;
- *height = window.height;
- }
- GRUB_MOD_INIT(gfxterm)
- {
- grub_term_register_output ("gfxterm", &grub_video_term);
- }
- GRUB_MOD_FINI(gfxterm)
- {
- grub_term_unregister_output (&grub_video_term);
- }
|